1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the ZCheckAuthentication function.
4 * Created by: Robert French
9 * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
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 $";
22 #if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
23 #define krb5_free_data(ctx, dat) free((dat)->data)
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
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.
34 Code_t ZCheckZcodeAuthentication(notice, from)
36 struct sockaddr_in *from;
38 /* If the value is already known, return it. */
39 if (notice->z_checked_auth != ZAUTH_UNSET)
40 return (notice->z_checked_auth);
45 if (!notice->z_ascii_checksum)
50 krb5_error_code result;
52 krb5_creds creds_in, *creds;
53 krb5_keyblock *keyblock;
55 krb5_cksumtype cksumtype;
57 #if HAVE_KRB5_C_MAKE_CHECKSUM
58 krb5_checksum checksum;
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);
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));
78 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
80 krb5_cc_close(Z_krb5_ctx, ccache);
84 /* construct the service principal */
85 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
86 strlen(__Zephyr_realm),
88 SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
90 krb5_free_cred_contents(Z_krb5_ctx, &creds_in);
91 krb5_cc_close(Z_krb5_ctx, ccache);
94 /* HOLDING: creds_in.server */
96 /* look up or get the credentials we need */
97 result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
99 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
100 krb5_cc_close(Z_krb5_ctx, ccache);
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);
114 krb5_free_creds(Z_krb5_ctx, creds);
115 return (ZAUTH_FAILED);
118 keyblock = &creds->session;
119 key_data = keyblock->keyvalue.data;
120 key_len = keyblock->keyvalue.length;
126 result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype,
129 krb5_free_creds(Z_krb5_ctx, creds);
130 return (ZAUTH_FAILED);
135 result = Z_krb5_lookup_cksumtype(val[i], &cksumtype);
137 } while (result != 0);
140 krb5_free_creds(Z_krb5_ctx, creds);
141 return (ZAUTH_FAILED);
148 /* Assemble the things to be checksummed */
149 /* first part is from start of packet through z_default_format:
151 * - z_num_other_fields
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:
173 cksum1_base = notice->z_multinotice;
174 if (notice->z_num_other_fields)
175 x = notice->z_other_fields[notice->z_num_other_fields];
177 x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
178 cksum1_len = x + strlen(x) + 1 - cksum1_base;
180 /* last part is the message body */
181 cksum2_base = notice->z_message;
182 cksum2_len = notice->z_message_len;
184 if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
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) */
191 ZChecksum_t our_checksum;
193 our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
195 if (our_checksum == notice->z_checksum) {
196 krb5_free_creds(Z_krb5_ctx, creds);
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);
208 /* HOLDING: creds, cksumbuf.data */
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);
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);
220 krb5_free_creds(Z_krb5_ctx, creds);
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);
233 /* HOLDING: creds, asn1_data, cksumbuf.data */
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);
245 krb5_free_creds(Z_krb5_ctx, creds);
247 if (!result && valid)
250 return (ZAUTH_FAILED);
252 checksum.checksum.length = asn1_len;
253 checksum.checksum.data = asn1_data;
254 checksum.cksumtype = cksumtype;
255 /* HOLDING: creds, asn1_data, cksumbuf.data */
257 result = krb5_crypto_init(Z_krb5_ctx, keyblock, enctype, &cryptctx);
258 krb5_free_creds(Z_krb5_ctx, creds);
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,
269 krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
273 return (ZAUTH_FAILED);
278 #endif /* HAVE_KRB5 */
279 return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO);