]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZCkZAut.c
r4254@bucket (orig r244): kcr | 2008-01-20 14:40:42 -0500
[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(ZNotice_t *notice,
35                                  struct sockaddr_in *from)
36 {       
37     /* If the value is already known, return it. */
38     if (notice->z_checked_auth != ZAUTH_UNSET)
39         return (notice->z_checked_auth);
40
41     if (!notice->z_auth)
42         return (ZAUTH_NO);
43
44     if (!notice->z_ascii_checksum)
45         return (ZAUTH_NO);
46
47 #ifdef HAVE_KRB5
48     {
49         krb5_error_code result;
50         krb5_creds *creds;
51         krb5_keyblock *keyblock;
52         krb5_enctype enctype;
53         krb5_cksumtype cksumtype;
54         krb5_data cksumbuf;
55         int valid;
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;
60
61         result = ZGetCreds(&creds);
62
63         if (result)
64             return (ZAUTH_NO);
65         /* HOLDING: creds */
66
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);
72         if (result) {
73             krb5_free_creds(Z_krb5_ctx, creds);
74             return (ZAUTH_FAILED);
75         }
76         /* HOLDING: creds */
77
78         /* Assemble the things to be checksummed */
79         /* first part is from start of packet through z_default_format:
80          * - z_version
81          * - z_num_other_fields
82          * - z_kind
83          * - z_uid
84          * - z_port
85          * - z_auth
86          * - z_authent_len
87          * - z_ascii_authent
88          * - z_class
89          * - z_class_inst
90          * - z_opcode
91          * - z_sender
92          * - z_recipient
93          * - z_default_format
94          */
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:
99          * - z_multinotice
100          * - z_multiuid
101          * - z_other_fields[]
102          */
103         cksum1_base = notice->z_multinotice;
104         if (notice->z_num_other_fields)
105           x = notice->z_other_fields[notice->z_num_other_fields];
106         else
107           x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
108         cksum1_len  = x + strlen(x) + 1 - cksum1_base;
109
110         /* last part is the message body */
111         cksum2_base = notice->z_message;
112         cksum2_len  = notice->z_message_len;
113
114         if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
115             key_len == 8 &&
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) */
120
121             ZChecksum_t our_checksum;
122
123             our_checksum = des_quad_cksum(cksum0_base, NULL, cksum0_len, 0,
124                                           key_data);
125             if (our_checksum == notice->z_checksum) {
126                 krb5_free_creds(Z_krb5_ctx, creds);
127                 return ZAUTH_YES;
128             }
129         }
130         /* HOLDING: creds */
131
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);
136             return ZAUTH_NO;
137         }
138         /* HOLDING: creds, cksumbuf.data */
139
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);
144
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);
149         if (!asn1_data) {
150             krb5_free_creds(Z_krb5_ctx, creds);
151             free(cksumbuf.data);
152             return ZAUTH_FAILED;
153         }
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);
159             free(asn1_data);
160             free(cksumbuf.data);
161             return ZAUTH_FAILED;
162         }
163         /* HOLDING: creds, asn1_data, cksumbuf.data */
164
165         valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
166                                     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 }