]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZCkZAut.c
66fe7ce6fca34742d6db3097c52f1610eac15c5e
[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_creds *creds;
52         krb5_keyblock *keyblock;
53         krb5_enctype enctype;
54         krb5_cksumtype cksumtype;
55         krb5_data cksumbuf;
56         int valid;
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;
61
62         result = ZGetCreds(&creds);
63
64         if (result)
65             return (ZAUTH_NO);
66         /* HOLDING: creds */
67
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);
73         if (result) {
74             krb5_free_creds(Z_krb5_ctx, creds);
75             return (ZAUTH_FAILED);
76         }
77         /* HOLDING: creds */
78
79         /* Assemble the things to be checksummed */
80         /* first part is from start of packet through z_default_format:
81          * - z_version
82          * - z_num_other_fields
83          * - z_kind
84          * - z_uid
85          * - z_port
86          * - z_auth
87          * - z_authent_len
88          * - z_ascii_authent
89          * - z_class
90          * - z_class_inst
91          * - z_opcode
92          * - z_sender
93          * - z_recipient
94          * - z_default_format
95          */
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:
100          * - z_multinotice
101          * - z_multiuid
102          * - z_other_fields[]
103          */
104         cksum1_base = notice->z_multinotice;
105         if (notice->z_num_other_fields)
106           x = notice->z_other_fields[notice->z_num_other_fields];
107         else
108           x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
109         cksum1_len  = x + strlen(x) + 1 - cksum1_base;
110
111         /* last part is the message body */
112         cksum2_base = notice->z_message;
113         cksum2_len  = notice->z_message_len;
114
115         if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
116             key_len == 8 &&
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) */
121
122             ZChecksum_t our_checksum;
123
124             our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
125                                           key_data);
126             if (our_checksum == notice->z_checksum) {
127                 krb5_free_creds(Z_krb5_ctx, creds);
128                 return ZAUTH_YES;
129             }
130         }
131         /* HOLDING: creds */
132
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);
137             return ZAUTH_NO;
138         }
139         /* HOLDING: creds, cksumbuf.data */
140
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);
145
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);
150         if (!asn1_data) {
151             krb5_free_creds(Z_krb5_ctx, creds);
152             free(cksumbuf.data);
153             return ZAUTH_FAILED;
154         }
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);
160             free(asn1_data);
161             free(cksumbuf.data);
162             return ZAUTH_FAILED;
163         }
164         /* HOLDING: creds, asn1_data, cksumbuf.data */
165
166         valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, asn1_data, asn1_len);
167
168         free(asn1_data);
169         krb5_free_creds(Z_krb5_ctx, creds);
170         free(cksumbuf.data);
171
172         if (valid)
173           return ZAUTH_YES;
174         else
175           return ZAUTH_FAILED;
176     }
177 #endif /* HAVE_KRB5 */
178     return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO);
179 }