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(ZNotice_t *notice,
35 struct sockaddr_in *from)
37 /* If the value is already known, return it. */
38 if (notice->z_checked_auth != ZAUTH_UNSET)
39 return (notice->z_checked_auth);
44 if (!notice->z_ascii_checksum)
49 krb5_error_code result;
51 krb5_keyblock *keyblock;
53 krb5_cksumtype cksumtype;
56 char *cksum0_base, *cksum1_base, *cksum2_base;
57 char *svcinst, *x, *y;
58 char *asn1_data, *key_data;
59 int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len;
61 result = ZGetCreds(&creds);
67 /* Figure out what checksum type to use */
68 keyblock = Z_credskey(creds);
69 key_data = Z_keydata(keyblock);
70 key_len = Z_keylen(keyblock);
71 result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
73 krb5_free_creds(Z_krb5_ctx, creds);
74 return (ZAUTH_FAILED);
78 /* Assemble the things to be checksummed */
79 /* first part is from start of packet through z_default_format:
81 * - z_num_other_fields
95 cksum0_base = notice->z_packet;
96 x = notice->z_default_format;
97 cksum0_len = x + strlen(x) + 1 - cksum0_base;
98 /* second part is from z_multinotice through other fields:
103 cksum1_base = notice->z_multinotice;
104 if (notice->z_num_other_fields)
105 x = notice->z_other_fields[notice->z_num_other_fields];
107 x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
108 cksum1_len = x + strlen(x) + 1 - cksum1_base;
110 /* last part is the message body */
111 cksum2_base = notice->z_message;
112 cksum2_len = notice->z_message_len;
114 if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
116 (enctype == ENCTYPE_DES_CBC_CRC ||
117 enctype == ENCTYPE_DES_CBC_MD4 ||
118 enctype == ENCTYPE_DES_CBC_MD5)) {
119 /* try old-format checksum (covers cksum0 only) */
121 ZChecksum_t our_checksum;
123 our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
125 if (our_checksum == notice->z_checksum) {
126 krb5_free_creds(Z_krb5_ctx, creds);
132 cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
133 cksumbuf.data = malloc(cksumbuf.length);
134 if (!cksumbuf.data) {
135 krb5_free_creds(Z_krb5_ctx, creds);
138 /* HOLDING: creds, cksumbuf.data */
140 memcpy(cksumbuf.data, cksum0_base, cksum0_len);
141 memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len);
142 memcpy(cksumbuf.data + cksum0_len + cksum1_len,
143 cksum2_base, cksum2_len);
145 /* decode zcoded checksum */
146 /* The encoded form is always longer than the original */
147 asn1_len = strlen(notice->z_ascii_checksum) + 1;
148 asn1_data = malloc(asn1_len);
150 krb5_free_creds(Z_krb5_ctx, creds);
154 /* HOLDING: creds, asn1_data, cksumbuf.data */
155 result = ZReadZcode(notice->z_ascii_checksum,
156 asn1_data, asn1_len, &asn1_len);
157 if (result != ZERR_NONE) {
158 krb5_free_creds(Z_krb5_ctx, creds);
163 /* HOLDING: creds, asn1_data, cksumbuf.data */
165 valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
166 asn1_data, asn1_len);
169 krb5_free_creds(Z_krb5_ctx, creds);
177 #endif /* HAVE_KRB5 */
178 return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO);