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, mcreds, *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);
142 in_creds.client = cred->name->princ;
143 in_creds.server = server->princ;
144 in_creds.times.endtime = endtime;
145 in_creds.authdata = NULL;
146 in_creds.keyblock.enctype = 0;
149 * cred->name is immutable, so there is no need to acquire
152 if (cred->name->ad_context != NULL) {
153 code = krb5_authdata_export_authdata(context,
154 cred->name->ad_context,
162 * For IAKERB or constrained delegation, only check the cache in this step.
163 * For IAKERB we will ask the server to make any necessary TGS requests;
164 * for constrained delegation we will adjust in_creds and make an S4U2Proxy
165 * request below if the cache lookup fails.
167 if (cred->impersonator != NULL || cred->iakerb_mech)
168 flags |= KRB5_GC_CACHED;
170 code = krb5_get_credentials(context, flags, cred->ccache,
171 &in_creds, &result_creds);
174 * Try constrained delegation if we have proxy credentials, unless
175 * we are trying to get a ticket to ourselves (in which case we could
176 * just use the evidence ticket directly from cache).
178 if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
179 !cred->iakerb_mech &&
180 !krb5_principal_compare(context, cred->impersonator, server->princ)) {
182 memset(&mcreds, 0, sizeof(mcreds));
183 mcreds.magic = KV5M_CREDS;
184 mcreds.server = cred->impersonator;
185 mcreds.client = cred->name->princ;
186 code = krb5_cc_retrieve_cred(context, cred->ccache,
187 KRB5_TC_MATCH_AUTHDATA, &mcreds,
192 assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
193 in_creds.client = cred->impersonator;
194 in_creds.second_ticket = evidence_creds.ticket;
195 flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
196 code = krb5_get_credentials(context, flags, cred->ccache,
197 &in_creds, &result_creds);
203 if (flags & KRB5_GC_CONSTRAINED_DELEGATION) {
204 if (!krb5_principal_compare(context, cred->name->princ,
205 result_creds->client)) {
206 /* server did not support constrained delegation */
207 code = KRB5_KDCREP_MODIFIED;
213 * Enforce a stricter limit (without timeskew forgiveness at the
214 * boundaries) because accept_sec_context code is also similarly
217 if (!krb5_gss_dbg_client_expcreds &&
218 ts_after(now, result_creds->times.endtime)) {
219 code = KRB5KRB_AP_ERR_TKT_EXPIRED;
223 *out_creds = result_creds;
227 krb5_free_authdata(context, in_creds.authdata);
228 krb5_free_cred_contents(context, &evidence_creds);
229 krb5_free_creds(context, result_creds);
233 struct gss_checksum_data {
234 krb5_gss_ctx_id_rec *ctx;
235 krb5_gss_cred_id_t cred;
237 krb5_data checksum_data;
238 krb5_gss_ctx_ext_t exts;
242 #include "../../krb5/krb/auth_con.h"
244 static krb5_error_code KRB5_CALLCONV
245 make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
246 void *cksum_data, krb5_data **out)
248 krb5_error_code code;
249 krb5_int32 con_flags;
251 struct gss_checksum_data *data = cksum_data;
254 krb5_data *finished = NULL;
255 krb5_key send_subkey;
257 data->checksum_data.data = 0;
259 /* build the checksum field */
261 if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
262 /* first get KRB_CRED message, so we know its length */
264 /* clear the time check flag that was set in krb5_auth_con_init() */
265 krb5_auth_con_getflags(context, auth_context, &con_flags);
266 krb5_auth_con_setflags(context, auth_context,
267 con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
269 assert(data->cred->name != NULL);
272 * RFC 4121 4.1.1 specifies forwarded credentials must be encrypted in
273 * the session key, but krb5_fwd_tgt_creds will use the send subkey if
274 * it's set in the auth context. Suppress the send subkey
277 krb5_auth_con_getsendsubkey_k(context, auth_context, &send_subkey);
278 krb5_auth_con_setsendsubkey_k(context, auth_context, NULL);
280 code = krb5_fwd_tgt_creds(context, auth_context, 0,
281 data->cred->name->princ, data->ctx->there->princ,
282 data->cred->ccache, 1,
285 /* Turn KRB5_AUTH_CONTEXT_DO_TIME back on and reset the send subkey. */
286 krb5_auth_con_setflags(context, auth_context, con_flags);
287 krb5_auth_con_setsendsubkey_k(context, auth_context, send_subkey);
288 krb5_k_free_key(context, send_subkey);
291 /* don't fail here; just don't accept/do the delegation
293 data->ctx->gss_flags &= ~(GSS_C_DELEG_FLAG |
294 GSS_C_DELEG_POLICY_FLAG);
296 data->checksum_data.length = 24;
298 if (credmsg.length+28 > KRB5_INT16_MAX) {
299 code = KRB5KRB_ERR_FIELD_TOOLONG;
303 data->checksum_data.length = 28+credmsg.length;
306 data->checksum_data.length = 24;
309 if (data->ctx->auth_context->keyblock != NULL
310 && data->ctx->auth_context->keyblock->enctype == 18) {
311 srand(time(0) ^ getpid());
312 /* Our ftp client code stupidly assumes a base64-encoded
313 version of the token will fit in 10K, so don't make this
315 junk = rand() & 0xff;
322 assert(data->exts != NULL);
324 if (data->exts->iakerb.conv) {
327 code = krb5_auth_con_getsendsubkey_k(context, auth_context, &key);
331 code = iakerb_make_finished(context, key, data->exts->iakerb.conv,
334 krb5_k_free_key(context, key);
338 krb5_k_free_key(context, key);
339 data->checksum_data.length += 8 + finished->length;
342 data->checksum_data.length += junk;
344 /* now allocate a buffer to hold the checksum data and
345 (maybe) KRB_CRED msg */
347 if ((data->checksum_data.data =
348 (char *) xmalloc(data->checksum_data.length)) == NULL) {
353 ptr = (unsigned char *)data->checksum_data.data;
355 TWRITE_INT(ptr, data->md5.length, 0);
356 TWRITE_STR(ptr, data->md5.contents, data->md5.length);
357 TWRITE_INT(ptr, data->ctx->gss_flags, 0);
360 TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
361 TWRITE_INT16(ptr, credmsg.length, 0);
362 TWRITE_STR(ptr, credmsg.data, credmsg.length);
364 if (data->exts->iakerb.conv) {
365 TWRITE_INT(ptr, KRB5_GSS_EXTS_IAKERB_FINISHED, 1);
366 TWRITE_INT(ptr, finished->length, 1);
367 TWRITE_STR(ptr, finished->data, finished->length);
370 memset(ptr, 'i', junk);
371 *out = &data->checksum_data;
374 krb5_free_data_contents(context, &credmsg);
375 krb5_free_data(context, finished);
379 static krb5_error_code
380 make_ap_req_v1(context, ctx, cred, k_cred, ad_context,
381 chan_bindings, mech_type, token, exts)
382 krb5_context context;
383 krb5_gss_ctx_id_rec *ctx;
384 krb5_gss_cred_id_t cred;
386 krb5_authdata_context ad_context;
387 gss_channel_bindings_t chan_bindings;
390 krb5_gss_ctx_ext_t exts;
392 krb5_flags mk_req_flags = 0;
393 krb5_error_code code;
394 struct gss_checksum_data cksum_struct;
401 k5_mutex_assert_locked(&cred->lock);
404 /* compute the hash of the channel bindings */
406 if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5)))
409 krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
411 cksum_struct.md5 = md5;
412 cksum_struct.ctx = ctx;
413 cksum_struct.cred = cred;
414 cksum_struct.checksum_data.data = NULL;
415 cksum_struct.exts = exts;
416 krb5_auth_con_set_checksum_func(context, ctx->auth_context,
417 make_gss_checksum, &cksum_struct);
419 /* call mk_req. subkey and ap_req need to be used or destroyed */
421 mk_req_flags = AP_OPTS_USE_SUBKEY;
423 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
424 mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_ETYPE_NEGOTIATION;
426 krb5_auth_con_set_authdata_context(context, ctx->auth_context, ad_context);
427 code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
428 NULL, k_cred, &ap_req);
429 krb5_auth_con_set_authdata_context(context, ctx->auth_context, NULL);
430 krb5_free_checksum_contents(context, &cksum_struct.md5);
431 krb5_free_data_contents(context, &cksum_struct.checksum_data);
435 /* store the interesting stuff from creds and authent */
436 ctx->krb_times = k_cred->times;
437 ctx->krb_flags = k_cred->ticket_flags;
439 /* build up the token */
440 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
442 * For DCE RPC, do not encapsulate the AP-REQ in the
443 * typical GSS wrapping.
445 code = data_to_gss(&ap_req, token);
449 /* allocate space for the token */
450 tlen = g_token_size((gss_OID) mech_type, ap_req.length);
452 if ((t = (unsigned char *) gssalloc_malloc(tlen)) == NULL) {
457 /* fill in the buffer */
460 g_make_token_header(mech_type, ap_req.length,
461 &ptr, KG_TOK_CTX_AP_REQ);
463 TWRITE_STR(ptr, ap_req.data, ap_req.length);
467 token->length = tlen;
468 token->value = (void *) t;
475 krb5_free_data_contents(context, &ap_req);
483 * Do the grunt work of setting up a new context.
487 OM_uint32 *minor_status,
488 krb5_gss_cred_id_t cred,
489 gss_ctx_id_t *context_handle,
490 gss_name_t target_name,
494 gss_channel_bindings_t input_chan_bindings,
495 gss_buffer_t input_token,
496 gss_OID *actual_mech_type,
497 gss_buffer_t output_token,
498 OM_uint32 *ret_flags,
500 krb5_context context,
501 krb5_gss_ctx_ext_t exts)
503 OM_uint32 major_status;
504 krb5_error_code code;
505 krb5_creds *k_cred = NULL;
506 krb5_gss_ctx_id_rec *ctx, *ctx_free;
508 gss_buffer_desc token;
509 krb5_keyblock *keyblock;
511 k5_mutex_assert_locked(&cred->lock);
512 major_status = GSS_S_FAILURE;
516 /* make sure the cred is usable for init */
518 if ((cred->usage != GSS_C_INITIATE) &&
519 (cred->usage != GSS_C_BOTH)) {
521 return(GSS_S_NO_CRED);
524 /* complain if the input token is non-null */
526 if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
528 return(GSS_S_DEFECTIVE_TOKEN);
533 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
535 *minor_status = ENOMEM;
536 return(GSS_S_FAILURE);
539 /* fill in the ctx */
540 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
541 ctx->magic = KG_CONTEXT;
543 if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
545 krb5_auth_con_setflags(context, ctx->auth_context,
546 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
548 /* limit the encryption types negotiated (if requested) */
549 if (cred->req_enctypes) {
550 if ((code = krb5_set_default_tgs_enctypes(context,
551 cred->req_enctypes))) {
560 ctx->gss_flags = req_flags & (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG |
561 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
562 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
563 GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
564 GSS_C_EXTENDED_ERROR_FLAG);
565 ctx->gss_flags |= GSS_C_TRANS_FLAG;
566 if (!cred->suppress_ci_flags)
567 ctx->gss_flags |= (GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);
568 if (req_flags & GSS_C_DCE_STYLE)
569 ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
571 if ((code = krb5_timeofday(context, &now)))
574 if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
575 ctx->krb_times.endtime = 0;
577 ctx->krb_times.endtime = ts_incr(now, time_req);
580 if ((code = kg_duplicate_name(context, cred->name, &ctx->here)))
583 if ((code = kg_duplicate_name(context, (krb5_gss_name_t)target_name,
587 code = get_credentials(context, cred, ctx->there, now,
588 ctx->krb_times.endtime, &k_cred);
592 ctx->krb_times = k_cred->times;
595 * GSS_C_DELEG_POLICY_FLAG means to delegate only if the
596 * ok-as-delegate ticket flag is set.
598 if ((req_flags & GSS_C_DELEG_POLICY_FLAG)
599 && (k_cred->ticket_flags & TKT_FLG_OK_AS_DELEGATE))
600 ctx->gss_flags |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG;
602 if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
604 code = *minor_status;
608 * Now try to make it static if at all possible....
610 ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
615 if ((code = make_ap_req_v1(context, ctx,
616 cred, k_cred, ctx->here->ad_context,
618 mech_type, &token, exts))) {
619 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
620 (code == KG_EMPTY_CCACHE))
621 major_status = GSS_S_NO_CRED;
622 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
623 major_status = GSS_S_CREDENTIALS_EXPIRED;
627 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &seq_temp);
628 ctx->seq_send = seq_temp;
629 code = krb5_auth_con_getsendsubkey(context, ctx->auth_context,
633 code = krb5_k_create_key(context, keyblock, &ctx->subkey);
634 krb5_free_keyblock(context, keyblock);
641 ctx->have_acceptor_subkey = 0;
642 code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
646 if (!(ctx->gss_flags & GSS_C_MUTUAL_FLAG)) {
647 /* There will be no AP-REP, so set up sequence state now. */
648 ctx->seq_recv = ctx->seq_send;
649 code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
650 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
651 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
657 /* compute time_rec */
659 if ((code = krb5_timeofday(context, &now)))
661 *time_rec = ts_delta(ctx->krb_times.endtime, now);
664 /* set the other returns */
665 *output_token = token;
668 *ret_flags = ctx->gss_flags;
670 if (actual_mech_type)
671 *actual_mech_type = mech_type;
673 /* return successfully */
675 *context_handle = (gss_ctx_id_t) ctx;
677 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
678 ctx->established = 0;
679 major_status = GSS_S_CONTINUE_NEEDED;
681 ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
682 ctx->established = 1;
683 major_status = GSS_S_COMPLETE;
687 krb5_free_creds(context, k_cred);
689 if (ctx_free->auth_context)
690 krb5_auth_con_free(context, ctx_free->auth_context);
692 kg_release_name(context, &ctx_free->here);
694 kg_release_name(context, &ctx_free->there);
695 if (ctx_free->subkey)
696 krb5_k_free_key(context, ctx_free->subkey);
700 *minor_status = code;
701 return (major_status);
707 * Handle the reply from the acceptor, if we're doing mutual auth.
711 OM_uint32 *minor_status,
712 gss_ctx_id_t *context_handle,
713 gss_name_t target_name,
717 gss_channel_bindings_t input_chan_bindings,
718 gss_buffer_t input_token,
719 gss_OID *actual_mech_type,
720 gss_buffer_t output_token,
721 OM_uint32 *ret_flags,
723 krb5_context context)
725 OM_uint32 major_status;
729 krb5_ap_rep_enc_part *ap_rep_data;
731 krb5_gss_ctx_id_rec *ctx;
732 krb5_error *krb_error;
733 krb5_error_code code;
734 krb5int_access kaccess;
736 major_status = GSS_S_FAILURE;
738 code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
742 ctx = (krb5_gss_ctx_id_t) *context_handle;
744 /* make sure the context is non-established, and that certain
745 arguments are unchanged */
747 if ((ctx->established) ||
748 ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
749 code = KG_CONTEXT_ESTABLISHED;
753 if (! kg_compare_name(context, ctx->there, (krb5_gss_name_t)target_name)) {
754 (void)krb5_gss_delete_sec_context(minor_status,
755 context_handle, NULL);
757 major_status = GSS_S_BAD_NAME;
761 /* verify the token and leave the AP_REP message in ap_rep */
763 if (input_token == GSS_C_NO_BUFFER) {
764 (void)krb5_gss_delete_sec_context(minor_status,
765 context_handle, NULL);
767 major_status = GSS_S_DEFECTIVE_TOKEN;
771 ptr = (unsigned char *) input_token->value;
773 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
775 ap_rep.length = input_token->length;
776 ap_rep.data = (char *)input_token->value;
777 } else if (g_verify_token_header(ctx->mech_used,
779 &ptr, KG_TOK_CTX_AP_REP,
780 input_token->length, 1)) {
781 if (g_verify_token_header((gss_OID) ctx->mech_used,
783 &ptr, KG_TOK_CTX_ERROR,
784 input_token->length, 1) == 0) {
786 /* Handle a KRB_ERROR message from the server */
788 sptr = (char *) ptr; /* PC compiler bug */
789 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
791 code = krb5_rd_error(context, &ap_rep, &krb_error);
794 if (krb_error->error)
795 code = (krb5_error_code)krb_error->error + ERROR_TABLE_BASE_krb5;
798 krb5_free_error(context, krb_error);
802 return(GSS_S_DEFECTIVE_TOKEN);
806 sptr = (char *) ptr; /* PC compiler bug */
807 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
809 /* decode the ap_rep */
810 if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
813 * XXX A hack for backwards compatiblity.
814 * To be removed in 1999 -- proven
816 krb5_auth_con_setuseruserkey(context, ctx->auth_context,
817 &ctx->subkey->keyblock);
818 if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
823 /* store away the sequence number */
824 ctx->seq_recv = ap_rep_data->seq_number;
825 code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
826 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
827 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
830 krb5_free_ap_rep_enc_part(context, ap_rep_data);
834 if (ap_rep_data->subkey != NULL &&
835 (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
836 ap_rep_data->subkey->enctype != ctx->subkey->keyblock.enctype)) {
837 /* Keep acceptor's subkey. */
838 ctx->have_acceptor_subkey = 1;
839 code = krb5_k_create_key(context, ap_rep_data->subkey,
840 &ctx->acceptor_subkey);
842 krb5_free_ap_rep_enc_part(context, ap_rep_data);
845 code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
846 &ctx->acceptor_subkey_cksumtype);
848 krb5_free_ap_rep_enc_part(context, ap_rep_data);
852 /* free the ap_rep_data */
853 krb5_free_ap_rep_enc_part(context, ap_rep_data);
855 if (ctx->gss_flags & GSS_C_DCE_STYLE) {
858 code = krb5_mk_rep_dce(context, ctx->auth_context, &outbuf);
862 code = data_to_gss(&outbuf, output_token);
867 /* set established */
868 ctx->established = 1;
873 if ((code = krb5_timeofday(context, &now)))
875 *time_rec = ts_delta(ctx->krb_times.endtime, now);
879 *ret_flags = ctx->gss_flags;
881 if (actual_mech_type)
882 *actual_mech_type = mech_type;
887 return GSS_S_COMPLETE;
890 (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
892 *minor_status = code;
893 return (major_status);
897 krb5_gss_init_sec_context_ext(
898 OM_uint32 *minor_status,
899 gss_cred_id_t claimant_cred_handle,
900 gss_ctx_id_t *context_handle,
901 gss_name_t target_name,
905 gss_channel_bindings_t input_chan_bindings,
906 gss_buffer_t input_token,
907 gss_OID *actual_mech_type,
908 gss_buffer_t output_token,
909 OM_uint32 *ret_flags,
911 krb5_gss_ctx_ext_t exts)
913 krb5_context context;
914 gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
915 krb5_gss_cred_id_t cred;
916 krb5_error_code kerr;
917 OM_uint32 major_status;
918 OM_uint32 tmp_min_stat;
920 if (*context_handle == GSS_C_NO_CONTEXT) {
921 kerr = krb5_gss_init_context(&context);
923 *minor_status = kerr;
924 return GSS_S_FAILURE;
926 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
927 save_error_info(*minor_status, context);
928 krb5_free_context(context);
929 return GSS_S_FAILURE;
932 context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
935 /* set up return values so they can be "freed" successfully */
937 major_status = GSS_S_FAILURE; /* Default major code */
938 output_token->length = 0;
939 output_token->value = NULL;
940 if (actual_mech_type)
941 *actual_mech_type = NULL;
943 /* verify the mech_type */
945 if (mech_type == GSS_C_NULL_OID || g_OID_equal(mech_type, gss_mech_krb5)) {
946 mech_type = (gss_OID) gss_mech_krb5;
947 } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
948 mech_type = (gss_OID) gss_mech_krb5_old;
949 } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
950 mech_type = (gss_OID) gss_mech_krb5_wrong;
951 } else if (g_OID_equal(mech_type, gss_mech_iakerb)) {
952 mech_type = (gss_OID) gss_mech_iakerb;
955 if (*context_handle == GSS_C_NO_CONTEXT)
956 krb5_free_context(context);
957 return(GSS_S_BAD_MECH);
960 /* is this a new connection or not? */
963 if (*context_handle == GSS_C_NO_CONTEXT) {
964 /* verify the credential, or use the default */
966 if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
967 major_status = kg_get_defcred(minor_status, &defcred);
968 if (major_status && GSS_ERROR(major_status)) {
969 if (*context_handle == GSS_C_NO_CONTEXT)
970 krb5_free_context(context);
971 return(major_status);
973 claimant_cred_handle = defcred;
976 major_status = kg_cred_resolve(minor_status, context,
977 claimant_cred_handle, target_name);
978 if (GSS_ERROR(major_status)) {
979 save_error_info(*minor_status, context);
980 krb5_gss_release_cred(&tmp_min_stat, &defcred);
981 if (*context_handle == GSS_C_NO_CONTEXT)
982 krb5_free_context(context);
983 return(major_status);
985 cred = (krb5_gss_cred_id_t)claimant_cred_handle;
987 major_status = kg_new_connection(minor_status, cred, context_handle,
988 target_name, mech_type, req_flags,
989 time_req, input_chan_bindings,
990 input_token, actual_mech_type,
991 output_token, ret_flags, time_rec,
993 k5_mutex_unlock(&cred->lock);
994 krb5_gss_release_cred(&tmp_min_stat, &defcred);
995 if (*context_handle == GSS_C_NO_CONTEXT) {
996 save_error_info (*minor_status, context);
997 krb5_free_context(context);
999 ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
1001 /* mutual_auth doesn't care about the credentials */
1002 major_status = mutual_auth(minor_status, context_handle,
1003 target_name, mech_type, req_flags,
1004 time_req, input_chan_bindings,
1005 input_token, actual_mech_type,
1006 output_token, ret_flags, time_rec,
1008 /* If context_handle is now NO_CONTEXT, mutual_auth called
1009 delete_sec_context, which would've zapped the krb5 context
1013 return(major_status);
1017 k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
1018 static int kdc_flag = 0;
1022 krb5_gss_init_context (krb5_context *ctxp)
1024 krb5_error_code err;
1029 err = gss_krb5int_initialize_library();
1033 k5_mutex_lock(&kg_kdc_flag_mutex);
1035 k5_mutex_unlock(&kg_kdc_flag_mutex);
1038 return krb5int_init_context_kdc(ctxp);
1041 return krb5_init_context(ctxp);
1046 krb5int_gss_use_kdc_context(OM_uint32 *minor_status,
1047 const gss_OID desired_mech,
1048 const gss_OID desired_object,
1055 err = gss_krb5int_initialize_library();
1058 k5_mutex_lock(&kg_kdc_flag_mutex);
1060 k5_mutex_unlock(&kg_kdc_flag_mutex);
1061 return GSS_S_COMPLETE;
1065 OM_uint32 KRB5_CALLCONV
1066 krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
1067 context_handle, target_name, mech_type,
1068 req_flags, time_req, input_chan_bindings,
1069 input_token, actual_mech_type, output_token,
1070 ret_flags, time_rec)
1071 OM_uint32 *minor_status;
1072 gss_cred_id_t claimant_cred_handle;
1073 gss_ctx_id_t *context_handle;
1074 gss_name_t target_name;
1076 OM_uint32 req_flags;
1078 gss_channel_bindings_t input_chan_bindings;
1079 gss_buffer_t input_token;
1080 gss_OID *actual_mech_type;
1081 gss_buffer_t output_token;
1082 OM_uint32 *ret_flags;
1083 OM_uint32 *time_rec;
1085 krb5_gss_ctx_ext_rec exts;
1087 memset(&exts, 0, sizeof(exts));
1089 return krb5_gss_init_sec_context_ext(minor_status,
1090 claimant_cred_handle,
1096 input_chan_bindings,