1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright 2000, 2004 by the Massachusetts Institute of Technology.
8 * All Rights Reserved.
9 *
10 * Export of this software from the United States of America may
11 * require a specific license from the United States Government.
12 * It is the responsibility of any person or organization contemplating
13 * export to obtain such a license before exporting.
14 *
15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16 * distribute this software and its documentation for any purpose and
17 * without fee is hereby granted, provided that the above copyright
18 * notice appear in all copies and that both that copyright notice and
19 * this permission notice appear in supporting documentation, and that
20 * the name of M.I.T. not be used in advertising or publicity pertaining
21 * to distribution of the software without specific, written prior
22 * permission. Furthermore if you modify this software you must label
23 * your software as modified software and not distribute it in such a
24 * fashion that it might be confused with the original M.I.T. software.
25 * M.I.T. makes no representations about the suitability of
26 * this software for any purpose. It is provided "as is" without express
27 * or implied warranty.
28 *
29 */
30 /*
31 * Copyright 1993 by OpenVision Technologies, Inc.
32 *
33 * Permission to use, copy, modify, distribute, and sell this software
34 * and its documentation for any purpose is hereby granted without fee,
35 * provided that the above copyright notice appears in all copies and
36 * that both that copyright notice and this permission notice appear in
37 * supporting documentation, and that the name of OpenVision not be used
38 * in advertising or publicity pertaining to distribution of the software
39 * without specific, written prior permission. OpenVision makes no
40 * representations about the suitability of this software for any
41 * purpose. It is provided "as is" without express or implied warranty.
42 *
43 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
44 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
45 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
46 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
47 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
48 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
49 * PERFORMANCE OF THIS SOFTWARE.
50 */
51
52 /*
53 * Copyright (C) 1998 by the FundsXpress, INC.
54 *
55 * All rights reserved.
56 *
57 * Export of this software from the United States of America may require
58 * a specific license from the United States Government. It is the
59 * responsibility of any person or organization contemplating export to
60 * obtain such a license before exporting.
61 *
62 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
63 * distribute this software and its documentation for any purpose and
64 * without fee is hereby granted, provided that the above copyright
65 * notice appear in all copies and that both that copyright notice and
66 * this permission notice appear in supporting documentation, and that
67 * the name of FundsXpress. not be used in advertising or publicity pertaining
68 * to distribution of the software without specific, written prior
69 * permission. FundsXpress makes no representations about the suitability of
70 * this software for any purpose. It is provided "as is" without express
71 * or implied warranty.
72 *
73 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
74 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
75 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
76 */
77
78 #include "k5-int.h"
79 #include "gssapiP_krb5.h"
80 #ifdef HAVE_MEMORY_H
81 #include <memory.h>
82 #endif
83 #include <assert.h>
84 #include "auth_con.h"
85
86 #ifdef CFX_EXERCISE
87 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
88 #else
89 #define CFX_ACCEPTOR_SUBKEY 1
90 #endif
91
92 /*
93 * Decode, decrypt and store the forwarded creds in the local ccache.
94 * and populate the callers delegated credential handle if it
95 * was provided.
96 */
97 static krb5_error_code
98 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
99 krb5_context context;
100 krb5_auth_context auth_context;
101 krb5_data *inbuf;
102 krb5_gss_cred_id_t *out_cred;
103 {
104 krb5_creds ** creds = NULL;
105 krb5_error_code retval;
106 krb5_ccache ccache = NULL;
107 krb5_gss_cred_id_t cred = NULL;
108 krb5_auth_context new_auth_ctx = NULL;
109 krb5_int32 flags_org;
110
111 /* Solaris Kerberos */
112 KRB5_LOG0(KRB5_INFO, "rd_and_store_for_creds() start");
113
114 if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
115 return retval;
116 krb5_auth_con_setflags(context, auth_context,
117 0);
118
119 /*
120 * By the time krb5_rd_cred is called here (after krb5_rd_req has been
121 * called in krb5_gss_accept_sec_context), the "keyblock" field of
122 * auth_context contains a pointer to the session key, and the
123 * "recv_subkey" field might contain a session subkey. Either of
124 * these (the "recv_subkey" if it isn't NULL, otherwise the
125 * "keyblock") might have been used to encrypt the encrypted part of
126 * the KRB_CRED message that contains the forwarded credentials. (The
127 * Java Crypto and Security Implementation from the DSTC in Australia
128 * always uses the session key. But apparently it never negotiates a
129 * subkey, so this code works fine against a JCSI client.) Up to the
130 * present, though, GSSAPI clients linked against the MIT code (which
131 * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
132 * all -- at this level. So if the first call to krb5_rd_cred fails,
133 * we should call it a second time with another auth context freshly
134 * created by krb5_auth_con_init. All of its keyblock fields will be
135 * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
136 * unencrypted. (The MIT code doesn't actually send the KRB_CRED
137 * message in the clear -- the "authenticator" whose "checksum" ends up
138 * containing the KRB_CRED message does get encrypted.)
139 */
140 /* Solaris Kerberos */
141 if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) {
142 krb5_enctype enctype = ENCTYPE_NULL;
143 /*
144 * If the client is using non-DES enctypes it really ought to
145 * send encrypted KRB-CREDs...
146 */
147 if (auth_context->keyblock != NULL)
148 enctype = auth_context->keyblock->enctype;
149 switch (enctype) {
150 case ENCTYPE_DES_CBC_MD5:
151 case ENCTYPE_DES_CBC_CRC:
152 case ENCTYPE_DES3_CBC_SHA1:
153 break;
154 default:
155 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
156 "krb5_rd_cred() retval = %d\n", retval);
157 goto cleanup;
158 /* NOTREACHED */
159 break;
160 }
161
162 /* Try to krb5_rd_cred() likely unencrypted KRB-CRED */
163 if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
164 goto cleanup;
165 krb5_auth_con_setflags(context, new_auth_ctx, 0);
166 if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
167 &creds, NULL))) {
168 /* Solaris Kerberos */
169 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
170 "krb5_rd_cred() retval = %d\n", retval);
171 goto cleanup;
172 }
173 }
174
175 if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
176 ccache = NULL;
177 goto cleanup;
178 }
179
180 if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) {
181 /* Solaris Kerberos */
182 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
183 "krb5_cc_initialize() retval = %d\n", retval);
184 goto cleanup;
185 }
186
187 if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) {
188 /* Solaris Kerberos */
189 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
190 "krb5_cc_store_cred() retval = %d\n", retval);
191 goto cleanup;
192 }
193
194 /* generate a delegated credential handle */
195 if (out_cred) {
196 /* allocate memory for a cred_t... */
197 if (!(cred =
198 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
199 retval = ENOMEM; /* out of memory? */
200 *out_cred = NULL;
201 goto cleanup;
202 }
203
204 /* zero it out... */
205 /* Solaris Kerberos */
206 (void) memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
207
208 retval = k5_mutex_init(&cred->lock);
209 if (retval) {
210 xfree(cred);
211 cred = NULL;
212 goto cleanup;
213 }
214
215 /* copy the client principle into it... */
216 if ((retval =
217 krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
218 /* Solaris Kerberos */
219 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
220 "krb5_copy_principal() retval = %d\n", retval);
221 k5_mutex_destroy(&cred->lock);
222 retval = ENOMEM; /* out of memory? */
223 xfree(cred); /* clean up memory on failure */
224 cred = NULL;
225 goto cleanup;
226 }
227
228 cred->usage = GSS_C_INITIATE; /* we can't accept with this */
229 /* cred->princ already set */
230 cred->prerfc_mech = 1; /* this cred will work with all three mechs */
231 cred->rfc_mech = 1;
232 cred->keytab = NULL; /* no keytab associated with this... */
233 cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
234 cred->ccache = ccache; /* the ccache containing the credential */
235 ccache = NULL; /* cred takes ownership so don't destroy */
236 }
237
238 /* If there were errors, there might have been a memory leak
239 if (!cred)
240 if ((retval = krb5_cc_close(context, ccache)))
241 goto cleanup;
242 */
243 cleanup:
244 if (creds)
245 krb5_free_tgt_creds(context, creds);
246
247 if (ccache)
248 (void)krb5_cc_destroy(context, ccache);
249
250 if (out_cred)
251 *out_cred = cred; /* return credential */
252
253 if (new_auth_ctx)
254 krb5_auth_con_free(context, new_auth_ctx);
255
256 krb5_auth_con_setflags(context, auth_context, flags_org);
257
258 /* Solaris Kerberos */
259 KRB5_LOG(KRB5_INFO, "rd_and_store_for_creds() end retval %d", retval);
260 return retval;
261 }
262
263 /*
264 * SUNW15resync
265 * Most of the logic here left "as is" because of lots of fixes MIT
266 * does not have yet
267 */
268 OM_uint32
269 krb5_gss_accept_sec_context(minor_status, context_handle,
270 verifier_cred_handle, input_token,
271 input_chan_bindings, src_name, mech_type,
272 output_token, ret_flags, time_rec,
273 delegated_cred_handle)
274 OM_uint32 *minor_status;
275 gss_ctx_id_t *context_handle;
276 gss_cred_id_t verifier_cred_handle;
277 gss_buffer_t input_token;
278 gss_channel_bindings_t input_chan_bindings;
279 gss_name_t *src_name;
280 gss_OID *mech_type;
281 gss_buffer_t output_token;
282 OM_uint32 *ret_flags;
283 OM_uint32 *time_rec;
284 gss_cred_id_t *delegated_cred_handle;
285 {
286 krb5_context context;
287 unsigned char *ptr, *ptr2;
288 char *sptr;
289 long tmp;
290 size_t md5len;
291 int bigend;
292 krb5_gss_cred_id_t cred = 0;
293 krb5_data ap_rep, ap_req;
294 krb5_ap_req *request = NULL;
295 int i;
296 krb5_error_code code;
297 krb5_address addr, *paddr;
298 krb5_authenticator *authdat = 0;
299 krb5_checksum reqcksum;
300 krb5_principal name = NULL;
301 krb5_ui_4 gss_flags = 0;
302 krb5_gss_ctx_id_rec *ctx = 0;
303 krb5_timestamp now;
304 gss_buffer_desc token;
305 krb5_auth_context auth_context = NULL;
306 krb5_ticket * ticket = NULL;
307 int option_id;
308 krb5_data option;
309 const gss_OID_desc *mech_used = NULL;
310 OM_uint32 major_status = GSS_S_FAILURE;
311 krb5_error krb_error_data;
312 krb5_data scratch;
313 gss_cred_id_t cred_handle = NULL;
314 krb5_gss_cred_id_t deleg_cred = NULL;
315 OM_uint32 saved_ap_options = 0;
316 krb5int_access kaccess;
317 int cred_rcache = 0;
318 OM_uint32 t_minor_status = 0;
319
320 KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
321
322 code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
323 if (code) {
324 *minor_status = code;
325 return(GSS_S_FAILURE);
326 }
327
328 code = krb5_gss_init_context(&context);
329 if (code) {
330 *minor_status = code;
331 return GSS_S_FAILURE;
332 }
333
334 /* set up returns to be freeable */
335
336 if (src_name)
337 *src_name = (gss_name_t) NULL;
338 output_token->length = 0;
339 output_token->value = NULL;
340 token.value = 0;
341 reqcksum.contents = 0;
342 ap_req.data = 0;
343 ap_rep.data = 0;
344
345 if (mech_type)
346 *mech_type = GSS_C_NULL_OID;
347 /* initialize the delegated cred handle to NO_CREDENTIAL for now */
348 if (delegated_cred_handle)
349 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
350
351 /*
352 * Context handle must be unspecified. Actually, it must be
353 * non-established, but currently, accept_sec_context never returns
354 * a non-established context handle.
355 */
356 /*SUPPRESS 29*/
357 if (*context_handle != GSS_C_NO_CONTEXT) {
358 *minor_status = 0;
359
360 /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
361 * for this error. This conflicts somewhat with RFC2743 which states
362 * GSS_S_NO_CONTEXT should be returned only for sucessor calls following
363 * GSS_S_CONTINUE_NEEDED status returns. Note the MIT code doesn't
364 * return GSS_S_NO_CONTEXT at all.
365 */
366
367 major_status = GSS_S_NO_CONTEXT;
368 KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
369 "error GSS_S_NO_CONTEXT");
370 goto cleanup;
371 }
372
373 /* verify the token's integrity, and leave the token in ap_req.
374 figure out which mech oid was used, and save it */
375
376 ptr = (unsigned char *) input_token->value;
377
378 if (!(code = g_verify_token_header(gss_mech_krb5,
379 (uint32_t *)&(ap_req.length),
380 &ptr, KG_TOK_CTX_AP_REQ,
381 input_token->length, 1))) {
382 mech_used = gss_mech_krb5;
383 } else if ((code == G_WRONG_MECH) &&
384 !(code = g_verify_token_header(gss_mech_krb5_old,
385 (uint32_t *)&(ap_req.length),
386 &ptr, KG_TOK_CTX_AP_REQ,
387 input_token->length, 1))) {
388 /*
389 * Previous versions of this library used the old mech_id
390 * and some broken behavior (wrong IV on checksum
391 * encryption). We support the old mech_id for
392 * compatibility, and use it to decide when to use the
393 * old behavior.
394 */
395 mech_used = gss_mech_krb5_old;
396 } else {
397 major_status = GSS_S_DEFECTIVE_TOKEN;
398 goto fail;
399 }
400
401 sptr = (char *) ptr;
402 TREAD_STR(sptr, ap_req.data, ap_req.length);
403
404 /*
405 * Solaris Kerberos:
406 * We need to decode the request now so that we can get the
407 * service principal in order to try and acquire a cred for it.
408 * below in the "handle default cred handle" code block.
409 */
410 if (!krb5_is_ap_req(&ap_req)) {
411 code = KRB5KRB_AP_ERR_MSG_TYPE;
412 goto fail;
413 }
414 /* decode the AP-REQ into request */
415 if ((code = decode_krb5_ap_req(&ap_req, &request))) {
416 if (code == KRB5_BADMSGTYPE)
417 code = KRB5KRB_AP_ERR_BADVERSION;
418 goto fail;
419 }
420
421 /* handle default cred handle */
422 /*
423 * Solaris Kerberos:
424 * If there is no princ associated with the cred then treat it the
425 * the same as GSS_C_NO_CREDENTIAL.
426 */
427 if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
428 ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
429 /* Note that we try to acquire a cred for the service principal
430 * named in the AP-REQ. This allows us to implement option (ii)
431 * of the recommended behaviour for GSS_Accept_sec_context() as
432 * described in section 1.1.1.3 of RFC2743.
433
434 * This is far more useful that option (i), for which we would
435 * acquire a cred for GSS_C_NO_NAME.
436 */
437 /* copy the princ from the ap-req or we'll lose it when we free
438 the ap-req */
439 krb5_principal princ;
440 if ((code = krb5_copy_principal(context, request->ticket->server,
441 &princ))) {
442 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
443 "krb5_copy_principal() error code %d", code);
444 major_status = GSS_S_FAILURE;
445 goto fail;
446 }
447 /* intern the acceptor name */
448 if (! kg_save_name((gss_name_t) princ)) {
449 code = G_VALIDATE_FAILED;
450 major_status = GSS_S_FAILURE;
451 goto fail;
452 }
453 major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
454 (gss_name_t) princ,
455 GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
456 GSS_C_ACCEPT, &cred_handle,
457 NULL, NULL);
458
459 if (major_status != GSS_S_COMPLETE){
460
461 /* Solaris kerberos: RFC2743 indicate this should be returned if we
462 * can't aquire a default cred.
463 */
464 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
465 "krb5_gss_acquire_cred() error"
466 "orig major_status = %d, now = GSS_S_NO_CRED\n",
467 major_status);
468
469 major_status = GSS_S_NO_CRED;
470 goto fail;
471 }
472
473 } else {
474 cred_handle = verifier_cred_handle;
475 }
476
477 major_status = krb5_gss_validate_cred((OM_uint32*) &code,
478 cred_handle);
479
480 if (GSS_ERROR(major_status)){
481
482 /* Solaris kerberos: RFC2743 indicate GSS_S_NO_CRED should be returned if
483 * the supplied cred isn't valid.
484 */
485
486 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
487 "krb5_gss_validate_cred() error"
488 "orig major_status = %d, now = GSS_S_NO_CRED\n",
489 major_status);
490
491 major_status = GSS_S_NO_CRED;
492 goto fail;
493 }
494
495 cred = (krb5_gss_cred_id_t) cred_handle;
496
497 /* make sure the supplied credentials are valid for accept */
498
499 if ((cred->usage != GSS_C_ACCEPT) &&
500 (cred->usage != GSS_C_BOTH)) {
501 code = 0;
502 KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
503 "error GSS_S_NO_CONTEXT");
504 major_status = GSS_S_NO_CRED;
505 goto fail;
506 }
507
508 /* construct the sender_addr */
509
510 if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
511 (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
512 /* XXX is this right? */
513 addr.addrtype = ADDRTYPE_INET;
514 addr.length = input_chan_bindings->initiator_address.length;
515 addr.contents = input_chan_bindings->initiator_address.value;
516
517 paddr = &addr;
518 } else {
519 paddr = NULL;
520 }
521
522 /* verify the AP_REQ message - setup the auth_context and rcache */
523
524 if ((code = krb5_auth_con_init(context, &auth_context))) {
525 major_status = GSS_S_FAILURE;
526 /* Solaris Kerberos */
527 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
528 "krb5_auth_con_init() error code %d", code);
529 goto fail;
530 }
531
532 (void) krb5_auth_con_setflags(context, auth_context,
533 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
534
535 if (cred->rcache) {
536 cred_rcache = 1;
537 if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
538 major_status = GSS_S_FAILURE;
539 /* Solaris Kerberos */
540 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
541 "krb5_auth_con_setrcache() error code %d", code);
542 goto fail;
543 }
544 }
545 if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
546 major_status = GSS_S_FAILURE;
547 /* Solaris Kerberos */
548 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
549 "krb5_auth_con_setaddrs() error code %d", code);
550 goto fail;
551 }
552
553 if ((code = krb5_rd_req_decoded(context, &auth_context, request,
554 cred->princ, cred->keytab, NULL, &ticket))) {
555 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
556 "krb5_rd_req() error code %d", code);
557 if (code == KRB5_KT_KVNONOTFOUND || code == KRB5_KT_NOTFOUND) {
558 major_status = GSS_S_DEFECTIVE_CREDENTIAL;
559 code = KRB5KRB_AP_ERR_NOKEY;
560 }
561 else if (code == KRB5KRB_AP_WRONG_PRINC) {
562 major_status = GSS_S_NO_CRED;
563 code = KRB5KRB_AP_ERR_NOT_US;
564 }
565 else if (code == KRB5KRB_AP_ERR_REPEAT)
566 major_status = GSS_S_DUPLICATE_TOKEN;
567 else
568 major_status = GSS_S_FAILURE;
569 goto fail;
570 }
571 krb5_auth_con_setflags(context, auth_context,
572 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
573
574 krb5_auth_con_getauthenticator(context, auth_context, &authdat);
575
576 #if 0
577 /* make sure the necessary parts of the authdat are present */
578
579 if ((authdat->authenticator->subkey == NULL) ||
580 (authdat->ticket->enc_part2 == NULL)) {
581 code = KG_NO_SUBKEY;
582 major_status = GSS_S_FAILURE;
583 goto fail;
584 }
585 #endif
586
587 {
588 /* gss krb5 v1 */
589
590 /* stash this now, for later. */
591 code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
592 if (code) {
593 /* Solaris Kerberos */
594 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
595 "krb5_c_checksum_length() error code %d", code);
596 major_status = GSS_S_FAILURE;
597 goto fail;
598 }
599
600 /* verify that the checksum is correct */
601
602 /*
603 The checksum may be either exactly 24 bytes, in which case
604 no options are specified, or greater than 24 bytes, in which case
605 one or more options are specified. Currently, the only valid
606 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
607 */
608
609 if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
610 (authdat->checksum->length < 24)) {
611 code = 0;
612 major_status = GSS_S_BAD_BINDINGS;
613 goto fail;
614 }
615
616 /*
617 "Be liberal in what you accept, and
618 conservative in what you send"
619 -- rfc1123
620
621 This code will let this acceptor interoperate with an initiator
622 using little-endian or big-endian integer encoding.
623 */
624
625 ptr = (unsigned char *) authdat->checksum->contents;
626 bigend = 0;
627
628 TREAD_INT(ptr, tmp, bigend);
629
630 if (tmp != md5len) {
631 ptr = (unsigned char *) authdat->checksum->contents;
632 bigend = 1;
633
634 TREAD_INT(ptr, tmp, bigend);
635
636 if (tmp != md5len) {
637 code = KG_BAD_LENGTH;
638 major_status = GSS_S_FAILURE;
639 goto fail;
640 }
641 }
642
643 /* at this point, bigend is set according to the initiator's
644 byte order */
645
646
647 /*
648 The following section of code attempts to implement the
649 optional channel binding facility as described in RFC2743.
650
651 Since this facility is optional channel binding may or may
652 not have been provided by either the client or the server.
653
654 If the server has specified input_chan_bindings equal to
655 GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
656 the server does provide channel bindings then we compute
657 a checksum and compare against those provided by the
658 client. If the check fails we test the clients checksum
659 to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
660 If either test succeeds we continue without error.
661 */
662 if ((code = kg_checksum_channel_bindings(context,
663 input_chan_bindings,
664 &reqcksum, bigend))) {
665 /* Solaris Kerberos */
666 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
667 "kg_checksum_channel_bindings() error code %d", code);
668 major_status = GSS_S_BAD_BINDINGS;
669 goto fail;
670 }
671
672 TREAD_STR(ptr, ptr2, reqcksum.length);
673
674 if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
675 if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
676 xfree(reqcksum.contents);
677 reqcksum.contents = 0;
678 if ((code = kg_checksum_channel_bindings(context,
679 GSS_C_NO_CHANNEL_BINDINGS,
680 &reqcksum, bigend))) {
681 major_status = GSS_S_BAD_BINDINGS;
682 goto fail;
683 }
684 if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
685 code = 0;
686 major_status = GSS_S_BAD_BINDINGS;
687 goto fail;
688 }
689 }
690
691 }
692
693 TREAD_INT(ptr, gss_flags, bigend);
694
695 /* if the checksum length > 24, there are options to process */
696
697 if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
698
699 i = authdat->checksum->length - 24;
700
701 if (i >= 4) {
702
703 TREAD_INT16(ptr, option_id, bigend);
704
705 TREAD_INT16(ptr, option.length, bigend);
706
707 i -= 4;
708
709 if (i < option.length || option.length < 0) {
710 code = KG_BAD_LENGTH;
711 major_status = GSS_S_FAILURE;
712 goto fail;
713 }
714
715 /* have to use ptr2, since option.data is wrong type and
716 macro uses ptr as both lvalue and rvalue */
717
718 TREAD_STR(ptr, ptr2, option.length);
719 option.data = (char *) ptr2;
720
721 i -= option.length;
722
723 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
724 major_status = GSS_S_FAILURE;
725 goto fail;
726 }
727
728 /* store the delegated credential */
729
730 code = rd_and_store_for_creds(context, auth_context, &option,
731 (delegated_cred_handle) ?
732 &deleg_cred : NULL);
733 if (code) {
734 major_status = GSS_S_FAILURE;
735 goto fail;
736 }
737
738 } /* if i >= 4 */
739 /* ignore any additional trailing data, for now */
740 #ifdef CFX_EXERCISE
741 {
742 FILE *f = fopen("/tmp/gsslog", "a");
743 if (f) {
744 fprintf(f,
745 "initial context token with delegation, %d extra bytes\n",
746 i);
747 fclose(f);
748 }
749 }
750 #endif
751 } else {
752 #ifdef CFX_EXERCISE
753 {
754 FILE *f = fopen("/tmp/gsslog", "a");
755 if (f) {
756 if (gss_flags & GSS_C_DELEG_FLAG)
757 fprintf(f,
758 "initial context token, delegation flag but too small\n");
759 else
760 /* no deleg flag, length might still be too big */
761 fprintf(f,
762 "initial context token, %d extra bytes\n",
763 authdat->checksum->length - 24);
764 fclose(f);
765 }
766 }
767 #endif
768 }
769 }
770
771 /* create the ctx struct and start filling it in */
772
773 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
774 == NULL) {
775 code = ENOMEM;
776 major_status = GSS_S_FAILURE;
777 goto fail;
778 }
779
780 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
781 ctx->mech_used = (gss_OID) mech_used;
782 ctx->auth_context = auth_context;
783 ctx->initiate = 0;
784 ctx->gss_flags = (GSS_C_TRANS_FLAG |
785 ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
786 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
787 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
788 ctx->seed_init = 0;
789 ctx->big_endian = bigend;
790 ctx->cred_rcache = cred_rcache;
791
792 /* Intern the ctx pointer so that delete_sec_context works */
793 if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
794 xfree(ctx);
795 ctx = 0;
796
797 /* Solaris Kerberos */
798 KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
799 "kg_save_ctx_id() error");
800 code = G_VALIDATE_FAILED;
801 major_status = GSS_S_FAILURE;
802 goto fail;
803 }
804
805 if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
806 /* Solaris Kerberos */
807 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
808 "krb5_copy_principal() error code %d", code);
809 major_status = GSS_S_FAILURE;
810 goto fail;
811 }
812
813 if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
814 /* Solaris Kerberos */
815 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
816 "krb5_copy_principal() 2 error code %d", code);
817 major_status = GSS_S_FAILURE;
818 goto fail;
819 }
820
821 if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
822 &ctx->subkey))) {
823 /* Solaris Kerberos */
824 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
825 "krb5_auth_con_getremotesubkey() error code %d", code);
826 major_status = GSS_S_FAILURE;
827 goto fail;
828 }
829
830 /* use the session key if the subkey isn't present */
831
832 if (ctx->subkey == NULL) {
833 if ((code = krb5_auth_con_getkey(context, auth_context,
834 &ctx->subkey))) {
835 /* Solaris Kerberos */
836 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
837 "krb5_auth_con_getkey() error code %d", code);
838 *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
839 major_status = GSS_S_FAILURE;
840 goto fail;
841 }
842 }
843
844 if (ctx->subkey == NULL) {
845 /* this isn't a very good error, but it's not clear to me this
846 can actually happen */
847 major_status = GSS_S_FAILURE;
848 code = KRB5KDC_ERR_NULL_KEY;
849 goto fail;
850 }
851
852 /* Solaris Kerberos */
853 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
854 "ctx->subkey->enctype=%d", ctx->subkey->enctype);
855
856 ctx->proto = 0;
857 switch(ctx->subkey->enctype) {
858 case ENCTYPE_DES_CBC_MD5:
859 case ENCTYPE_DES_CBC_CRC:
860 ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
861 ctx->signalg = SGN_ALG_DES_MAC_MD5;
862 ctx->cksum_size = 8;
863 ctx->sealalg = SEAL_ALG_DES;
864
865 /* fill in the encryption descriptors */
866
867 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
868 major_status = GSS_S_FAILURE;
869 goto fail;
870 }
871
872 for (i=0; i<ctx->enc->length; i++)
873 /*SUPPRESS 113*/
874 ctx->enc->contents[i] ^= 0xf0;
875
876 goto copy_subkey_to_seq;
877 break;
878
879 case ENCTYPE_DES3_CBC_SHA1:
880 ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
881 ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
882 ctx->cksum_size = 20;
883 ctx->sealalg = SEAL_ALG_DES3KD;
884
885 /* fill in the encryption descriptors */
886 copy_subkey:
887 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
888 major_status = GSS_S_FAILURE;
889 goto fail;
890 }
891 copy_subkey_to_seq:
892 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
893 major_status = GSS_S_FAILURE;
894 goto fail;
895 }
896 break;
897
898 case ENCTYPE_ARCFOUR_HMAC:
899 ctx->signalg = SGN_ALG_HMAC_MD5 ;
900 ctx->cksum_size = 8;
901 ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
902 goto copy_subkey;
903
904 default:
905 ctx->signalg = -1;
906 ctx->sealalg = -1;
907 ctx->proto = 1;
908 code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
909 &ctx->cksumtype);
910 if (code)
911 goto fail;
912 code = krb5_c_checksum_length(context, ctx->cksumtype,
913 (size_t *)&ctx->cksum_size);
914 if (code)
915 goto fail;
916 ctx->have_acceptor_subkey = 0;
917 goto copy_subkey;
918 }
919
920 /* Solaris Kerberos */
921 KRB5_LOG1(KRB5_ERR, "accept_sec_context: subkey enctype = %d proto = %d",
922 ctx->subkey->enctype, ctx->proto);
923
924 ctx->endtime = ticket->enc_part2->times.endtime;
925 ctx->krb_flags = ticket->enc_part2->flags;
926
927 krb5_free_ticket(context, ticket); /* Done with ticket */
928
929 {
930 krb5_ui_4 seq_temp;
931 krb5_auth_con_getremoteseqnumber(context, auth_context,
932 (krb5_int32 *)&seq_temp);
933 ctx->seq_recv = seq_temp;
934 }
935
936 if ((code = krb5_timeofday(context, &now))) {
937 major_status = GSS_S_FAILURE;
938 goto fail;
939 }
940
941 if (ctx->endtime < now) {
942 code = 0;
943 major_status = GSS_S_CREDENTIALS_EXPIRED;
944 goto fail;
945 }
946
947 g_order_init(&(ctx->seqstate), ctx->seq_recv,
948 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
949 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
950
951 /* at this point, the entire context structure is filled in,
952 so it can be released. */
953
954 /* generate an AP_REP if necessary */
955
956 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
957 unsigned char * ptr3;
958 krb5_ui_4 seq_temp;
959 int cfx_generate_subkey;
960
961 if (ctx->proto == 1)
962 cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
963 else
964 cfx_generate_subkey = 0;
965
966 if (cfx_generate_subkey) {
967 krb5_int32 acflags;
968 code = krb5_auth_con_getflags(context, auth_context, &acflags);
969 if (code == 0) {
970 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
971 code = krb5_auth_con_setflags(context, auth_context, acflags);
972 }
973 if (code) {
974 major_status = GSS_S_FAILURE;
975 goto fail;
976 }
977 }
978
979 if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
980 major_status = GSS_S_FAILURE;
981 goto fail;
982 }
983
984 krb5_auth_con_getlocalseqnumber(context, auth_context,
985 (krb5_int32 *)&seq_temp);
986 ctx->seq_send = seq_temp & 0xffffffffL;
987
988 if (cfx_generate_subkey) {
989 /* Get the new acceptor subkey. With the code above, there
990 should always be one if we make it to this point. */
991 code = krb5_auth_con_getsendsubkey(context, auth_context,
992 &ctx->acceptor_subkey);
993 if (code != 0) {
994 major_status = GSS_S_FAILURE;
995 goto fail;
996 }
997 code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
998 ctx->acceptor_subkey->enctype,
999 &ctx->acceptor_subkey_cksumtype);
1000 if (code) {
1001 major_status = GSS_S_FAILURE;
1002 goto fail;
1003 }
1004 ctx->have_acceptor_subkey = 1;
1005 }
1006
1007 /* the reply token hasn't been sent yet, but that's ok. */
1008 ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1009 ctx->established = 1;
1010
1011 token.length = g_token_size(mech_used, ap_rep.length);
1012
1013 if ((token.value = (unsigned char *) xmalloc(token.length))
1014 == NULL) {
1015 major_status = GSS_S_FAILURE;
1016 code = ENOMEM;
1017 goto fail;
1018 }
1019 ptr3 = token.value;
1020 g_make_token_header(mech_used, ap_rep.length,
1021 &ptr3, KG_TOK_CTX_AP_REP);
1022
1023 TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1024
1025 ctx->established = 1;
1026
1027 } else {
1028 token.length = 0;
1029 token.value = NULL;
1030 ctx->seq_send = ctx->seq_recv;
1031
1032 ctx->established = 1;
1033 }
1034
1035 /* set the return arguments */
1036
1037 if (src_name) {
1038 if ((code = krb5_copy_principal(context, ctx->there, &name))) {
1039 major_status = GSS_S_FAILURE;
1040 goto fail;
1041 }
1042 /* intern the src_name */
1043 if (! kg_save_name((gss_name_t) name)) {
1044 code = G_VALIDATE_FAILED;
1045 major_status = GSS_S_FAILURE;
1046 goto fail;
1047 }
1048 }
1049
1050 if (mech_type)
1051 *mech_type = (gss_OID) mech_used;
1052
1053 if (time_rec)
1054 *time_rec = ctx->endtime - now;
1055
1056 if (ret_flags)
1057 *ret_flags = ctx->gss_flags;
1058
1059 *context_handle = (gss_ctx_id_t)ctx;
1060 *output_token = token;
1061
1062 if (src_name)
1063 *src_name = (gss_name_t) name;
1064
1065 if (delegated_cred_handle && deleg_cred) {
1066 if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1067 /* Solaris Kerberos */
1068 KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1069 "kg_save_cred_id() error");
1070 major_status = GSS_S_FAILURE;
1071 code = (OM_uint32) G_VALIDATE_FAILED;
1072 goto fail;
1073 }
1074
1075 *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1076 }
1077
1078 /* finally! */
1079
1080 *minor_status = 0;
1081 major_status = GSS_S_COMPLETE;
1082
1083 fail:
1084 if (authdat)
1085 krb5_free_authenticator(context, authdat);
1086 /* The ctx structure has the handle of the auth_context */
1087 if (auth_context && !ctx) {
1088 if (cred_rcache)
1089 (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1090
1091 krb5_auth_con_free(context, auth_context);
1092 }
1093 if (reqcksum.contents)
1094 xfree(reqcksum.contents);
1095 if (ap_rep.data)
1096 xfree(ap_rep.data);
1097
1098 if (request != NULL) {
1099 saved_ap_options = request->ap_options;
1100 krb5_free_ap_req(context, request);
1101 request = NULL;
1102 }
1103
1104 if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1105 if (!verifier_cred_handle && cred_handle) {
1106 krb5_gss_release_cred(minor_status, &cred_handle);
1107 }
1108
1109 if (ctx)
1110 ctx->k5_context = context;
1111
1112 return(major_status);
1113 }
1114
1115 /* from here on is the real "fail" code */
1116
1117 if (ctx)
1118 (void) krb5_gss_delete_sec_context(minor_status,
1119 (gss_ctx_id_t *) &ctx, NULL);
1120 if (deleg_cred) { /* free memory associated with the deleg credential */
1121 if (deleg_cred->ccache)
1122 (void)krb5_cc_close(context, deleg_cred->ccache);
1123 if (deleg_cred->princ)
1124 krb5_free_principal(context, deleg_cred->princ);
1125 xfree(deleg_cred);
1126 }
1127 if (token.value)
1128 xfree(token.value);
1129 if (name) {
1130 (void) kg_delete_name((gss_name_t) name);
1131 krb5_free_principal(context, name);
1132 }
1133
1134 *minor_status = code;
1135
1136 if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1137 gss_flags |= GSS_C_MUTUAL_FLAG;
1138
1139 if (cred
1140 && ((gss_flags & GSS_C_MUTUAL_FLAG)
1141 || (major_status == GSS_S_CONTINUE_NEEDED))) {
1142 unsigned int tmsglen;
1143 int toktype;
1144
1145 /*
1146 * The client is expecting a response, so we can send an
1147 * error token back
1148 */
1149 memset(&krb_error_data, 0, sizeof(krb_error_data));
1150
1151 code -= ERROR_TABLE_BASE_krb5;
1152 if (code < 0 || code > 128)
1153 code = 60 /* KRB_ERR_GENERIC */;
1154
1155 krb_error_data.error = code;
1156 (void) krb5_us_timeofday(context, &krb_error_data.stime,
1157 &krb_error_data.susec);
1158 krb_error_data.server = cred->princ;
1159
1160 code = krb5_mk_error(context, &krb_error_data, &scratch);
1161 if (code)
1162 goto cleanup;
1163
1164 tmsglen = scratch.length;
1165 toktype = KG_TOK_CTX_ERROR;
1166
1167 token.length = g_token_size(mech_used, tmsglen);
1168 token.value = (unsigned char *) xmalloc(token.length);
1169 if (!token.value)
1170 goto cleanup;
1171
1172 ptr = token.value;
1173 g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1174
1175 TWRITE_STR(ptr, scratch.data, scratch.length);
1176 xfree(scratch.data);
1177
1178 *output_token = token;
1179 }
1180
1181 cleanup:
1182 if (!verifier_cred_handle && cred_handle) {
1183 krb5_gss_release_cred(&t_minor_status, &cred_handle);
1184 }
1185 krb5_free_context(context);
1186
1187 /* Solaris Kerberos */
1188 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1189 "major_status = %d", major_status);
1190 return (major_status);
1191 }