1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains source for the ZMakeAuthentication function.
4 * Created by: Robert French
6 * $Id: ZMkAuth.c,v 1.20 2002/11/11 18:28:06 ghudson Exp $
8 * Copyright (c) 1987 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
16 static const char rcsid_ZMakeAuthentication_c[] = "$Id: ZMkAuth.c,v 1.20 2002/11/11 18:28:06 ghudson Exp $";
23 #if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
24 #define krb5_free_data(ctx, dat) free((dat)->data)
27 Code_t ZResetAuthentication () {
31 Code_t ZMakeAuthentication(notice, buffer, buffer_len, len)
32 register ZNotice_t *notice;
38 return ZMakeZcodeAuthentication(notice, buffer, buffer_len, len/*?XXX*/);
40 #if defined(HAVE_KRB4) || defined(HAVE_KRB5)
49 krb5_creds *creds_out;
51 result = ZGetCreds(&creds_out);
55 result = krb5_524_convert_creds(Z_krb5_ctx, creds_out, &cred);
56 /* krb5_free_creds(Z_krb5_ctx, creds_out);*/
59 /* HOLDING: creds_out */
61 if (creds_out->keyblock.enctype != ENCTYPE_DES_CBC_CRC)
62 return (KRB5_BAD_ENCTYPE);
63 session = (C_Block *)creds_out->keyblock.contents;
65 result = krb_mk_req_creds(&authent, &cred, 0);
66 if (result != MK_AP_OK)
67 return result + krb_err_base;
70 result = krb_mk_req(&authent, SERVER_SERVICE,
71 SERVER_INSTANCE, __Zephyr_realm, 0);
72 if (result != MK_AP_OK)
73 return (result+krb_err_base);
74 result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE,
75 __Zephyr_realm, &cred);
76 if (result != KSUCCESS)
77 return (result+krb_err_base);
79 session = (C_Block *)cred.session;
83 notice->z_authent_len = authent.length;
84 notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3);
85 /* zero length authent is an error, so malloc(0) is not a problem */
86 if (!notice->z_ascii_authent)
88 if ((result = ZMakeAscii(notice->z_ascii_authent,
91 authent.length)) != ZERR_NONE) {
92 free(notice->z_ascii_authent);
95 result = Z_FormatRawHeader(notice, buffer, buffer_len, len, &cstart,
97 free(notice->z_ascii_authent);
98 notice->z_authent_len = 0;
102 /* Compute a checksum over the header and message. */
103 checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, session);
104 checksum ^= des_quad_cksum(cend, NULL, buffer + *len - cend, 0,
106 checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
108 notice->z_checksum = checksum;
109 ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum);
113 notice->z_checksum = 0;
115 notice->z_authent_len = 0;
116 notice->z_ascii_authent = "";
117 return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL));
122 Code_t ZMakeZcodeAuthentication(notice, buffer, buffer_len, phdr_len)
123 register ZNotice_t *notice;
128 return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
132 Code_t ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
134 register ZNotice_t *notice;
141 krb5_error_code result;
143 krb5_keyblock *keyblock;
144 krb5_enctype enctype;
145 krb5_cksumtype cksumtype;
146 krb5_auth_context authctx;
149 char *svcinst, *x, *y;
150 char *cksum_start, *cstart, *cend, *asn1_data;
151 int plain_len; /* length of part not to be checksummed */
152 int cksum_len; /* length of part to be checksummed (incl cksum) */
153 int cksum0_len; /* length of part before checksum */
154 int cksum1_len; /* length of part after checksum */
155 int i, zcode_len, asn1_len;
157 result = ZGetCredsRealm(&creds, realm);
162 /* Figure out what checksum type to use */
163 keyblock = Z_credskey(creds);
164 result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
166 krb5_free_creds(Z_krb5_ctx, creds);
171 /* Create the authenticator */
172 result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
174 krb5_free_creds(Z_krb5_ctx, creds);
178 authent = (krb5_data *)malloc(sizeof(krb5_data));
180 /* HOLDING: creds, authctx */
181 result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */,
182 0 /* in_data */, creds, authent);
183 krb5_auth_con_free(Z_krb5_ctx, authctx);
185 krb5_free_creds(Z_krb5_ctx, creds);
188 /* HOLDING: creds, authent */
190 /* Encode the authenticator */
192 notice->z_authent_len = authent->length;
193 zcode_len = authent->length * 2 + 2; /* 2x growth plus Z and null */
194 notice->z_ascii_authent = (char *)malloc(zcode_len);
195 if (!notice->z_ascii_authent) {
196 krb5_free_data(Z_krb5_ctx, authent);
197 krb5_free_creds(Z_krb5_ctx, creds);
200 /* HOLDING: creds, authent, notice->z_ascii_authent */
201 result = ZMakeZcode(notice->z_ascii_authent, zcode_len,
202 authent->data, authent->length);
203 krb5_free_data(Z_krb5_ctx, authent);
205 free(notice->z_ascii_authent);
206 krb5_free_creds(Z_krb5_ctx, creds);
209 /* HOLDING: creds, notice->z_ascii_authent */
211 /* format the notice header, with a zero checksum */
212 result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len,
213 &cksum_start, &cksum_len, &cstart, &cend);
214 free(notice->z_ascii_authent);
215 notice->z_authent_len = 0;
217 krb5_free_creds(Z_krb5_ctx, creds);
222 /* Assemble the things to be checksummed */
223 plain_len = cksum_start - buffer;
224 cksum0_len = cstart - cksum_start;
225 cksum1_len = (cksum_start + cksum_len) - cend;
226 memset(&cksumbuf, 0, sizeof(cksumbuf));
227 cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len;
228 cksumbuf.data = malloc(cksumbuf.length);
229 if (!cksumbuf.data) {
230 krb5_free_creds(Z_krb5_ctx, creds);
233 /* HOLDING: creds, cksumbuf.data */
234 memcpy(cksumbuf.data, cksum_start, cksum0_len);
235 memcpy(cksumbuf.data + cksum0_len, cend, cksum1_len);
236 memcpy(cksumbuf.data + cksum0_len + cksum1_len,
237 notice->z_message, notice->z_message_len);
239 /* compute the checksum */
240 result = Z_Checksum(&cksumbuf, keyblock, cksumtype, &asn1_data, &asn1_len);
241 krb5_free_creds(Z_krb5_ctx, creds);
248 * OK.... we can zcode to a space starting at 'cstart',
249 * with a length of buffer_len - (plain_len + cksum_len).
250 * Then we tack on the end part, which is located at
251 * cksumbuf.data + cksum0_len and has length cksum1_len
253 result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len),
254 asn1_data, asn1_len);
256 zcode_len = strlen(cstart) + 1;
257 memcpy(cstart + zcode_len, cksumbuf.data + cksum0_len, cksum1_len);
258 *phdr_len -= cksum_len - (cksum0_len + cksum1_len);
259 *phdr_len += zcode_len;
262 /* free stuff up, and then return the result from the last call */
268 #endif /* HAVE_KRB5 */
272 int ZGetCreds(krb5_creds **creds_out) {
273 return ZGetCredsRealm(creds_out, __Zephyr_realm);
276 int ZGetCredsRealm(krb5_creds **creds_out, char *realm) {
278 krb5_ccache ccache; /* XXX make this a global or static?*/
281 result = krb5_cc_default(Z_krb5_ctx, &ccache);
285 memset((char *)&creds_in, 0, sizeof(creds_in));
286 result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
289 SERVER_SERVICE, SERVER_INSTANCE, 0);
291 krb5_cc_close(Z_krb5_ctx, ccache);
295 result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
297 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */
298 krb5_cc_close(Z_krb5_ctx, ccache);
302 creds_in.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* XXX? */
304 result = krb5_get_credentials(Z_krb5_ctx, 0, ccache, &creds_in, creds_out);
305 krb5_cc_close(Z_krb5_ctx, ccache);
306 krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */