1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2000, 2004, 2007, 2008 by the Massachusetts Institute of Technology.
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
26 * Copyright 1993 by OpenVision Technologies, Inc.
28 * Permission to use, copy, modify, distribute, and sell this software
29 * and its documentation for any purpose is hereby granted without fee,
30 * provided that the above copyright notice appears in all copies and
31 * that both that copyright notice and this permission notice appear in
32 * supporting documentation, and that the name of OpenVision not be used
33 * in advertising or publicity pertaining to distribution of the software
34 * without specific, written prior permission. OpenVision makes no
35 * representations about the suitability of this software for any
36 * purpose. It is provided "as is" without express or implied warranty.
38 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44 * PERFORMANCE OF THIS SOFTWARE.
48 * Copyright (C) 1998 by the FundsXpress, INC.
50 * All rights reserved.
52 * Export of this software from the United States of America may require
53 * a specific license from the United States Government. It is the
54 * responsibility of any person or organization contemplating export to
55 * obtain such a license before exporting.
57 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
58 * distribute this software and its documentation for any purpose and
59 * without fee is hereby granted, provided that the above copyright
60 * notice appear in all copies and that both that copyright notice and
61 * this permission notice appear in supporting documentation, and that
62 * the name of FundsXpress. not be used in advertising or publicity pertaining
63 * to distribution of the software without specific, written prior
64 * permission. FundsXpress makes no representations about the suitability of
65 * this software for any purpose. It is provided "as is" without express
66 * or implied warranty.
68 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
69 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
70 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
73 * Copyright (c) 2006-2008, Novell, Inc.
74 * All rights reserved.
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions are met:
79 * * Redistributions of source code must retain the above copyright notice,
80 * this list of conditions and the following disclaimer.
81 * * Redistributions in binary form must reproduce the above copyright
82 * notice, this list of conditions and the following disclaimer in the
83 * documentation and/or other materials provided with the distribution.
84 * * The copyright holder's name is not used to endorse or promote products
85 * derived from this software without specific prior written permission.
87 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
88 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
91 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
92 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
93 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
94 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
95 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
96 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
97 * POSSIBILITY OF SUCH DAMAGE.
101 #include "gssapiP_krb5.h"
108 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
110 #define CFX_ACCEPTOR_SUBKEY 1
116 create_constrained_deleg_creds(OM_uint32 *minor_status,
117 krb5_gss_cred_id_t verifier_cred_handle,
119 krb5_gss_cred_id_t *out_cred,
120 krb5_context context)
122 OM_uint32 major_status;
123 krb5_creds krb_creds;
125 krb5_error_code code;
127 assert(out_cred != NULL);
128 assert(verifier_cred_handle->usage == GSS_C_BOTH);
130 memset(&krb_creds, 0, sizeof(krb_creds));
131 krb_creds.client = ticket->enc_part2->client;
132 krb_creds.server = ticket->server;
133 krb_creds.keyblock = *(ticket->enc_part2->session);
134 krb_creds.ticket_flags = ticket->enc_part2->flags;
135 krb_creds.times = ticket->enc_part2->times;
136 krb_creds.magic = KV5M_CREDS;
137 krb_creds.authdata = NULL;
139 code = encode_krb5_ticket(ticket, &data);
141 *minor_status = code;
142 return GSS_S_FAILURE;
145 krb_creds.ticket = *data;
147 major_status = kg_compose_deleg_cred(minor_status,
148 verifier_cred_handle,
155 krb5_free_data(context, data);
160 /* Decode, decrypt and store the forwarded creds in the local ccache. */
161 static krb5_error_code
162 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
163 krb5_context context;
164 krb5_auth_context auth_context;
166 krb5_gss_cred_id_t *out_cred;
168 krb5_creds ** creds = NULL;
169 krb5_error_code retval;
170 krb5_ccache ccache = NULL;
171 krb5_gss_cred_id_t cred = NULL;
172 krb5_auth_context new_auth_ctx = NULL;
173 krb5_int32 flags_org;
175 if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
177 krb5_auth_con_setflags(context, auth_context,
181 * By the time krb5_rd_cred is called here (after krb5_rd_req has been
182 * called in krb5_gss_accept_sec_context), the "keyblock" field of
183 * auth_context contains a pointer to the session key, and the
184 * "recv_subkey" field might contain a session subkey. Either of
185 * these (the "recv_subkey" if it isn't NULL, otherwise the
186 * "keyblock") might have been used to encrypt the encrypted part of
187 * the KRB_CRED message that contains the forwarded credentials. (The
188 * Java Crypto and Security Implementation from the DSTC in Australia
189 * always uses the session key. But apparently it never negotiates a
190 * subkey, so this code works fine against a JCSI client.) Up to the
191 * present, though, GSSAPI clients linked against the MIT code (which
192 * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
193 * all -- at this level. So if the first call to krb5_rd_cred fails,
194 * we should call it a second time with another auth context freshly
195 * created by krb5_auth_con_init. All of its keyblock fields will be
196 * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
197 * unencrypted. (The MIT code doesn't actually send the KRB_CRED
198 * message in the clear -- the "authenticator" whose "checksum" ends up
199 * containing the KRB_CRED message does get encrypted.)
201 if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
202 if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
204 krb5_auth_con_setflags(context, new_auth_ctx, 0);
205 if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
210 if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
215 if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
218 if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
221 /* generate a delegated credential handle */
223 /* allocate memory for a cred_t... */
225 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
226 retval = ENOMEM; /* out of memory? */
231 memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
233 retval = k5_mutex_init(&cred->lock);
240 /* copy the client principle into it... */
242 kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
244 k5_mutex_destroy(&cred->lock);
245 retval = ENOMEM; /* out of memory? */
246 xfree(cred); /* clean up memory on failure */
251 cred->usage = GSS_C_INITIATE; /* we can't accept with this */
252 /* cred->name already set */
253 cred->keytab = NULL; /* no keytab associated with this... */
254 cred->expire = creds[0]->times.endtime; /* store the end time */
255 cred->ccache = ccache; /* the ccache containing the credential */
256 cred->destroy_ccache = 1;
257 ccache = NULL; /* cred takes ownership so don't destroy */
260 /* If there were errors, there might have been a memory leak
262 if ((retval = krb5_cc_close(context, ccache)))
267 krb5_free_tgt_creds(context, creds);
270 (void)krb5_cc_destroy(context, ccache);
273 *out_cred = cred; /* return credential */
276 krb5_auth_con_free(context, new_auth_ctx);
278 krb5_auth_con_setflags(context, auth_context, flags_org);
285 * Performs third leg of DCE authentication
288 kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
289 input_token, input_chan_bindings, src_name, mech_type,
290 output_token, ret_flags, time_rec, delegated_cred_handle)
291 OM_uint32 *minor_status;
292 gss_ctx_id_t *context_handle;
293 gss_cred_id_t verifier_cred_handle;
294 gss_buffer_t input_token;
295 gss_channel_bindings_t input_chan_bindings;
296 gss_name_t *src_name;
298 gss_buffer_t output_token;
299 OM_uint32 *ret_flags;
301 gss_cred_id_t *delegated_cred_handle;
303 krb5_error_code code;
304 krb5_gss_ctx_id_rec *ctx = 0;
306 krb5_gss_name_t name = NULL;
309 OM_uint32 major_status = GSS_S_FAILURE;
311 output_token->length = 0;
312 output_token->value = NULL;
315 *mech_type = GSS_C_NULL_OID;
316 /* return a bogus cred handle */
317 if (delegated_cred_handle)
318 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
320 ctx = (krb5_gss_ctx_id_rec *)*context_handle;
322 code = krb5_timeofday(ctx->k5_context, &now);
324 major_status = GSS_S_FAILURE;
328 ap_rep.data = input_token->value;
329 ap_rep.length = input_token->length;
331 code = krb5_rd_rep_dce(ctx->k5_context,
336 major_status = GSS_S_FAILURE;
340 ctx->established = 1;
343 code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
345 major_status = GSS_S_FAILURE;
348 *src_name = (gss_name_t) name;
352 *mech_type = ctx->mech_used;
355 *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
357 /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
360 *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
364 return GSS_S_COMPLETE;
367 /* real failure code follows */
369 (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
371 *context_handle = GSS_C_NO_CONTEXT;
372 *minor_status = code;
377 static krb5_error_code
378 kg_process_extension(krb5_context context,
379 krb5_auth_context auth_context,
382 krb5_gss_ctx_ext_t exts)
384 krb5_error_code code = 0;
386 assert(exts != NULL);
389 case KRB5_GSS_EXTS_IAKERB_FINISHED:
390 if (exts->iakerb.conv == NULL) {
391 code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
395 code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
399 code = iakerb_verify_finished(context, key, exts->iakerb.conv,
402 exts->iakerb.verified = 1;
404 krb5_k_free_key(context, key);
415 kg_accept_krb5(minor_status, context_handle,
416 verifier_cred_handle, input_token,
417 input_chan_bindings, src_name, mech_type,
418 output_token, ret_flags, time_rec,
419 delegated_cred_handle, exts)
420 OM_uint32 *minor_status;
421 gss_ctx_id_t *context_handle;
422 gss_cred_id_t verifier_cred_handle;
423 gss_buffer_t input_token;
424 gss_channel_bindings_t input_chan_bindings;
425 gss_name_t *src_name;
427 gss_buffer_t output_token;
428 OM_uint32 *ret_flags;
430 gss_cred_id_t *delegated_cred_handle;
431 krb5_gss_ctx_ext_t exts;
433 krb5_context context;
434 unsigned char *ptr, *ptr2;
438 krb5_gss_cred_id_t cred = 0;
439 krb5_data ap_rep, ap_req;
441 krb5_error_code code;
442 krb5_address addr, *paddr;
443 krb5_authenticator *authdat = 0;
444 krb5_checksum reqcksum;
445 krb5_gss_name_t name = NULL;
446 krb5_ui_4 gss_flags = 0;
447 krb5_gss_ctx_id_rec *ctx = NULL;
449 gss_buffer_desc token;
450 krb5_auth_context auth_context = NULL;
451 krb5_ticket * ticket = NULL;
454 const gss_OID_desc *mech_used = NULL;
455 OM_uint32 major_status = GSS_S_FAILURE;
456 OM_uint32 tmp_minor_status;
457 krb5_error krb_error_data;
459 gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
460 krb5_gss_cred_id_t deleg_cred = NULL;
461 krb5int_access kaccess;
464 int token_deleg_flag = 0;
465 krb5_flags ap_req_options = 0;
466 krb5_enctype negotiated_etype;
467 krb5_authdata_context ad_context = NULL;
468 krb5_principal accprinc = NULL;
469 krb5_ap_req *request = NULL;
471 code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
473 *minor_status = code;
474 return(GSS_S_FAILURE);
477 code = krb5_gss_init_context(&context);
479 *minor_status = code;
480 return GSS_S_FAILURE;
483 /* set up returns to be freeable */
486 *src_name = (gss_name_t) NULL;
487 output_token->length = 0;
488 output_token->value = NULL;
490 reqcksum.contents = 0;
495 *mech_type = GSS_C_NULL_OID;
496 /* return a bogus cred handle */
497 if (delegated_cred_handle)
498 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
500 /* handle default cred handle */
501 if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
502 major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
503 GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
504 GSS_C_ACCEPT, &defcred,
506 if (major_status != GSS_S_COMPLETE) {
507 code = *minor_status;
510 verifier_cred_handle = defcred;
513 /* Resolve any initiator state in the verifier cred and lock it. */
514 major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
516 if (GSS_ERROR(major_status)) {
517 code = *minor_status;
520 cred = (krb5_gss_cred_id_t)verifier_cred_handle;
522 /* make sure the supplied credentials are valid for accept */
524 if ((cred->usage != GSS_C_ACCEPT) &&
525 (cred->usage != GSS_C_BOTH)) {
527 major_status = GSS_S_NO_CRED;
531 /* verify the token's integrity, and leave the token in ap_req.
532 figure out which mech oid was used, and save it */
534 ptr = (unsigned char *) input_token->value;
536 if (!(code = g_verify_token_header(gss_mech_krb5,
538 &ptr, KG_TOK_CTX_AP_REQ,
539 input_token->length, 1))) {
540 mech_used = gss_mech_krb5;
541 } else if ((code == G_WRONG_MECH)
542 &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
544 &ptr, KG_TOK_CTX_AP_REQ,
545 input_token->length, 1))) {
546 mech_used = gss_mech_iakerb;
547 } else if ((code == G_WRONG_MECH)
548 &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
550 &ptr, KG_TOK_CTX_AP_REQ,
551 input_token->length, 1))) {
552 mech_used = gss_mech_krb5_wrong;
553 } else if ((code == G_WRONG_MECH) &&
554 !(code = g_verify_token_header(gss_mech_krb5_old,
556 &ptr, KG_TOK_CTX_AP_REQ,
557 input_token->length, 1))) {
559 * Previous versions of this library used the old mech_id
560 * and some broken behavior (wrong IV on checksum
561 * encryption). We support the old mech_id for
562 * compatibility, and use it to decide when to use the
565 mech_used = gss_mech_krb5_old;
566 } else if (code == G_WRONG_TOKID) {
567 major_status = GSS_S_CONTINUE_NEEDED;
568 code = KRB5KRB_AP_ERR_MSG_TYPE;
569 mech_used = gss_mech_krb5;
571 } else if (code == G_BAD_TOK_HEADER) {
572 /* DCE style not encapsulated */
573 ap_req.length = input_token->length;
574 ap_req.data = input_token->value;
575 mech_used = gss_mech_krb5;
578 major_status = GSS_S_DEFECTIVE_TOKEN;
583 TREAD_STR(sptr, ap_req.data, ap_req.length);
585 /* construct the sender_addr */
587 if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
588 (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
589 /* XXX is this right? */
590 addr.addrtype = ADDRTYPE_INET;
591 addr.length = input_chan_bindings->initiator_address.length;
592 addr.contents = input_chan_bindings->initiator_address.value;
599 /* decode the AP_REQ message */
600 code = decode_krb5_ap_req(&ap_req, &request);
602 major_status = GSS_S_FAILURE;
605 ticket = request->ticket;
607 /* decode the message */
609 if ((code = krb5_auth_con_init(context, &auth_context))) {
610 major_status = GSS_S_FAILURE;
611 save_error_info((OM_uint32)code, context);
616 if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
617 major_status = GSS_S_FAILURE;
621 if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
622 major_status = GSS_S_FAILURE;
626 /* Limit the encryption types negotiated (if requested). */
627 if (cred->req_enctypes) {
628 if ((code = krb5_auth_con_setpermetypes(context, auth_context,
629 cred->req_enctypes))) {
630 major_status = GSS_S_FAILURE;
635 if (!cred->default_identity) {
636 if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
637 major_status = GSS_S_FAILURE;
642 code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
643 cred->keytab, &ap_req_options, NULL);
645 krb5_free_principal(context, accprinc);
647 major_status = GSS_S_FAILURE;
650 krb5_auth_con_setflags(context, auth_context,
651 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
653 krb5_auth_con_getauthenticator(context, auth_context, &authdat);
656 /* make sure the necessary parts of the authdat are present */
658 if ((authdat->authenticator->subkey == NULL) ||
659 (authdat->ticket->enc_part2 == NULL)) {
661 major_status = GSS_S_FAILURE;
666 if (authdat->checksum == NULL) {
668 * Some SMB client implementations use handcrafted GSSAPI code that
669 * does not provide a checksum. MS-KILE documents that the Microsoft
670 * implementation considers a missing checksum acceptable; the server
671 * assumes all flags are unset in this case, and does not check channel
675 } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
676 /* Samba does not send 0x8003 GSS-API checksums */
681 code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
683 major_status = GSS_S_FAILURE;
690 code = krb5_k_verify_checksum(context,
692 KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
696 krb5_k_free_key(context, subkey);
697 if (code || !valid) {
698 major_status = GSS_S_BAD_SIG;
702 /* Use ap_options from the request to guess the mutual flag. */
703 gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
704 if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
705 gss_flags |= GSS_C_MUTUAL_FLAG;
709 /* stash this now, for later. */
710 code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
712 major_status = GSS_S_FAILURE;
716 /* verify that the checksum is correct */
719 The checksum may be either exactly 24 bytes, in which case
720 no options are specified, or greater than 24 bytes, in which case
721 one or more options are specified. Currently, the only valid
722 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
725 if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
726 (authdat->checksum->length < 24)) {
728 major_status = GSS_S_BAD_BINDINGS;
732 ptr = (unsigned char *) authdat->checksum->contents;
734 TREAD_INT(ptr, tmp, 0);
737 code = KG_BAD_LENGTH;
738 major_status = GSS_S_FAILURE;
743 The following section of code attempts to implement the
744 optional channel binding facility as described in RFC2743.
746 Since this facility is optional channel binding may or may
747 not have been provided by either the client or the server.
749 If the server has specified input_chan_bindings equal to
750 GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
751 the server does provide channel bindings then we compute
752 a checksum and compare against those provided by the
755 if ((code = kg_checksum_channel_bindings(context,
758 major_status = GSS_S_BAD_BINDINGS;
762 /* Always read the clients bindings - eventhough we might ignore them */
763 TREAD_STR(ptr, ptr2, reqcksum.length);
765 if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
766 if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
767 xfree(reqcksum.contents);
768 reqcksum.contents = 0;
770 major_status = GSS_S_BAD_BINDINGS;
776 xfree(reqcksum.contents);
777 reqcksum.contents = 0;
779 /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
780 * mask it out until we actually read a delegated credential. */
781 TREAD_INT(ptr, gss_flags, 0);
782 token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
783 gss_flags &= ~GSS_C_DELEG_FLAG;
785 /* if the checksum length > 24, there are options to process */
787 i = authdat->checksum->length - 24;
788 if (i && token_deleg_flag) {
790 TREAD_INT16(ptr, option_id, 0);
791 TREAD_INT16(ptr, option.length, 0);
794 if (i < option.length) {
795 code = KG_BAD_LENGTH;
796 major_status = GSS_S_FAILURE;
800 /* have to use ptr2, since option.data is wrong type and
801 macro uses ptr as both lvalue and rvalue */
803 TREAD_STR(ptr, ptr2, option.length);
804 option.data = (char *) ptr2;
808 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
809 major_status = GSS_S_FAILURE;
813 /* store the delegated credential */
815 code = rd_and_store_for_creds(context, auth_context, &option,
816 (delegated_cred_handle) ?
819 major_status = GSS_S_FAILURE;
823 gss_flags |= GSS_C_DELEG_FLAG;
825 /* ignore any additional trailing data, for now */
828 /* Process Type-Length-Data options */
830 code = KG_BAD_LENGTH;
831 major_status = GSS_S_FAILURE;
834 TREAD_INT(ptr, option_id, 1);
835 TREAD_INT(ptr, option.length, 1);
837 if (i < option.length) {
838 code = KG_BAD_LENGTH;
839 major_status = GSS_S_FAILURE;
842 TREAD_STR(ptr, ptr2, option.length);
843 option.data = (char *)ptr2;
847 code = kg_process_extension(context, auth_context,
848 option_id, &option, exts);
850 major_status = GSS_S_FAILURE;
856 if (exts->iakerb.conv && !exts->iakerb.verified) {
857 major_status = GSS_S_BAD_SIG;
861 /* only DCE_STYLE clients are allowed to send raw AP-REQs */
862 if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
863 major_status = GSS_S_DEFECTIVE_TOKEN;
867 /* create the ctx struct and start filling it in */
869 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
872 major_status = GSS_S_FAILURE;
876 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
877 ctx->magic = KG_CONTEXT;
878 ctx->mech_used = (gss_OID) mech_used;
879 ctx->auth_context = auth_context;
881 ctx->gss_flags = (GSS_C_TRANS_FLAG |
882 ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
883 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
884 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
885 GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
886 GSS_C_EXTENDED_ERROR_FLAG)));
888 ctx->cred_rcache = cred_rcache;
890 /* XXX move this into gss_name_t */
891 if ( (code = krb5_merge_authdata(context,
892 ticket->enc_part2->authorization_data,
893 authdat->authorization_data,
895 major_status = GSS_S_FAILURE;
898 if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
900 major_status = GSS_S_FAILURE;
903 if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
905 major_status = GSS_S_FAILURE;
908 if ((code = kg_init_name(context, authdat->client, NULL, NULL,
909 ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
910 major_status = GSS_S_FAILURE;
913 /* Now owned by ctx->there */
914 authdat->client = NULL;
915 krb5_auth_con_set_authdata_context(context, auth_context, NULL);
917 if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
919 major_status = GSS_S_FAILURE;
923 /* use the session key if the subkey isn't present */
925 if (ctx->subkey == NULL) {
926 if ((code = krb5_auth_con_getkey_k(context, auth_context,
928 major_status = GSS_S_FAILURE;
933 if (ctx->subkey == NULL) {
934 /* this isn't a very good error, but it's not clear to me this
935 can actually happen */
936 major_status = GSS_S_FAILURE;
937 code = KRB5KDC_ERR_NULL_KEY;
943 ctx->have_acceptor_subkey = 0;
944 /* DCE_STYLE implies acceptor_subkey */
945 if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
946 code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
948 major_status = GSS_S_FAILURE;
952 ctx->krb_times = ticket->enc_part2->times; /* struct copy */
953 ctx->krb_flags = ticket->enc_part2->flags;
955 if (delegated_cred_handle != NULL &&
956 deleg_cred == NULL && /* no unconstrained delegation */
957 cred->usage == GSS_C_BOTH &&
958 (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
960 * Now, we always fabricate a delegated credentials handle
961 * containing the service ticket to ourselves, which can be
962 * used for S4U2Proxy.
964 major_status = create_constrained_deleg_creds(minor_status, cred,
967 if (GSS_ERROR(major_status))
969 ctx->gss_flags |= GSS_C_DELEG_FLAG;
974 krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
975 ctx->seq_recv = seq_temp;
978 if ((code = krb5_timeofday(context, &now))) {
979 major_status = GSS_S_FAILURE;
983 code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
984 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
985 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
988 major_status = GSS_S_FAILURE;
992 /* DCE_STYLE implies mutual authentication */
993 if (ctx->gss_flags & GSS_C_DCE_STYLE)
994 ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
996 /* at this point, the entire context structure is filled in,
997 so it can be released. */
999 /* generate an AP_REP if necessary */
1001 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1002 unsigned char * ptr3;
1003 krb5_int32 seq_temp;
1004 int cfx_generate_subkey;
1007 * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
1008 * because pre-CFX tokens do not indicate which key to use. (Note that
1009 * DCE_STYLE implies that we will use a subkey.)
1011 if (ctx->proto == 0 &&
1012 (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
1013 (ap_req_options & AP_OPTS_USE_SUBKEY)) {
1014 code = (*kaccess.auth_con_get_subkey_enctype)(context,
1018 major_status = GSS_S_FAILURE;
1022 switch (negotiated_etype) {
1023 case ENCTYPE_DES_CBC_MD5:
1024 case ENCTYPE_DES_CBC_MD4:
1025 case ENCTYPE_DES_CBC_CRC:
1026 case ENCTYPE_DES3_CBC_SHA1:
1027 case ENCTYPE_ARCFOUR_HMAC:
1028 case ENCTYPE_ARCFOUR_HMAC_EXP:
1029 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
1030 * enctype, even though RFC 4757 treats it as one. */
1031 ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
1036 if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
1037 (ap_req_options & AP_OPTS_USE_SUBKEY))
1038 cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1040 cfx_generate_subkey = 0;
1042 if (cfx_generate_subkey) {
1044 code = krb5_auth_con_getflags(context, auth_context, &acflags);
1046 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1047 code = krb5_auth_con_setflags(context, auth_context, acflags);
1050 major_status = GSS_S_FAILURE;
1055 if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1056 major_status = GSS_S_FAILURE;
1060 krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
1061 ctx->seq_send = seq_temp & 0xffffffffL;
1063 if (cfx_generate_subkey) {
1064 /* Get the new acceptor subkey. With the code above, there
1065 should always be one if we make it to this point. */
1066 code = krb5_auth_con_getsendsubkey_k(context, auth_context,
1067 &ctx->acceptor_subkey);
1069 major_status = GSS_S_FAILURE;
1072 ctx->have_acceptor_subkey = 1;
1074 code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
1075 &ctx->acceptor_subkey_cksumtype);
1077 major_status = GSS_S_FAILURE;
1082 /* the reply token hasn't been sent yet, but that's ok. */
1083 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
1084 assert(ctx->have_acceptor_subkey);
1086 /* in order to force acceptor subkey to be used, don't set PROT_READY */
1088 /* Raw AP-REP is returned */
1089 code = data_to_gss(&ap_rep, output_token);
1092 major_status = GSS_S_FAILURE;
1096 ctx->established = 0;
1098 *context_handle = (gss_ctx_id_t)ctx;
1100 major_status = GSS_S_CONTINUE_NEEDED;
1102 /* Only last leg should set return arguments */
1105 ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1107 ctx->established = 1;
1109 token.length = g_token_size(mech_used, ap_rep.length);
1111 if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
1113 major_status = GSS_S_FAILURE;
1118 g_make_token_header(mech_used, ap_rep.length,
1119 &ptr3, KG_TOK_CTX_AP_REP);
1121 TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1123 ctx->established = 1;
1128 ctx->seq_send = ctx->seq_recv;
1130 ctx->established = 1;
1133 /* set the return arguments */
1136 code = kg_duplicate_name(context, ctx->there, &name);
1138 major_status = GSS_S_FAILURE;
1144 *mech_type = (gss_OID) mech_used;
1146 /* Add the maximum allowable clock skew as a grace period for context
1147 * expiration, just as we do for the ticket. */
1149 *time_rec = ctx->krb_times.endtime + context->clockskew - now;
1152 *ret_flags = ctx->gss_flags;
1154 *context_handle = (gss_ctx_id_t)ctx;
1155 *output_token = token;
1158 *src_name = (gss_name_t) name;
1160 if (delegated_cred_handle)
1161 *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1166 major_status = GSS_S_COMPLETE;
1170 krb5_free_authenticator(context, authdat);
1171 /* The ctx structure has the handle of the auth_context */
1172 if (auth_context && !ctx) {
1174 (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1176 krb5_auth_con_free(context, auth_context);
1178 if (reqcksum.contents)
1179 xfree(reqcksum.contents);
1181 krb5_free_data_contents(context, &ap_rep);
1182 if (major_status == GSS_S_COMPLETE ||
1183 (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
1184 ctx->k5_context = context;
1189 /* from here on is the real "fail" code */
1192 (void) krb5_gss_delete_sec_context(&tmp_minor_status,
1193 (gss_ctx_id_t *) &ctx, NULL);
1194 if (deleg_cred) { /* free memory associated with the deleg credential */
1195 if (deleg_cred->ccache)
1196 (void)krb5_cc_close(context, deleg_cred->ccache);
1197 if (deleg_cred->name)
1198 kg_release_name(context, &deleg_cred->name);
1204 (void) kg_release_name(context, &name);
1207 *minor_status = code;
1209 /* We may have failed before being able to read the GSS flags from the
1210 * authenticator, so also check the request AP options. */
1211 if (cred != NULL && request != NULL &&
1212 ((gss_flags & GSS_C_MUTUAL_FLAG) ||
1213 (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
1214 major_status == GSS_S_CONTINUE_NEEDED)) {
1215 unsigned int tmsglen;
1219 * The client is expecting a response, so we can send an
1222 memset(&krb_error_data, 0, sizeof(krb_error_data));
1224 code -= ERROR_TABLE_BASE_krb5;
1225 if (code < 0 || code > KRB_ERR_MAX)
1226 code = 60 /* KRB_ERR_GENERIC */;
1228 krb_error_data.error = code;
1229 (void) krb5_us_timeofday(context, &krb_error_data.stime,
1230 &krb_error_data.susec);
1232 krb_error_data.server = ticket->server;
1233 code = krb5_mk_error(context, &krb_error_data, &scratch);
1237 tmsglen = scratch.length;
1238 toktype = KG_TOK_CTX_ERROR;
1240 token.length = g_token_size(mech_used, tmsglen);
1241 token.value = gssalloc_malloc(token.length);
1246 g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1248 TWRITE_STR(ptr, scratch.data, scratch.length);
1249 krb5_free_data_contents(context, &scratch);
1251 *output_token = token;
1255 krb5_free_ap_req(context, request);
1257 k5_mutex_unlock(&cred->lock);
1259 krb5_gss_release_cred(&tmp_minor_status, &defcred);
1261 if (major_status && *minor_status)
1262 save_error_info(*minor_status, context);
1263 krb5_free_context(context);
1265 return (major_status);
1267 #endif /* LEAN_CLIENT */
1269 OM_uint32 KRB5_CALLCONV
1270 krb5_gss_accept_sec_context_ext(
1271 OM_uint32 *minor_status,
1272 gss_ctx_id_t *context_handle,
1273 gss_cred_id_t verifier_cred_handle,
1274 gss_buffer_t input_token,
1275 gss_channel_bindings_t input_chan_bindings,
1276 gss_name_t *src_name,
1278 gss_buffer_t output_token,
1279 OM_uint32 *ret_flags,
1280 OM_uint32 *time_rec,
1281 gss_cred_id_t *delegated_cred_handle,
1282 krb5_gss_ctx_ext_t exts)
1284 krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
1287 * Context handle must be unspecified. Actually, it must be
1288 * non-established, but currently, accept_sec_context never returns
1289 * a non-established context handle.
1293 if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
1294 return kg_accept_dce(minor_status, context_handle,
1295 verifier_cred_handle, input_token,
1296 input_chan_bindings, src_name, mech_type,
1297 output_token, ret_flags, time_rec,
1298 delegated_cred_handle);
1300 *minor_status = EINVAL;
1301 save_error_string(EINVAL, "accept_sec_context called with existing context handle");
1302 return GSS_S_FAILURE;
1306 return kg_accept_krb5(minor_status, context_handle,
1307 verifier_cred_handle, input_token,
1308 input_chan_bindings, src_name, mech_type,
1309 output_token, ret_flags, time_rec,
1310 delegated_cred_handle, exts);
1313 OM_uint32 KRB5_CALLCONV
1314 krb5_gss_accept_sec_context(minor_status, context_handle,
1315 verifier_cred_handle, input_token,
1316 input_chan_bindings, src_name, mech_type,
1317 output_token, ret_flags, time_rec,
1318 delegated_cred_handle)
1319 OM_uint32 *minor_status;
1320 gss_ctx_id_t *context_handle;
1321 gss_cred_id_t verifier_cred_handle;
1322 gss_buffer_t input_token;
1323 gss_channel_bindings_t input_chan_bindings;
1324 gss_name_t *src_name;
1326 gss_buffer_t output_token;
1327 OM_uint32 *ret_flags;
1328 OM_uint32 *time_rec;
1329 gss_cred_id_t *delegated_cred_handle;
1331 krb5_gss_ctx_ext_rec exts;
1333 memset(&exts, 0, sizeof(exts));
1335 return krb5_gss_accept_sec_context_ext(minor_status,
1337 verifier_cred_handle,
1339 input_chan_bindings,
1345 delegated_cred_handle,