]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/lib/ZMkAuth.c
r4266@bucket (orig r256): kcr | 2008-01-20 22:39:30 -0500
[1ts-debian.git] / zephyr / lib / ZMkAuth.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains source for the ZMakeAuthentication function.
3  *
4  *      Created by:     Robert French
5  *
6  *      $Id$
7  *
8  *      Copyright (c) 1987 by the Massachusetts Institute of Technology.
9  *      For copying and distribution information, see the file
10  *      "mit-copyright.h".
11  */
12
13 #include <internal.h>
14
15 #ifndef lint
16 static const char rcsid_ZMakeAuthentication_c[] = "$Id$";
17 #endif
18
19 #ifdef HAVE_KRB4
20 #include <krb_err.h>
21 #endif
22
23 #if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
24 #define krb5_free_data(ctx, dat) free((dat)->data)
25 #endif
26
27 Code_t
28 ZResetAuthentication(void)
29 {
30     return ZERR_NONE;
31 }
32
33 Code_t
34 ZMakeAuthentication(register ZNotice_t *notice,
35                     char *buffer,
36                     int buffer_len,
37                     int *len)
38 {
39 #ifdef HAVE_KRB5
40     return ZMakeZcodeAuthentication(notice, buffer, buffer_len, len/*?XXX*/);
41 #else
42 #ifdef HAVE_KRB4
43     int result;
44     time_t now;
45     KTEXT_ST authent;
46     char *cstart, *cend;
47     ZChecksum_t checksum;
48     CREDENTIALS cred;
49     C_Block *session;
50
51     result = krb_mk_req(&authent, SERVER_SERVICE,
52                         SERVER_INSTANCE, __Zephyr_realm, 0);
53     if (result != MK_AP_OK)
54         return (result+krb_err_base);
55     result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE,
56                           __Zephyr_realm, &cred);
57     if (result != KSUCCESS)
58         return (result+krb_err_base);
59
60     session = (C_Block *)cred.session;
61
62     notice->z_auth = 1;
63     notice->z_authent_len = authent.length;
64     notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3);
65     /* zero length authent is an error, so malloc(0) is not a problem */
66     if (!notice->z_ascii_authent)
67         return (ENOMEM);
68     if ((result = ZMakeAscii(notice->z_ascii_authent,
69                              authent.length*3,
70                              authent.dat,
71                              authent.length)) != ZERR_NONE) {
72         free(notice->z_ascii_authent);
73         return (result);
74     }
75     result = Z_FormatRawHeader(notice, buffer, buffer_len, len, &cstart,
76                                &cend);
77     free(notice->z_ascii_authent);
78     notice->z_authent_len = 0;
79     if (result)
80         return(result);
81
82     /* Compute a checksum over the header and message. */
83     checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, session);
84     checksum ^= des_quad_cksum(cend, NULL, buffer + *len - cend, 0,
85                                session);
86     checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
87                                0, session);
88     notice->z_checksum = checksum;
89     ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum);
90
91     return (ZERR_NONE);
92 #else
93     notice->z_checksum = 0;
94     notice->z_auth = 1;
95     notice->z_authent_len = 0;
96     notice->z_ascii_authent = "";
97     return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL));
98 #endif
99 #endif
100 }
101
102 Code_t
103 ZMakeZcodeAuthentication(register ZNotice_t *notice,
104                          char *buffer,
105                          int buffer_len,
106                          int *phdr_len)
107 {
108     return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
109                                          __Zephyr_realm);
110 }
111
112 Code_t
113 ZMakeZcodeRealmAuthentication(register ZNotice_t *notice,
114                               char *buffer,
115                               int buffer_len,
116                               int *phdr_len,
117                               char *realm)
118 {
119 #ifdef HAVE_KRB5
120     krb5_error_code result;
121     krb5_creds *creds;
122     krb5_keyblock *keyblock;
123     krb5_auth_context authctx;
124     krb5_data *authent;
125     char *cksum_start, *cstart, *cend;
126     int cksum_len, zcode_len, phdr_adj;
127
128     result = ZGetCredsRealm(&creds, realm);
129     if (result)
130         return result;
131     /* HOLDING: creds */
132
133     /* Figure out what checksum type to use */
134     keyblock = Z_credskey(creds);
135     /* HOLDING: creds */
136
137     /* Create the authenticator */
138     result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
139     if (result) {
140         krb5_free_creds(Z_krb5_ctx, creds);
141         return (result);
142     }
143
144     authent = (krb5_data *)malloc(sizeof(krb5_data));
145
146     /* HOLDING: creds, authctx */
147     result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */,
148                                   0 /* in_data */, creds, authent);
149     krb5_auth_con_free(Z_krb5_ctx, authctx);
150     if (result) {
151         krb5_free_creds(Z_krb5_ctx, creds);
152         return (result);
153     }
154     /* HOLDING: creds, authent */
155
156     /* Encode the authenticator */
157     notice->z_auth = 1;
158     notice->z_authent_len = authent->length;
159     zcode_len = authent->length * 2 + 2; /* 2x growth plus Z and null */
160     notice->z_ascii_authent = (char *)malloc(zcode_len);
161     if (!notice->z_ascii_authent) {
162         krb5_free_data(Z_krb5_ctx, authent);
163         krb5_free_creds(Z_krb5_ctx, creds);
164         return (ENOMEM);
165     }
166     /* HOLDING: creds, authent, notice->z_ascii_authent */
167     result = ZMakeZcode(notice->z_ascii_authent, zcode_len,
168                         (unsigned char *)authent->data, authent->length);
169     krb5_free_data(Z_krb5_ctx, authent);
170     if (result) {
171         free(notice->z_ascii_authent);
172         krb5_free_creds(Z_krb5_ctx, creds);
173         return (result);
174     }
175     /* HOLDING: creds, notice->z_ascii_authent */
176
177     /* format the notice header, with a zero checksum */
178     result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len,
179                                   &cksum_start, &cksum_len, &cstart, &cend);
180     free(notice->z_ascii_authent);
181     notice->z_authent_len = 0;
182     if (result) {
183         krb5_free_creds(Z_krb5_ctx, creds);
184         return (result);
185     }
186     result = Z_InsertZcodeChecksum(keyblock, notice, buffer, cksum_start,
187                                    cksum_len, cstart, cend, buffer_len,
188                                    &phdr_adj);
189     krb5_free_creds(Z_krb5_ctx, creds);
190     if (result) {
191          return result;
192     }
193     *phdr_len += phdr_adj;
194
195     return (result);
196 #endif /* HAVE_KRB5 */
197 }
198
199 #ifdef HAVE_KRB5
200 int
201 ZGetCreds(krb5_creds **creds_out)
202 {
203   return ZGetCredsRealm(creds_out, __Zephyr_realm);
204 }
205
206 int
207 ZGetCredsRealm(krb5_creds **creds_out,
208                char *realm)
209 {
210   krb5_creds creds_in;
211   krb5_ccache ccache; /* XXX make this a global or static?*/
212   int result;
213
214   result = krb5_cc_default(Z_krb5_ctx, &ccache);
215   if (result)
216     return result;
217
218   memset((char *)&creds_in, 0, sizeof(creds_in));
219   result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
220                                 strlen(realm),
221                                 realm,
222                                 SERVER_SERVICE, SERVER_INSTANCE, 0);
223   if (result) {
224     krb5_cc_close(Z_krb5_ctx, ccache);
225     return result;
226   }
227
228   result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
229   if (result) {
230     krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */
231     krb5_cc_close(Z_krb5_ctx, ccache);
232     return result;
233   }
234
235 #ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
236   creds_in.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* XXX? */
237 #else
238   creds_in.session.keytype = KEYTYPE_DES; /* XXX? */
239 #endif
240
241   result = krb5_get_credentials(Z_krb5_ctx, 0, ccache, &creds_in, creds_out);
242   krb5_cc_close(Z_krb5_ctx, ccache);
243   krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */
244
245   return result;
246 }
247 #endif