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_keyblock *keyblock;
54 krb5_cksumtype cksumtype;
57 char *cksum0_base, *cksum1_base, *cksum2_base;
58 char *svcinst, *x, *y;
59 char *asn1_data, *key_data;
60 int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len;
62 result = ZGetCreds(&creds);
68 /* Figure out what checksum type to use */
69 keyblock = Z_credskey(creds);
70 key_data = Z_keydata(keyblock);
71 key_len = Z_keylen(keyblock);
72 result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
74 krb5_free_creds(Z_krb5_ctx, creds);
75 return (ZAUTH_FAILED);
79 /* Assemble the things to be checksummed */
80 /* first part is from start of packet through z_default_format:
82 * - z_num_other_fields
96 cksum0_base = notice->z_packet;
97 x = notice->z_default_format;
98 cksum0_len = x + strlen(x) + 1 - cksum0_base;
99 /* second part is from z_multinotice through other fields:
104 cksum1_base = notice->z_multinotice;
105 if (notice->z_num_other_fields)
106 x = notice->z_other_fields[notice->z_num_other_fields];
108 x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
109 cksum1_len = x + strlen(x) + 1 - cksum1_base;
111 /* last part is the message body */
112 cksum2_base = notice->z_message;
113 cksum2_len = notice->z_message_len;
115 if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
117 (enctype == ENCTYPE_DES_CBC_CRC ||
118 enctype == ENCTYPE_DES_CBC_MD4 ||
119 enctype == ENCTYPE_DES_CBC_MD5)) {
120 /* try old-format checksum (covers cksum0 only) */
122 ZChecksum_t our_checksum;
124 our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
126 if (our_checksum == notice->z_checksum) {
127 krb5_free_creds(Z_krb5_ctx, creds);
133 cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
134 cksumbuf.data = malloc(cksumbuf.length);
135 if (!cksumbuf.data) {
136 krb5_free_creds(Z_krb5_ctx, creds);
139 /* HOLDING: creds, cksumbuf.data */
141 memcpy(cksumbuf.data, cksum0_base, cksum0_len);
142 memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len);
143 memcpy(cksumbuf.data + cksum0_len + cksum1_len,
144 cksum2_base, cksum2_len);
146 /* decode zcoded checksum */
147 /* The encoded form is always longer than the original */
148 asn1_len = strlen(notice->z_ascii_checksum) + 1;
149 asn1_data = malloc(asn1_len);
151 krb5_free_creds(Z_krb5_ctx, creds);
155 /* HOLDING: creds, asn1_data, cksumbuf.data */
156 result = ZReadZcode(notice->z_ascii_checksum,
157 asn1_data, asn1_len, &asn1_len);
158 if (result != ZERR_NONE) {
159 krb5_free_creds(Z_krb5_ctx, creds);
164 /* HOLDING: creds, asn1_data, cksumbuf.data */
166 valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, 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);