2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "gssapi_locl.h"
36 RCSID("$Id: accept_sec_context.c,v 1.53 2005/05/29 15:12:41 lha Exp $");
38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39 krb5_keytab gssapi_krb5_keytab;
42 gsskrb5_register_acceptor_identity (const char *identity)
46 ret = gssapi_krb5_init();
50 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
52 if(gssapi_krb5_keytab != NULL) {
53 krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab);
54 gssapi_krb5_keytab = NULL;
56 if (identity == NULL) {
57 ret = krb5_kt_default(gssapi_krb5_context, &gssapi_krb5_keytab);
61 asprintf(&p, "FILE:%s", identity);
63 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
66 ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
69 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
72 return GSS_S_COMPLETE;
76 gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx)
79 int acceptor = (context_handle->more_flags & LOCAL) == 0;
82 if (context_handle->auth_context->local_subkey)
83 key = context_handle->auth_context->local_subkey;
85 key = context_handle->auth_context->remote_subkey;
87 if (context_handle->auth_context->remote_subkey)
88 key = context_handle->auth_context->remote_subkey;
90 key = context_handle->auth_context->local_subkey;
93 key = context_handle->auth_context->keyblock;
98 switch (key->keytype) {
99 case ETYPE_DES_CBC_CRC:
100 case ETYPE_DES_CBC_MD4:
101 case ETYPE_DES_CBC_MD5:
102 case ETYPE_DES3_CBC_MD5:
103 case ETYPE_DES3_CBC_SHA1:
104 case ETYPE_ARCFOUR_HMAC_MD5:
105 case ETYPE_ARCFOUR_HMAC_MD5_56:
109 if ((acceptor && context_handle->auth_context->local_subkey) ||
110 (!acceptor && context_handle->auth_context->remote_subkey))
111 context_handle->more_flags |= ACCEPTOR_SUBKEY;
118 gsskrb5_accept_delegated_token
119 (OM_uint32 * minor_status,
120 gss_ctx_id_t * context_handle,
121 gss_cred_id_t * delegated_cred_handle)
123 krb5_data *fwd_data = &(*context_handle)->fwd_data;
124 OM_uint32 *flags = &(*context_handle)->flags;
125 krb5_principal principal = (*context_handle)->source;
126 krb5_ccache ccache = NULL;
127 krb5_error_code kret;
128 int32_t ac_flags, ret;
129 gss_cred_id_t handle = NULL;
131 if (delegated_cred_handle == NULL) {
132 /* XXX Create a new delegated_cred_handle? */
136 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
138 *flags &= ~GSS_C_DELEG_FLAG;
143 *delegated_cred_handle = NULL;
145 handle = calloc(1, sizeof(*handle));
146 if (handle == NULL) {
148 *minor_status = ENOMEM;
149 krb5_set_error_string(gssapi_krb5_context, "out of memory");
150 gssapi_krb5_set_error_string();
151 *flags &= ~GSS_C_DELEG_FLAG;
154 if ((ret = gss_duplicate_name(minor_status, principal,
155 &handle->principal)) != 0) {
156 *flags &= ~GSS_C_DELEG_FLAG;
160 kret = krb5_cc_gen_new (gssapi_krb5_context,
164 *flags &= ~GSS_C_DELEG_FLAG;
168 ccache = handle->ccache;
170 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
172 *flags &= ~GSS_C_DELEG_FLAG;
175 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
176 &handle->mechanisms);
178 *flags &= ~GSS_C_DELEG_FLAG;
183 kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal);
185 *flags &= ~GSS_C_DELEG_FLAG;
190 krb5_auth_con_removeflags(gssapi_krb5_context,
191 (*context_handle)->auth_context,
192 KRB5_AUTH_CONTEXT_DO_TIME,
194 kret = krb5_rd_cred2(gssapi_krb5_context,
195 (*context_handle)->auth_context,
199 gssapi_krb5_set_error_string();
200 krb5_auth_con_setflags(gssapi_krb5_context,
201 (*context_handle)->auth_context,
204 *flags &= ~GSS_C_DELEG_FLAG;
206 *minor_status = kret;
210 /* if there was some kind of failure, clean up internal structures */
211 if ((*flags & GSS_C_DELEG_FLAG) == 0) {
213 if (handle->principal)
214 gss_release_name(minor_status, &handle->principal);
215 if (handle->mechanisms)
216 gss_release_oid_set(NULL, &handle->mechanisms);
218 krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
223 if (delegated_cred_handle == NULL) {
225 krb5_cc_close(gssapi_krb5_context, ccache);
228 *delegated_cred_handle = handle;
234 gsskrb5_acceptor_ready(
235 OM_uint32 * minor_status,
236 gss_ctx_id_t * context_handle,
237 gss_cred_id_t * delegated_cred_handle)
242 u_int32_t *flags = &(*context_handle)->flags;
244 krb5_auth_getremoteseqnumber (gssapi_krb5_context,
245 (*context_handle)->auth_context,
248 gsskrb5_is_cfx(*context_handle, &is_cfx);
250 ret = _gssapi_msg_order_create(minor_status,
251 &(*context_handle)->order,
252 _gssapi_msg_order_f(*flags),
253 seq_number, 0, is_cfx);
256 if (!(*flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(*flags)) {
257 krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
258 (*context_handle)->auth_context,
263 * We should handle the delegation ticket, in case it's there
265 if ((*context_handle)->fwd_data.length > 0 && (*flags & GSS_C_DELEG_FLAG)) {
266 ret = gsskrb5_accept_delegated_token(minor_status,
268 delegated_cred_handle);
271 /* Well, looks like it wasn't there after all */
272 *flags &= ~GSS_C_DELEG_FLAG;
275 (*context_handle)->state = ACCEPTOR_READY;
276 (*context_handle)->more_flags |= OPEN;
278 return GSS_S_COMPLETE;
281 gsskrb5_acceptor_start
282 (OM_uint32 * minor_status,
283 gss_ctx_id_t * context_handle,
284 const gss_cred_id_t acceptor_cred_handle,
285 const gss_buffer_t input_token_buffer,
286 const gss_channel_bindings_t input_chan_bindings,
287 gss_name_t * src_name,
289 gss_buffer_t output_token,
290 OM_uint32 * ret_flags,
291 OM_uint32 * time_rec,
292 gss_cred_id_t * delegated_cred_handle
295 krb5_error_code kret;
296 OM_uint32 ret = GSS_S_COMPLETE;
298 krb5_flags ap_options;
300 krb5_ticket *ticket = NULL;
301 krb5_keytab keytab = NULL;
302 krb5_keyblock *keyblock = NULL;
305 krb5_data_zero (&(*context_handle)->fwd_data);
308 * We may, or may not, have an escapsulation.
310 ret = gssapi_krb5_decapsulate (minor_status,
317 /* No OID wrapping apparently available. */
318 indata.length = input_token_buffer->length;
319 indata.data = input_token_buffer->value;
323 * We need to get our keytab
325 if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
326 if (gssapi_krb5_keytab != NULL) {
327 keytab = gssapi_krb5_keytab;
329 } else if (acceptor_cred_handle->keytab != NULL) {
330 keytab = acceptor_cred_handle->keytab;
334 * We need to check the ticket and create the AP-REP packet
336 kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
337 &(*context_handle)->auth_context,
339 (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
346 *minor_status = kret;
347 gssapi_krb5_set_error_string ();
352 * We need to remember some data on the context_handle
354 (*context_handle)->ticket = ticket;
355 (*context_handle)->service_keyblock = keyblock;
356 (*context_handle)->lifetime = ticket->ticket.endtime;
359 * We need to copy the principal names to the context and the calling layer
361 kret = krb5_copy_principal(gssapi_krb5_context,
363 &(*context_handle)->source);
366 *minor_status = kret;
367 gssapi_krb5_set_error_string ();
370 kret = krb5_copy_principal (gssapi_krb5_context,
372 &(*context_handle)->target);
375 *minor_status = kret;
376 gssapi_krb5_set_error_string ();
381 * We need to setup some compat stuff, this assumes that context_handle->target is already set
383 ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
388 if (src_name != NULL) {
389 kret = krb5_copy_principal (gssapi_krb5_context,
394 *minor_status = kret;
395 gssapi_krb5_set_error_string ();
401 * We need to get the flags out of the 8003 checksum
404 krb5_authenticator authenticator;
406 kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
407 (*context_handle)->auth_context,
411 *minor_status = kret;
412 gssapi_krb5_set_error_string ();
416 ret = gssapi_krb5_verify_8003_checksum(minor_status,
418 authenticator->cksum,
420 &(*context_handle)->fwd_data);
421 krb5_free_authenticator(gssapi_krb5_context, &authenticator);
427 if(flags & GSS_C_MUTUAL_FLAG) {
430 gsskrb5_is_cfx(*context_handle, &is_cfx);
433 || (ap_options & AP_OPTS_USE_SUBKEY)) {
434 kret = krb5_auth_con_addflags(gssapi_krb5_context,
435 (*context_handle)->auth_context,
436 KRB5_AUTH_CONTEXT_USE_SUBKEY,
438 (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
441 kret = krb5_mk_rep(gssapi_krb5_context,
442 (*context_handle)->auth_context,
445 *minor_status = kret;
446 gssapi_krb5_set_error_string ();
447 return GSS_S_FAILURE;
450 if (!(flags & GSS_C_DCE_STYLE)) {
451 ret = gssapi_krb5_encapsulate(minor_status,
456 krb5_data_free (&outbuf);
461 output_token->length = outbuf.length;
462 output_token->value = outbuf.data;
466 flags |= GSS_C_TRANS_FLAG;
468 /* Remember the flags */
470 (*context_handle)->lifetime = ticket->ticket.endtime;
471 (*context_handle)->flags = flags;
472 (*context_handle)->more_flags |= OPEN;
475 *mech_type = GSS_KRB5_MECHANISM;
478 ret = gssapi_lifetime_left(minor_status,
479 (*context_handle)->lifetime,
487 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
489 if (flags & GSS_C_DCE_STYLE) {
491 /* Return flags to caller, but we haven't processed delgations yet */
492 *ret_flags = flags & ~GSS_C_DELEG_FLAG;
495 (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
496 return GSS_S_CONTINUE_NEEDED;
499 ret = gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
502 * We need to send the flags back to the caller
505 *ret_flags = (*context_handle)->flags;
510 gsskrb5_acceptor_wait_for_dcestyle(
511 OM_uint32 * minor_status,
512 gss_ctx_id_t * context_handle,
513 const gss_cred_id_t acceptor_cred_handle,
514 const gss_buffer_t input_token_buffer,
515 const gss_channel_bindings_t input_chan_bindings,
516 gss_name_t * src_name,
518 gss_buffer_t output_token,
519 OM_uint32 * ret_flags,
520 OM_uint32 * time_rec,
521 gss_cred_id_t * delegated_cred_handle)
524 krb5_error_code kret;
526 OM_uint32 r_seq_number;
527 OM_uint32 l_seq_number;
529 /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
530 inbuf.length = input_token_buffer->length;
531 inbuf.data = input_token_buffer->value;
534 * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
535 * and then reset the remote seq_number to the old value
538 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
539 (*context_handle)->auth_context,
542 gssapi_krb5_set_error_string ();
543 *minor_status = kret;
544 return GSS_S_FAILURE;
547 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
548 (*context_handle)->auth_context,
551 gssapi_krb5_set_error_string ();
552 *minor_status = kret;
553 return GSS_S_FAILURE;
556 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
557 (*context_handle)->auth_context,
560 gssapi_krb5_set_error_string ();
561 *minor_status = kret;
562 return GSS_S_FAILURE;
566 /* We need to verify the AP_REP, but we need to flag that this
567 is DCE_STYLE, so don't check the timestamps this time
570 krb5_ap_rep_enc_part *repl;
573 kret = krb5_auth_con_removeflags(gssapi_krb5_context,
574 (*context_handle)->auth_context,
575 KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags);
576 if (kret) { /* Can't happen */
577 gssapi_krb5_set_error_string ();
578 *minor_status = kret;
579 return GSS_S_FAILURE;
582 kret = krb5_rd_rep(gssapi_krb5_context,
583 (*context_handle)->auth_context,
587 gssapi_krb5_set_error_string ();
588 *minor_status = kret;
589 return GSS_S_FAILURE;
592 /* Because the inbuf above is a final leg from client
593 * to server, we don't have a use for a 'reply'
595 krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
597 /* Do no harm, put the flags back */
598 kret = krb5_auth_con_setflags(gssapi_krb5_context,
599 (*context_handle)->auth_context,
601 if (kret) { /* Can't happen */
602 gssapi_krb5_set_error_string ();
603 *minor_status = kret;
604 return GSS_S_FAILURE;
608 /* We need to check the liftime */
610 OM_uint32 lifetime_rec;
612 ret = gssapi_lifetime_left(minor_status,
613 (*context_handle)->lifetime,
618 if (lifetime_rec == 0) {
619 return GSS_S_CONTEXT_EXPIRED;
622 if (time_rec) *time_rec = lifetime_rec;
625 /* We need to give the caller the flags which are in use */
626 if (ret_flags) *ret_flags = (*context_handle)->flags;
629 kret = krb5_copy_principal(gssapi_krb5_context,
630 (*context_handle)->source,
633 *minor_status = kret;
634 gssapi_krb5_set_error_string ();
635 return GSS_S_FAILURE;
640 * After the krb5_rd_rep() the remote and local seq_number should be the same,
641 * because the client just replies the seq_number from our AP-REP in its AP-REP,
642 * but then the client uses the seq_number from its AP-REQ for GSS_wrap()
645 OM_uint32 tmp_r_seq_number;
646 OM_uint32 tmp_l_seq_number;
648 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
649 (*context_handle)->auth_context,
652 gssapi_krb5_set_error_string ();
653 *minor_status = kret;
654 return GSS_S_FAILURE;
657 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
658 (*context_handle)->auth_context,
661 gssapi_krb5_set_error_string ();
662 *minor_status = kret;
663 return GSS_S_FAILURE;
667 * Here we check if the client has responsed with our local seq_number,
669 if (tmp_r_seq_number != tmp_l_seq_number) {
670 return GSS_S_UNSEQ_TOKEN;
675 * We need to reset the remote seq_number, because the client will use,
676 * the old one for the GSS_wrap() calls
679 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
680 (*context_handle)->auth_context,
683 gssapi_krb5_set_error_string ();
684 *minor_status = kret;
685 return GSS_S_FAILURE;
689 return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
693 gsskrb5_accept_sec_context
694 (OM_uint32 * minor_status,
695 gss_ctx_id_t * context_handle,
696 const gss_cred_id_t acceptor_cred_handle,
697 const gss_buffer_t input_token_buffer,
698 const gss_channel_bindings_t input_chan_bindings,
699 gss_name_t * src_name,
701 gss_buffer_t output_token,
702 OM_uint32 * ret_flags,
703 OM_uint32 * time_rec,
704 gss_cred_id_t * delegated_cred_handle
707 OM_uint32 ret = GSS_S_COMPLETE;
709 gss_ctx_id_t local_context;
713 krb5_data_zero (&fwd_data);
714 output_token->length = 0;
715 output_token->value = NULL;
717 if (src_name != NULL)
720 *mech_type = GSS_KRB5_MECHANISM;
722 if (*context_handle == GSS_C_NO_CONTEXT) {
723 ret = _gsskrb5_create_ctx(minor_status,
729 local_context = *context_handle;
733 * TODO: check the channel_bindings
734 * (above just sets them to krb5 layer)
737 HEIMDAL_MUTEX_lock(&(local_context)->ctx_id_mutex);
739 switch ((local_context)->state) {
741 ret = gsskrb5_acceptor_start(minor_status,
743 acceptor_cred_handle,
751 delegated_cred_handle);
753 case ACCEPTOR_WAIT_FOR_DCESTYLE:
754 ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
756 acceptor_cred_handle,
764 delegated_cred_handle);
767 /* this function should not be called after it has returned GSS_S_COMPLETE */
768 ret = GSS_S_BAD_STATUS;
771 /* TODO: is this correct here? --metze */
772 ret = GSS_S_BAD_STATUS;
776 HEIMDAL_MUTEX_unlock(&(local_context)->ctx_id_mutex);
778 if (*context_handle == GSS_C_NO_CONTEXT) {
779 if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
780 *context_handle = local_context;
782 gss_delete_sec_context(minor_status,
792 code_NegTokenArg(OM_uint32 *minor_status,
793 const NegTokenTarg *targ,
799 size_t buf_size, buf_len;
802 buf = malloc(buf_size);
804 *minor_status = ENOMEM;
805 return GSS_S_FAILURE;
809 ret = encode_NegTokenTarg(buf + buf_size - 1,
815 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
826 if (ret == ASN1_OVERFLOW) {
830 tmp = realloc (buf, buf_size);
832 *minor_status = ENOMEM;
834 return GSS_S_FAILURE;
840 return GSS_S_FAILURE;
843 } while (ret == ASN1_OVERFLOW);
845 data->data = buf + buf_size - buf_len;
846 data->length = buf_len;
848 return GSS_S_COMPLETE;
852 send_reject (OM_uint32 *minor_status,
853 gss_buffer_t output_token)
860 ALLOC(targ.negResult, 1);
861 if (targ.negResult == NULL) {
862 *minor_status = ENOMEM;
863 return GSS_S_FAILURE;
865 *(targ.negResult) = reject;
866 targ.supportedMech = NULL;
867 targ.responseToken = NULL;
868 targ.mechListMIC = NULL;
870 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
871 free_NegTokenTarg(&targ);
876 ret = _gssapi_encapsulate(minor_status,
879 GSS_SPNEGO_MECHANISM);
881 output_token->value = malloc(data.length);
882 if (output_token->value == NULL) {
883 *minor_status = ENOMEM;
886 output_token->length = data.length;
887 memcpy(output_token->value, data.data, output_token->length);
893 return GSS_S_BAD_MECH;
897 send_accept (OM_uint32 *minor_status,
898 OM_uint32 major_status,
899 gss_buffer_t output_token,
900 gss_buffer_t mech_token,
901 gss_ctx_id_t context_handle,
902 const MechTypeList *mechtypelist)
908 gss_buffer_desc mech_buf, mech_mic_buf;
909 krb5_boolean require_mic;
911 memset(&targ, 0, sizeof(targ));
912 ALLOC(targ.negResult, 1);
913 if (targ.negResult == NULL) {
914 *minor_status = ENOMEM;
915 return GSS_S_FAILURE;
917 *(targ.negResult) = accept_completed;
919 ALLOC(targ.supportedMech, 1);
920 if (targ.supportedMech == NULL) {
921 free_NegTokenTarg(&targ);
922 *minor_status = ENOMEM;
923 return GSS_S_FAILURE;
926 ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
927 GSS_KRB5_MECHANISM->length,
931 free_NegTokenTarg(&targ);
932 *minor_status = ENOMEM;
933 return GSS_S_FAILURE;
936 if (mech_token != NULL && mech_token->length != 0) {
937 ALLOC(targ.responseToken, 1);
938 if (targ.responseToken == NULL) {
939 free_NegTokenTarg(&targ);
940 *minor_status = ENOMEM;
941 return GSS_S_FAILURE;
943 targ.responseToken->length = mech_token->length;
944 targ.responseToken->data = mech_token->value;
945 mech_token->length = 0;
946 mech_token->value = NULL;
948 targ.responseToken = NULL;
951 ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
954 free_NegTokenTarg(&targ);
958 if (major_status == GSS_S_COMPLETE && require_mic) {
961 ALLOC(targ.mechListMIC, 1);
962 if (targ.mechListMIC == NULL) {
963 free_NegTokenTarg(&targ);
964 *minor_status = ENOMEM;
965 return GSS_S_FAILURE;
968 ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
969 mechtypelist, &buf_len, ret);
971 free_NegTokenTarg(&targ);
974 if (mech_buf.length != buf_len)
977 ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
979 free (mech_buf.value);
981 free_NegTokenTarg(&targ);
985 targ.mechListMIC->length = mech_mic_buf.length;
986 targ.mechListMIC->data = mech_mic_buf.value;
988 targ.mechListMIC = NULL;
990 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
991 free_NegTokenTarg(&targ);
996 ret = _gssapi_encapsulate(minor_status,
999 GSS_SPNEGO_MECHANISM);
1001 output_token->value = malloc(data.length);
1002 if (output_token->value == NULL) {
1003 *minor_status = ENOMEM;
1004 ret = GSS_S_FAILURE;
1006 output_token->length = data.length;
1007 memcpy(output_token->value, data.data, output_token->length);
1013 return GSS_S_COMPLETE;
1017 spnego_accept_sec_context
1018 (OM_uint32 * minor_status,
1019 gss_ctx_id_t * context_handle,
1020 const gss_cred_id_t acceptor_cred_handle,
1021 const gss_buffer_t input_token_buffer,
1022 const gss_channel_bindings_t input_chan_bindings,
1023 gss_name_t * src_name,
1024 gss_OID * mech_type,
1025 gss_buffer_t output_token,
1026 OM_uint32 * ret_flags,
1027 OM_uint32 * time_rec,
1028 gss_cred_id_t * delegated_cred_handle
1031 OM_uint32 ret, ret2;
1039 output_token->length = 0;
1040 output_token->value = NULL;
1042 ret = _gssapi_decapsulate (minor_status,
1045 GSS_SPNEGO_MECHANISM);
1049 ret = der_match_tag_and_length(data.data, data.length,
1050 ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
1054 if(len > data.length - taglen)
1055 return ASN1_OVERRUN;
1057 ret = decode_NegTokenInit((const char *)data.data + taglen, len,
1060 return GSS_S_DEFECTIVE_TOKEN;
1062 if (ni.mechTypes == NULL) {
1063 free_NegTokenInit(&ni);
1064 return send_reject (minor_status, output_token);
1067 for (i = 0; !found && i < ni.mechTypes->len; ++i) {
1071 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
1073 &ni.mechTypes->val[i],
1076 free_NegTokenInit(&ni);
1077 return GSS_S_DEFECTIVE_TOKEN;
1079 if (mech_len == GSS_KRB5_MECHANISM->length
1080 && memcmp(GSS_KRB5_MECHANISM->elements,
1081 mechbuf + sizeof(mechbuf) - mech_len,
1086 gss_buffer_desc ibuf, obuf;
1087 gss_buffer_t ot = NULL;
1090 if (ni.mechToken != NULL) {
1091 ibuf.length = ni.mechToken->length;
1092 ibuf.value = ni.mechToken->data;
1094 ret = gsskrb5_accept_sec_context(&minor,
1096 acceptor_cred_handle,
1098 input_chan_bindings,
1104 delegated_cred_handle);
1105 if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
1108 free_NegTokenInit(&ni);
1109 send_reject (minor_status, output_token);
1113 ret2 = send_accept (minor_status, ret, output_token, ot,
1114 *context_handle, ni.mechTypes);
1115 if (ret2 != GSS_S_COMPLETE)
1118 gss_release_buffer(&minor, ot);
1119 free_NegTokenInit(&ni);
1122 free_NegTokenInit(&ni);
1123 return send_reject (minor_status, output_token);
1128 gss_accept_sec_context
1129 (OM_uint32 * minor_status,
1130 gss_ctx_id_t * context_handle,
1131 const gss_cred_id_t acceptor_cred_handle,
1132 const gss_buffer_t input_token_buffer,
1133 const gss_channel_bindings_t input_chan_bindings,
1134 gss_name_t * src_name,
1135 gss_OID * mech_type,
1136 gss_buffer_t output_token,
1137 OM_uint32 * ret_flags,
1138 OM_uint32 * time_rec,
1139 gss_cred_id_t * delegated_cred_handle
1148 mech_len = gssapi_krb5_get_mech (input_token_buffer->value,
1149 input_token_buffer->length,
1152 /* This could be 'dce style' kerberos, where the OID is missing :-( */
1153 if ((mech_len < 0) || ((mech_len == GSS_KRB5_MECHANISM->length)
1154 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0))
1155 ret = gsskrb5_accept_sec_context(minor_status,
1157 acceptor_cred_handle,
1159 input_chan_bindings,
1165 delegated_cred_handle);
1166 else if (mech_len == GSS_SPNEGO_MECHANISM->length
1167 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0)
1168 ret = spnego_accept_sec_context(minor_status,
1170 acceptor_cred_handle,
1172 input_chan_bindings,
1178 delegated_cred_handle);
1180 return GSS_S_BAD_MECH;