]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZCkZAut.c
c0f962850b3ac4d2b1f8b15e1a0629499670a1e0
[1ts-debian.git] / zephyr / lib / ZCkZAut.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains source for the ZCheckAuthentication function.
3  *
4  *      Created by:     Robert French
5  *
6  *      $Source$
7  *      $Author$
8  *
9  *      Copyright (c) 1987,1991 by the Massachusetts Institute of Technology.
10  *      For copying and distribution information, see the file
11  *      "mit-copyright.h". 
12  */
13 /* $Header$ */
14
15 #ifndef lint
16 static char rcsid_ZCheckAuthentication_c[] =
17     "$Zephyr: /mit/zephyr/src/lib/RCS/ZCheckAuthentication.c,v 1.14 89/03/24 14:17:38 jtkohl Exp Locker: raeburn $";
18 #endif
19
20 #include <internal.h>
21
22 #if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
23 #define krb5_free_data(ctx, dat) free((dat)->data)
24 #endif
25
26 /* Check authentication of the notice.
27    If it looks authentic but fails the Kerberos check, return -1.
28    If it looks authentic and passes the Kerberos check, return 1.
29    If it doesn't look authentic, return 0
30
31    When not using Kerberos, return true if the notice claims to be authentic.
32    Only used by clients; the server uses its own routine.
33  */
34 Code_t ZCheckZcodeAuthentication(notice, from)
35     ZNotice_t *notice;
36     struct sockaddr_in *from;
37 {       
38     /* If the value is already known, return it. */
39     if (notice->z_checked_auth != ZAUTH_UNSET)
40         return (notice->z_checked_auth);
41
42     if (!notice->z_auth)
43         return (ZAUTH_NO);
44
45     if (!notice->z_ascii_checksum)
46         return (ZAUTH_NO);
47
48 #ifdef HAVE_KRB5
49     {
50         krb5_error_code result;
51         krb5_ccache ccache;
52         krb5_creds creds_in, *creds;
53         krb5_keyblock *keyblock;
54         krb5_enctype enctype;
55         krb5_cksumtype cksumtype;
56         krb5_data cksumbuf;
57 #if HAVE_KRB5_C_MAKE_CHECKSUM
58         krb5_checksum checksum;
59         krb5_boolean valid;
60 #else
61         krb5_crypto cryptctx;
62         Checksum checksum;
63         size_t xlen;
64 #endif
65         char *cksum0_base, *cksum1_base, *cksum2_base;
66         char *svcinst, *x, *y;
67         char *asn1_data, *key_data;
68         int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len;
69         /* Get a pointer to the default ccache.  We don't need to free this. */
70         result = krb5_cc_default(Z_krb5_ctx, &ccache);
71         if (result)
72             return (ZAUTH_NO);
73
74         /* GRRR.  There's no allocator or constructor for krb5_creds */
75         /* GRRR.  It would be nice if this API were documented at all */
76         memset(&creds_in, 0, sizeof(creds_in));
77
78         result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
79         if (result) {
80             krb5_cc_close(Z_krb5_ctx, ccache);
81             return(result);
82         }
83
84         /* construct the service principal */
85         result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
86                                       strlen(__Zephyr_realm),
87                                       __Zephyr_realm,
88                                       SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
89         if (result) {
90             krb5_free_cred_contents(Z_krb5_ctx, &creds_in);
91             krb5_cc_close(Z_krb5_ctx, ccache);
92             return (ZAUTH_NO);
93         }
94         /* HOLDING: creds_in.server */
95
96         /* look up or get the credentials we need */
97         result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
98                                       &creds_in, &creds);
99         krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
100         krb5_cc_close(Z_krb5_ctx, ccache);
101
102         if (result)
103             return (ZAUTH_NO);
104         /* HOLDING: creds */
105
106         /* Figure out what checksum type to use */
107 #if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
108         keyblock = &creds->keyblock;
109         key_data = keyblock->contents;
110         key_len  = keyblock->length;
111         enctype  = keyblock->enctype;
112         result = Z_krb5_lookup_cksumtype(enctype, &cksumtype);
113         if (result) {
114             krb5_free_creds(Z_krb5_ctx, creds);
115             return (ZAUTH_FAILED);
116         }
117 #else
118         keyblock = &creds->session;
119         key_data = keyblock->keyvalue.data;
120         key_len  = keyblock->keyvalue.length;
121         {
122             unsigned int len;  
123             ENCTYPE *val;  
124             int i = 0;  
125   
126             result  = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype,  
127                                                &len, &val);  
128             if (result) {  
129                 krb5_free_creds(Z_krb5_ctx, creds);
130                 return (ZAUTH_FAILED);
131             }  
132   
133             do {  
134                 if (i == len) break; 
135                 result = Z_krb5_lookup_cksumtype(val[i], &cksumtype);  
136                 i++; 
137             } while (result != 0);  
138  
139             if (result) {  
140                 krb5_free_creds(Z_krb5_ctx, creds);
141                 return (ZAUTH_FAILED);
142             }  
143             enctype = val[i-1];  
144         }  
145 #endif
146         /* HOLDING: creds */
147
148         /* Assemble the things to be checksummed */
149         /* first part is from start of packet through z_default_format:
150          * - z_version
151          * - z_num_other_fields
152          * - z_kind
153          * - z_uid
154          * - z_port
155          * - z_auth
156          * - z_authent_len
157          * - z_ascii_authent
158          * - z_class
159          * - z_class_inst
160          * - z_opcode
161          * - z_sender
162          * - z_recipient
163          * - z_default_format
164          */
165         cksum0_base = notice->z_packet;
166         x           = notice->z_default_format;
167         cksum0_len  = x + strlen(x) + 1 - cksum0_base;
168         /* second part is from z_multinotice through other fields:
169          * - z_multinotice
170          * - z_multiuid
171          * - z_other_fields[]
172          */
173         cksum1_base = notice->z_multinotice;
174         if (notice->z_num_other_fields)
175           x = notice->z_other_fields[notice->z_num_other_fields];
176         else
177           x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
178         cksum1_len  = x + strlen(x) + 1 - cksum1_base;
179
180         /* last part is the message body */
181         cksum2_base = notice->z_message;
182         cksum2_len  = notice->z_message_len;
183
184         if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
185             key_len == 8 &&
186             (enctype == ENCTYPE_DES_CBC_CRC ||
187              enctype == ENCTYPE_DES_CBC_MD4 ||
188              enctype == ENCTYPE_DES_CBC_MD5)) {
189           /* try old-format checksum (covers cksum0 only) */
190
191             ZChecksum_t our_checksum;
192
193             our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
194                                           key_data);
195             if (our_checksum == notice->z_checksum) {
196                 krb5_free_creds(Z_krb5_ctx, creds);
197                 return ZAUTH_YES;
198             }
199         }
200         /* HOLDING: creds */
201
202         cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
203         cksumbuf.data = malloc(cksumbuf.length);
204         if (!cksumbuf.data) {
205             krb5_free_creds(Z_krb5_ctx, creds);
206             return ZAUTH_NO;
207         }
208         /* HOLDING: creds, cksumbuf.data */
209
210         memcpy(cksumbuf.data, cksum0_base, cksum0_len);
211         memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len);
212         memcpy(cksumbuf.data + cksum0_len + cksum1_len,
213                cksum2_base, cksum2_len);
214
215         /* decode zcoded checksum */
216         /* The encoded form is always longer than the original */
217         asn1_len = strlen(notice->z_ascii_checksum) + 1;
218         asn1_data = malloc(asn1_len);
219         if (!asn1_data) {
220             krb5_free_creds(Z_krb5_ctx, creds);
221             free(cksumbuf.data);
222             return ZAUTH_FAILED;
223         }
224         /* HOLDING: creds, asn1_data, cksumbuf.data */
225         result = ZReadZcode(notice->z_ascii_checksum,
226                             asn1_data, asn1_len, &asn1_len);
227         if (result != ZERR_NONE) {
228             krb5_free_creds(Z_krb5_ctx, creds);
229             free(asn1_data);
230             free(cksumbuf.data);
231             return ZAUTH_FAILED;
232         }
233         /* HOLDING: creds, asn1_data, cksumbuf.data */
234
235 #if HAVE_KRB5_C_MAKE_CHECKSUM
236         /* Verify the checksum -- MIT crypto API */
237         memset(&checksum, 0, sizeof(checksum));
238         checksum.length = asn1_len;
239         checksum.contents = asn1_data;
240         checksum.checksum_type = cksumtype;
241         result = krb5_c_verify_checksum(Z_krb5_ctx,
242                                         keyblock, Z_KEYUSAGE_SRV_CKSUM,
243                                         &cksumbuf, &checksum, &valid);
244         free(asn1_data);
245         krb5_free_creds(Z_krb5_ctx, creds);
246         free(cksumbuf.data);
247         if (!result && valid)
248             return (ZAUTH_YES);
249         else
250             return (ZAUTH_FAILED);
251 #else
252         checksum.checksum.length = asn1_len;
253         checksum.checksum.data = asn1_data;
254         checksum.cksumtype = cksumtype;
255         /* HOLDING: creds, asn1_data, cksumbuf.data */
256
257         result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx);
258         krb5_free_creds(Z_krb5_ctx, creds);
259         if (result) {
260             free(asn1_data);
261             free(cksumbuf.data);
262             return result;
263         }
264         /* HOLDING: cryptctx, checksum, cksumbuf.data */
265         result = krb5_verify_checksum(Z_krb5_ctx, cryptctx,
266                                       Z_KEYUSAGE_SRV_CKSUM,
267                                       cksumbuf.data, cksumbuf.length,
268                                       &checksum);
269         krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
270         free(asn1_data);
271         free(cksumbuf.data);
272         if (result)
273             return (ZAUTH_FAILED);
274         else
275             return (ZAUTH_YES);
276 #endif
277     }
278 #endif /* HAVE_KRB5 */
279     return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO);
280 }