1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2000, 2002, 2003, 2007, 2008 by the Massachusetts Institute of
4 * Technology. All Rights Reserved.
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"
112 /* XXX This is for debugging only!!! Should become a real bitfield
114 int krb5_gss_dbg_client_expcreds = 0;
117 * Common code which fetches the correct krb5 credentials from the
120 static krb5_error_code get_credentials(context, cred, server, now,
122 krb5_context context;
123 krb5_gss_cred_id_t cred;
124 krb5_gss_name_t server;
126 krb5_timestamp endtime;
127 krb5_creds **out_creds;
129 krb5_error_code code;
130 krb5_creds in_creds, evidence_creds, *result_creds = NULL;
131 krb5_flags flags = 0;
135 k5_mutex_assert_locked(&cred->lock);
136 memset(&in_creds, 0, sizeof(krb5_creds));
137 memset(&evidence_creds, 0, sizeof(krb5_creds));
138 in_creds.client = in_creds.server = NULL;
140 assert(cred->name != NULL);
143 * Do constrained delegation if we have proxy credentials and
144 * we're not trying to get a ticket to ourselves (in which case
145 * we can just use the S4U2Self or evidence ticket directly).
147 if (cred->impersonator &&
148 !krb5_principal_compare(context, cred->impersonator, server->princ)) {
151 flags |= KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
153 memset(&mcreds, 0, sizeof(mcreds));
155 mcreds.magic = KV5M_CREDS;
156 mcreds.server = cred->impersonator;
157 mcreds.client = cred->name->princ;
159 code = krb5_cc_retrieve_cred(context, cred->ccache,
160 KRB5_TC_MATCH_AUTHDATA, &mcreds,
165 assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
167 in_creds.client = cred->impersonator;
168 in_creds.second_ticket = evidence_creds.ticket;
170 in_creds.client = cred->name->princ;
173 in_creds.server = server->princ;
174 in_creds.times.endtime = endtime;
175 in_creds.authdata = NULL;
176 in_creds.keyblock.enctype = 0;
179 * cred->name is immutable, so there is no need to acquire
182 if (cred->name->ad_context != NULL) {
183 code = krb5_authdata_export_authdata(context,
184 cred->name->ad_context,
191 /* Don't go out over the network if we used IAKERB */
192 if (cred->iakerb_mech)
193 flags |= KRB5_GC_CACHED;
195 code = krb5_get_credentials(context, flags, cred->ccache,
196 &in_creds, &result_creds);
197 if (code == KRB5_CC_NOTFOUND && cred->password.data != NULL &&
198 !cred->iakerb_mech) {
199 krb5_creds tgt_creds;
201 memset(&tgt_creds, 0, sizeof(tgt_creds));
203 /* No TGT in the ccache, but we can get one with the password. */
204 code = krb5_get_init_creds_password(context, &tgt_creds,
212 code = krb5_cc_store_cred(context, cred->ccache, &tgt_creds);
214 krb5_free_cred_contents(context, &tgt_creds);
217 cred->tgt_expire = tgt_creds.times.endtime;
218 krb5_free_cred_contents(context, &tgt_creds);
220 code = krb5_get_credentials(context, flags, cred->ccache,
221 &in_creds, &result_creds);
226 if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
227 if (!krb5_principal_compare(context, cred->name->princ,
228 result_creds->client)) {
229 /* server did not support constrained delegation */
230 code = KRB5_KDCREP_MODIFIED;
236 * Enforce a stricter limit (without timeskew forgiveness at the
237 * boundaries) because accept_sec_context code is also similarly
240 if (!krb5_gss_dbg_client_expcreds && result_creds->times.endtime < now) {
241 code = KRB5KRB_AP_ERR_TKT_EXPIRED;
245 *out_creds = result_creds;
249 krb5_free_authdata(context, in_creds.authdata);
250 krb5_free_cred_contents(context, &evidence_creds);
251 krb5_free_creds(context, result_creds);
255 struct gss_checksum_data {
256 krb5_gss_ctx_id_rec *ctx;
257 krb5_gss_cred_id_t cred;
259 krb5_data checksum_data;
260 krb5_gss_ctx_ext_t exts;
264 #include "../../krb5/krb/auth_con.h"
266 static krb5_error_code KRB5_CALLCONV
267 make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
268 void *cksum_data, krb5_data **out)
270 krb5_error_code code;
271 krb5_int32 con_flags;
273 struct gss_checksum_data *data = cksum_data;
276 krb5_data *finished = NULL;
277 krb5_key send_subkey;
279 data->checksum_data.data = 0;
281 /* build the checksum field */
283 if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
284 /* first get KRB_CRED message, so we know its length */
286 /* clear the time check flag that was set in krb5_auth_con_init() */
287 krb5_auth_con_getflags(context, auth_context, &con_flags);
288 krb5_auth_con_setflags(context, auth_context,
289 con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
291 assert(data->cred->name != NULL);
294 * RFC 4121 4.1.1 specifies forwarded credentials must be encrypted in
295 * the session key, but krb5_fwd_tgt_creds will use the send subkey if
296 * it's set in the auth context. Suppress the send subkey
299 krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
300 krb5_auth_con_setsendsubkey_k(context, auth_context, NULL);
302 code = krb5_fwd_tgt_creds(context, auth_context, 0,
303 data->cred->name->princ, data->ctx->there->princ,
304 data->cred->ccache, 1,
307 /* Turn KRB5_AUTH_CONTEXT_DO_TIME back on and reset the send subkey. */
308 krb5_auth_con_setflags(context, auth_context, con_flags);
309 krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey);
310 krb5_k_free_key(context, send_subkey);
313 /* don't fail here; just don't accept/do the delegation
315 data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG |
316 GSS_C_DELEG_POLICY_FLAG);
318 data->checksum_data.length = 24;
320 if (credmsg.length+28 > KRB5_INT16_MAX) {
321 code = KRB5KRB_ERR_FIELD_TOOLONG;
325 data->checksum_data.length = 28+credmsg.length;
328 data->checksum_data.length = 24;
331 if (data->ctx->auth_context->keyblock != NULL
332 && data->ctx->auth_context->keyblock->enctype == 18) {
333 srand(time(0) ^ getpid());
334 /* Our ftp client code stupidly assumes a base64-encoded
335 version of the token will fit in 10K, so don't make this
337 junk = rand() & 0xff;
344 assert(data->exts != NULL);
346 if (data->exts->iakerb.conv) {
349 code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
353 code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
356 krb5_k_free_key(context, key);
360 krb5_k_free_key(context, key);
361 data->checksum_data.length += 8 + finished->length;
364 data->checksum_data.length += junk;
366 /* now allocate a buffer to hold the checksum data and
367 (maybe) KRB_CRED msg */
369 if ((data->checksum_data.data =
370 (char *) xmalloc(data->checksum_data.length)) == NULL) {
375 ptr = (unsigned char *)data->checksum_data.data;
377 TWRITE_INT(ptr, data->md5.length, 0);
378 TWRITE_STR(ptr, data->md5.contents, data->md5.length);
379 TWRITE_INT(ptr, data->ctx->gss_flags, 0);
381 /* done with this, free it */
382 xfree(data->md5.contents);
385 TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
386 TWRITE_INT16(ptr, credmsg.length, 0);
387 TWRITE_STR(ptr, credmsg.data, credmsg.length);
389 if (data->exts->iakerb.conv) {
390 TWRITE_INT(ptr, KRB5_GSS_EXTS_IAKERB_FINISHED, 1);
391 TWRITE_INT(ptr, finished->length, 1);
392 TWRITE_STR(ptr, finished->data, finished->length);
395 memset(ptr, 'i', junk);
396 *out = &data->checksum_data;
399 krb5_free_data_contents(context, &credmsg);
400 krb5_free_data(context, finished);
404 static krb5_error_code
405 make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
406 chan_bindings, mech_type, token, exts)
407 krb5_context context;
408 krb5_gss_ctx_id_rec *ctx;
409 krb5_gss_cred_id_t cred;
411 krb5_authdata_context ad_context;
412 gss_channel_bindings_t chan_bindings;
415 krb5_gss_ctx_ext_t exts;
417 krb5_flags mk_req_flags = 0;
418 krb5_error_code code;
419 struct gss_checksum_data cksum_struct;
426 k5_mutex_assert_locked(&cred->lock);
429 /* compute the hash of the channel bindings */
431 if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
434 krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
436 cksum_struct.md5 = md5;
437 cksum_struct.ctx = ctx;
438 cksum_struct.cred = cred;
439 cksum_struct.checksum_data.data = NULL;
440 cksum_struct.exts = exts;
441 krb5_auth_con_set_checksum_func(context, ctx->auth_context,
442 make_gss_checksum, &cksum_struct);
444 /* call mk_req. subkey and ap_req need to be used or destroyed */
446 mk_req_flags = AP_OPTS_USE_SUBKEY;
448 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
449 mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION;
451 krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context);
452 code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
453 NULL, k_cred, &ap_req);
454 krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL);
455 krb5_free_data_contents(context, &cksum_struct.checksum_data);
459 /* store the interesting stuff from creds and authent */
460 ctx->krb_times = k_cred->times;
461 ctx->krb_flags = k_cred->ticket_flags;
463 /* build up the token */
464 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
466 * For DCE RPC, do not encapsulate the AP-REQ in the
467 * typical GSS wrapping.
469 code = data_to_gss(&ap_req, token);
473 /* allocate space for the token */
474 tlen = g_token_size((gss_OID) mech_type, ap_req.length);
476 if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL) {
481 /* fill in the buffer */
484 g_make_token_header(mech_type, ap_req.length,
485 &ptr, KG_TOK_CTX_AP_REQ);
487 TWRITE_STR(ptr, ap_req.data, ap_req.length);
491 token->length = tlen;
492 token->value = (void *) t;
499 krb5_free_data_contents(context, &ap_req);
507 * Do the grunt work of setting up a new context.
511 OM_uint32 *minor_status,
512 krb5_gss_cred_id_t cred,
513 gss_ctx_id_t *context_handle,
514 gss_name_t target_name,
518 gss_channel_bindings_t input_chan_bindings,
519 gss_buffer_t input_token,
520 gss_OID *actual_mech_type,
521 gss_buffer_t output_token,
522 OM_uint32 *ret_flags,
524 krb5_context context,
525 krb5_gss_ctx_ext_t exts)
527 OM_uint32 major_status;
528 krb5_error_code code;
529 krb5_creds *k_cred = NULL;
530 krb5_gss_ctx_id_rec *ctx, *ctx_free;
532 gss_buffer_desc token;
533 krb5_keyblock *keyblock;
535 k5_mutex_assert_locked(&cred->lock);
536 major_status = GSS_S_FAILURE;
540 /* make sure the cred is usable for init */
542 if ((cred->usage != GSS_C_INITIATE) &&
543 (cred->usage != GSS_C_BOTH)) {
545 return(GSS_S_NO_CRED);
548 /* complain if the input token is non-null */
550 if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
552 return(GSS_S_DEFECTIVE_TOKEN);
557 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
559 *minor_status = ENOMEM;
560 return(GSS_S_FAILURE);
563 /* fill in the ctx */
564 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
565 ctx->magic = KG_CONTEXT;
567 if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
569 krb5_auth_con_setflags(context, ctx->auth_context,
570 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
572 /* limit the encryption types negotiated (if requested) */
573 if (cred->req_enctypes) {
574 if ((code = krb5_set_default_tgs_enctypes(context,
575 cred->req_enctypes))) {
581 ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
583 ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
584 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
585 GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
586 GSS_C_EXTENDED_ERROR_FLAG)));
588 ctx->big_endian = 0; /* all initiators do little-endian, as per spec */
591 if (req_flags & GSS_C_DCE_STYLE)
592 ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
594 if ((code = krb5_timeofday(context, &now)))
597 if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
598 ctx->krb_times.endtime = 0;
600 ctx->krb_times.endtime = now + time_req;
603 if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
606 if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name,
610 code = get_credentials(context, cred, ctx->there, now,
611 ctx->krb_times.endtime, &k_cred);
615 ctx->krb_times = k_cred->times;
618 * GSS_C_DELEG_POLICY_FLAG means to delegate only if the
619 * ok-as-delegate ticket flag is set.
621 if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
622 && (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE))
623 ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
625 if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
627 code = *minor_status;
631 * Now try to make it static if at all possible....
633 ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
638 if ((code = make_ap_req_v1(context, ctx,
639 cred, k_cred, ctx->here->ad_context,
641 mech_type, &token, exts))) {
642 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
643 (code == KG_EMPTY_CCACHE))
644 major_status = GSS_S_NO_CRED;
645 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
646 major_status = GSS_S_CREDENTIALS_EXPIRED;
650 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
651 ctx->seq_send = seq_temp;
652 code = krb5_auth_con_getsendsubkey(context, ctx->auth_context,
656 code = krb5_k_create_key(context, keyblock, &ctx->subkey);
657 krb5_free_keyblock(context, keyblock);
664 ctx->have_acceptor_subkey = 0;
665 code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
669 /* compute time_rec */
671 if ((code = krb5_timeofday(context, &now)))
673 *time_rec = ctx->krb_times.endtime - now;
676 /* set the other returns */
677 *output_token = token;
680 *ret_flags = ctx->gss_flags;
682 if (actual_mech_type)
683 *actual_mech_type = mech_type;
685 /* return successfully */
687 *context_handle = (gss_ctx_id_t) ctx;
689 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
690 ctx->established = 0;
691 major_status = GSS_S_CONTINUE_NEEDED;
693 ctx->seq_recv = ctx->seq_send;
694 g_order_init(&(ctx->seqstate), ctx->seq_recv,
695 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
696 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
697 ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
698 ctx->established = 1;
699 major_status = GSS_S_COMPLETE;
703 krb5_free_creds(context, k_cred);
705 if (ctx_free->auth_context)
706 krb5_auth_con_free(context, ctx_free->auth_context);
708 kg_release_name(context, &ctx_free->here);
710 kg_release_name(context, &ctx_free->there);
711 if (ctx_free->subkey)
712 krb5_k_free_key(context, ctx_free->subkey);
716 *minor_status = code;
717 return (major_status);
723 * Handle the reply from the acceptor, if we're doing mutual auth.
727 OM_uint32 *minor_status,
728 gss_ctx_id_t *context_handle,
729 gss_name_t target_name,
733 gss_channel_bindings_t input_chan_bindings,
734 gss_buffer_t input_token,
735 gss_OID *actual_mech_type,
736 gss_buffer_t output_token,
737 OM_uint32 *ret_flags,
739 krb5_context context)
741 OM_uint32 major_status;
745 krb5_ap_rep_enc_part *ap_rep_data;
747 krb5_gss_ctx_id_rec *ctx;
748 krb5_error *krb_error;
749 krb5_error_code code;
750 krb5int_access kaccess;
752 major_status = GSS_S_FAILURE;
754 code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
758 ctx = (krb5_gss_ctx_id_t) *context_handle;
760 /* make sure the context is non-established, and that certain
761 arguments are unchanged */
763 if ((ctx->established) ||
764 ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
765 code = KG_CONTEXT_ESTABLISHED;
769 if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) {
770 (void)krb5_gss_delete_sec_context(minor_status,
771 context_handle, NULL);
773 major_status = GSS_S_BAD_NAME;
777 /* verify the token and leave the AP_REP message in ap_rep */
779 if (input_token == GSS_C_NO_BUFFER) {
780 (void)krb5_gss_delete_sec_context(minor_status,
781 context_handle, NULL);
783 major_status = GSS_S_DEFECTIVE_TOKEN;
787 ptr = (unsigned char *) input_token->value;
789 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
791 ap_rep.length = input_token->length;
792 ap_rep.data = (char *)input_token->value;
793 } else if (g_verify_token_header(ctx->mech_used,
795 &ptr, KG_TOK_CTX_AP_REP,
796 input_token->length, 1)) {
797 if (g_verify_token_header((gss_OID) ctx->mech_used,
799 &ptr, KG_TOK_CTX_ERROR,
800 input_token->length, 1) == 0) {
802 /* Handle a KRB_ERROR message from the server */
804 sptr = (char *) ptr; /* PC compiler bug */
805 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
807 code = krb5_rd_error(context, &ap_rep, &krb_error);
810 if (krb_error->error)
811 code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5;
814 krb5_free_error(context, krb_error);
818 return(GSS_S_DEFECTIVE_TOKEN);
822 sptr = (char *) ptr; /* PC compiler bug */
823 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
825 /* decode the ap_rep */
826 if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
829 * XXX A hack for backwards compatiblity.
830 * To be removed in 1999 -- proven
832 krb5_auth_con_setuseruserkey(context, ctx->auth_context,
833 &ctx->subkey->keyblock);
834 if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
839 /* store away the sequence number */
840 ctx->seq_recv = ap_rep_data->seq_number;
841 g_order_init(&(ctx->seqstate), ctx->seq_recv,
842 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
843 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
845 if (ap_rep_data->subkey != NULL &&
846 (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
847 ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) {
848 /* Keep acceptor's subkey. */
849 ctx->have_acceptor_subkey = 1;
850 code = krb5_k_create_key(context, ap_rep_data->subkey,
851 &ctx->acceptor_subkey);
853 krb5_free_ap_rep_enc_part(context, ap_rep_data);
856 code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
857 &ctx->acceptor_subkey_cksumtype);
859 krb5_free_ap_rep_enc_part(context, ap_rep_data);
863 /* free the ap_rep_data */
864 krb5_free_ap_rep_enc_part(context, ap_rep_data);
866 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
869 code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf);
873 code = data_to_gss(&outbuf, output_token);
878 /* set established */
879 ctx->established = 1;
884 if ((code = krb5_timeofday(context, &now)))
886 *time_rec = ctx->krb_times.endtime - now;
890 *ret_flags = ctx->gss_flags;
892 if (actual_mech_type)
893 *actual_mech_type = mech_type;
898 return GSS_S_COMPLETE;
901 (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
903 *minor_status = code;
904 return (major_status);
908 krb5_gss_init_sec_context_ext(
909 OM_uint32 *minor_status,
910 gss_cred_id_t claimant_cred_handle,
911 gss_ctx_id_t *context_handle,
912 gss_name_t target_name,
916 gss_channel_bindings_t input_chan_bindings,
917 gss_buffer_t input_token,
918 gss_OID *actual_mech_type,
919 gss_buffer_t output_token,
920 OM_uint32 *ret_flags,
922 krb5_gss_ctx_ext_t exts)
924 krb5_context context;
925 gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
926 krb5_gss_cred_id_t cred;
927 krb5_error_code kerr;
928 OM_uint32 major_status;
929 OM_uint32 tmp_min_stat;
931 if (*context_handle == GSS_C_NO_CONTEXT) {
932 kerr = krb5_gss_init_context(&context);
934 *minor_status = kerr;
935 return GSS_S_FAILURE;
937 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
938 save_error_info(*minor_status, context);
939 krb5_free_context(context);
940 return GSS_S_FAILURE;
943 context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
946 /* set up return values so they can be "freed" successfully */
948 major_status = GSS_S_FAILURE; /* Default major code */
949 output_token->length = 0;
950 output_token->value = NULL;
951 if (actual_mech_type)
952 *actual_mech_type = NULL;
954 /* verify the credential, or use the default */
956 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
957 major_status = kg_get_defcred(minor_status, &defcred);
958 if (major_status && GSS_ERROR(major_status)) {
959 if (*context_handle == GSS_C_NO_CONTEXT)
960 krb5_free_context(context);
961 return(major_status);
963 claimant_cred_handle = defcred;
966 major_status = kg_cred_resolve(minor_status, context, claimant_cred_handle,
968 if (GSS_ERROR(major_status)) {
969 save_error_info(*minor_status, context);
970 krb5_gss_release_cred(&tmp_min_stat, &defcred);
971 if (*context_handle == GSS_C_NO_CONTEXT)
972 krb5_free_context(context);
973 return(major_status);
975 cred = (krb5_gss_cred_id_t)claimant_cred_handle;
977 /* verify the mech_type */
979 if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) {
980 mech_type = (gss_OID) gss_mech_krb5;
981 } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
982 mech_type = (gss_OID) gss_mech_krb5_old;
983 } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
984 mech_type = (gss_OID) gss_mech_krb5_wrong;
985 } else if (g_OID_equal(mech_type, gss_mech_iakerb)) {
986 mech_type = (gss_OID) gss_mech_iakerb;
988 k5_mutex_unlock(&cred->lock);
989 krb5_gss_release_cred(minor_status, &defcred);
991 if (*context_handle == GSS_C_NO_CONTEXT)
992 krb5_free_context(context);
993 return(GSS_S_BAD_MECH);
996 /* is this a new connection or not? */
999 if (*context_handle == GSS_C_NO_CONTEXT) {
1000 major_status = kg_new_connection(minor_status, cred, context_handle,
1001 target_name, mech_type, req_flags,
1002 time_req, input_chan_bindings,
1003 input_token, actual_mech_type,
1004 output_token, ret_flags, time_rec,
1006 k5_mutex_unlock(&cred->lock);
1007 if (*context_handle == GSS_C_NO_CONTEXT) {
1008 save_error_info (*minor_status, context);
1009 krb5_free_context(context);
1011 ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
1013 /* mutual_auth doesn't care about the credentials */
1014 k5_mutex_unlock(&cred->lock);
1015 major_status = mutual_auth(minor_status, context_handle,
1016 target_name, mech_type, req_flags,
1017 time_req, input_chan_bindings,
1018 input_token, actual_mech_type,
1019 output_token, ret_flags, time_rec,
1021 /* If context_handle is now NO_CONTEXT, mutual_auth called
1022 delete_sec_context, which would've zapped the krb5 context
1026 krb5_gss_release_cred(&tmp_min_stat, &defcred);
1027 return(major_status);
1031 k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
1032 static int kdc_flag = 0;
1036 krb5_gss_init_context (krb5_context *ctxp)
1038 krb5_error_code err;
1043 err = gss_krb5int_initialize_library();
1047 err = k5_mutex_lock(&kg_kdc_flag_mutex);
1051 k5_mutex_unlock(&kg_kdc_flag_mutex);
1054 return krb5int_init_context_kdc(ctxp);
1057 return krb5_init_context(ctxp);
1062 krb5int_gss_use_kdc_context(OM_uint32 *minor_status,
1063 const gss_OID desired_mech,
1064 const gss_OID desired_object,
1071 err = gss_krb5int_initialize_library();
1074 *minor_status = k5_mutex_lock(&kg_kdc_flag_mutex);
1075 if (*minor_status) {
1076 return GSS_S_FAILURE;
1079 k5_mutex_unlock(&kg_kdc_flag_mutex);
1080 return GSS_S_COMPLETE;
1084 OM_uint32 KRB5_CALLCONV
1085 krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
1086 context_handle, target_name, mech_type,
1087 req_flags, time_req, input_chan_bindings,
1088 input_token, actual_mech_type, output_token,
1089 ret_flags, time_rec)
1090 OM_uint32 *minor_status;
1091 gss_cred_id_t claimant_cred_handle;
1092 gss_ctx_id_t *context_handle;
1093 gss_name_t target_name;
1095 OM_uint32 req_flags;
1097 gss_channel_bindings_t input_chan_bindings;
1098 gss_buffer_t input_token;
1099 gss_OID *actual_mech_type;
1100 gss_buffer_t output_token;
1101 OM_uint32 *ret_flags;
1102 OM_uint32 *time_rec;
1104 krb5_gss_ctx_ext_rec exts;
1106 memset(&exts, 0, sizeof(exts));
1108 return krb5_gss_init_sec_context_ext(minor_status,
1109 claimant_cred_handle,
1115 input_chan_bindings,