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);
272 (*context_handle)->state = ACCEPTOR_READY;
273 (*context_handle)->more_flags |= OPEN;
275 return GSS_S_COMPLETE;
278 gsskrb5_acceptor_start
279 (OM_uint32 * minor_status,
280 gss_ctx_id_t * context_handle,
281 const gss_cred_id_t acceptor_cred_handle,
282 const gss_buffer_t input_token_buffer,
283 const gss_channel_bindings_t input_chan_bindings,
284 gss_name_t * src_name,
286 gss_buffer_t output_token,
287 OM_uint32 * ret_flags,
288 OM_uint32 * time_rec,
289 gss_cred_id_t * delegated_cred_handle
292 krb5_error_code kret;
293 OM_uint32 ret = GSS_S_COMPLETE;
295 krb5_flags ap_options;
297 krb5_ticket *ticket = NULL;
298 krb5_keytab keytab = NULL;
299 krb5_keyblock *keyblock = NULL;
303 krb5_data_zero (&fwd_data);
306 * We may, or may not, have an escapsulation.
308 ret = gssapi_krb5_decapsulate (minor_status,
315 /* No OID wrapping apparently available. */
316 indata.length = input_token_buffer->length;
317 indata.data = input_token_buffer->value;
321 * We need to get our keytab
323 if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
324 if (gssapi_krb5_keytab != NULL) {
325 keytab = gssapi_krb5_keytab;
327 } else if (acceptor_cred_handle->keytab != NULL) {
328 keytab = acceptor_cred_handle->keytab;
332 * We need to check the ticket and create the AP-REP packet
334 kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
335 &(*context_handle)->auth_context,
337 (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
344 *minor_status = kret;
345 gssapi_krb5_set_error_string ();
350 * We need to remember some data on the context_handle
352 (*context_handle)->ticket = ticket;
353 (*context_handle)->service_keyblock = keyblock;
354 (*context_handle)->lifetime = ticket->ticket.endtime;
357 * We need to copy the principal names to the context and the calling layer
359 kret = krb5_copy_principal(gssapi_krb5_context,
361 &(*context_handle)->source);
364 *minor_status = kret;
365 gssapi_krb5_set_error_string ();
368 kret = krb5_copy_principal (gssapi_krb5_context,
370 &(*context_handle)->target);
373 *minor_status = kret;
374 gssapi_krb5_set_error_string ();
379 * We need to setup some compat stuff, this assumes that context_handle->target is already set
381 ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
386 if (src_name != NULL) {
387 kret = krb5_copy_principal (gssapi_krb5_context,
392 *minor_status = kret;
393 gssapi_krb5_set_error_string ();
399 * We need to get the flags out of the 8003 checksum
402 krb5_authenticator authenticator;
404 kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
405 (*context_handle)->auth_context,
409 *minor_status = kret;
410 gssapi_krb5_set_error_string ();
414 ret = gssapi_krb5_verify_8003_checksum(minor_status,
416 authenticator->cksum,
419 krb5_free_authenticator(gssapi_krb5_context, &authenticator);
424 if(flags & GSS_C_MUTUAL_FLAG) {
427 gsskrb5_is_cfx(*context_handle, &is_cfx);
430 || (ap_options & AP_OPTS_USE_SUBKEY)) {
431 kret = krb5_auth_con_addflags(gssapi_krb5_context,
432 (*context_handle)->auth_context,
433 KRB5_AUTH_CONTEXT_USE_SUBKEY,
435 (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
438 kret = krb5_mk_rep(gssapi_krb5_context,
439 (*context_handle)->auth_context,
442 *minor_status = kret;
443 gssapi_krb5_set_error_string ();
444 return GSS_S_FAILURE;
447 if (!(flags & GSS_C_DCE_STYLE)) {
448 ret = gssapi_krb5_encapsulate(minor_status,
453 krb5_data_free (&outbuf);
456 output_token->length = outbuf.length;
457 output_token->value = outbuf.data;
462 * We need to send the flags back to the caller
464 flags |= GSS_C_TRANS_FLAG;
469 /* And remember them for later */
471 (*context_handle)->lifetime = ticket->ticket.endtime;
472 (*context_handle)->flags = flags;
473 (*context_handle)->more_flags |= OPEN;
476 *mech_type = GSS_KRB5_MECHANISM;
479 ret = gssapi_lifetime_left(minor_status,
480 (*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) {
490 (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
491 return GSS_S_CONTINUE_NEEDED;
494 return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
498 gsskrb5_acceptor_wait_for_dcestyle(
499 OM_uint32 * minor_status,
500 gss_ctx_id_t * context_handle,
501 const gss_cred_id_t acceptor_cred_handle,
502 const gss_buffer_t input_token_buffer,
503 const gss_channel_bindings_t input_chan_bindings,
504 gss_name_t * src_name,
506 gss_buffer_t output_token,
507 OM_uint32 * ret_flags,
508 OM_uint32 * time_rec,
509 gss_cred_id_t * delegated_cred_handle)
512 krb5_error_code kret;
514 OM_uint32 r_seq_number;
515 OM_uint32 l_seq_number;
517 /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
518 inbuf.length = input_token_buffer->length;
519 inbuf.data = input_token_buffer->value;
522 * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
523 * and then reset the remote seq_number to the old value
526 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
527 (*context_handle)->auth_context,
530 gssapi_krb5_set_error_string ();
531 *minor_status = kret;
532 return GSS_S_FAILURE;
535 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
536 (*context_handle)->auth_context,
539 gssapi_krb5_set_error_string ();
540 *minor_status = kret;
541 return GSS_S_FAILURE;
544 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
545 (*context_handle)->auth_context,
548 gssapi_krb5_set_error_string ();
549 *minor_status = kret;
550 return GSS_S_FAILURE;
554 /* We need to verify the AP_REP, but we need to flag that this
555 is DCE_STYLE, so don't check the timestamps this time
558 krb5_ap_rep_enc_part *repl;
561 kret = krb5_auth_con_removeflags(gssapi_krb5_context,
562 (*context_handle)->auth_context,
563 KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags);
564 if (kret) { /* Can't happen */
565 gssapi_krb5_set_error_string ();
566 *minor_status = kret;
567 return GSS_S_FAILURE;
570 kret = krb5_rd_rep(gssapi_krb5_context,
571 (*context_handle)->auth_context,
575 gssapi_krb5_set_error_string ();
576 *minor_status = kret;
577 return GSS_S_FAILURE;
580 /* Because the inbuf above is a final leg from client
581 * to server, we don't have a use for a 'reply'
583 krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
585 /* Do no harm, put the flags back */
586 kret = krb5_auth_con_setflags(gssapi_krb5_context,
587 (*context_handle)->auth_context,
589 if (kret) { /* Can't happen */
590 gssapi_krb5_set_error_string ();
591 *minor_status = kret;
592 return GSS_S_FAILURE;
596 /* We need to check the liftime */
598 OM_uint32 lifetime_rec;
600 ret = gssapi_lifetime_left(minor_status,
601 (*context_handle)->lifetime,
605 if (lifetime_rec == 0) {
606 return GSS_S_CONTEXT_EXPIRED;
609 if (time_rec) *time_rec = lifetime_rec;
612 /* We need to give the caller the flags which are in use */
613 if (ret_flags) *ret_flags = (*context_handle)->flags;
616 kret = krb5_copy_principal(gssapi_krb5_context,
617 (*context_handle)->source,
620 *minor_status = kret;
621 gssapi_krb5_set_error_string ();
622 return GSS_S_FAILURE;
627 * After the krb5_rd_rep() the remote and local seq_number should be the same,
628 * because the client just replies the seq_number from our AP-REP in its AP-REP,
629 * but then the client uses the seq_number from its AP-REQ for GSS_wrap()
632 OM_uint32 tmp_r_seq_number;
633 OM_uint32 tmp_l_seq_number;
635 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
636 (*context_handle)->auth_context,
639 gssapi_krb5_set_error_string ();
640 *minor_status = kret;
641 return GSS_S_FAILURE;
644 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
645 (*context_handle)->auth_context,
648 gssapi_krb5_set_error_string ();
649 *minor_status = kret;
650 return GSS_S_FAILURE;
654 * Here we check if the client has responsed with our local seq_number,
656 if (tmp_r_seq_number != tmp_l_seq_number) {
657 return GSS_S_UNSEQ_TOKEN;
662 * We need to reset the remote seq_number, because the client will use,
663 * the old one for the GSS_wrap() calls
666 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
667 (*context_handle)->auth_context,
670 gssapi_krb5_set_error_string ();
671 *minor_status = kret;
672 return GSS_S_FAILURE;
676 return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
680 gsskrb5_accept_sec_context
681 (OM_uint32 * minor_status,
682 gss_ctx_id_t * context_handle,
683 const gss_cred_id_t acceptor_cred_handle,
684 const gss_buffer_t input_token_buffer,
685 const gss_channel_bindings_t input_chan_bindings,
686 gss_name_t * src_name,
688 gss_buffer_t output_token,
689 OM_uint32 * ret_flags,
690 OM_uint32 * time_rec,
691 gss_cred_id_t * delegated_cred_handle
694 OM_uint32 ret = GSS_S_COMPLETE;
696 gss_ctx_id_t local_context;
700 krb5_data_zero (&fwd_data);
701 output_token->length = 0;
702 output_token->value = NULL;
704 if (src_name != NULL)
707 *mech_type = GSS_KRB5_MECHANISM;
709 if (*context_handle == GSS_C_NO_CONTEXT) {
710 ret = _gsskrb5_create_ctx(minor_status,
716 local_context = *context_handle;
720 * TODO: check the channel_bindings
721 * (above just sets them to krb5 layer)
724 HEIMDAL_MUTEX_lock(&(local_context)->ctx_id_mutex);
726 switch ((local_context)->state) {
728 ret = gsskrb5_acceptor_start(minor_status,
730 acceptor_cred_handle,
738 delegated_cred_handle);
740 case ACCEPTOR_WAIT_FOR_DCESTYLE:
741 ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
743 acceptor_cred_handle,
751 delegated_cred_handle);
754 /* this function should not be called after it has returned GSS_S_COMPLETE */
755 ret = GSS_S_BAD_STATUS;
758 /* TODO: is this correct here? --metze */
759 ret = GSS_S_BAD_STATUS;
763 HEIMDAL_MUTEX_unlock(&(local_context)->ctx_id_mutex);
765 if (*context_handle == GSS_C_NO_CONTEXT) {
766 if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
767 *context_handle = local_context;
769 gss_delete_sec_context(minor_status,
779 code_NegTokenArg(OM_uint32 *minor_status,
780 const NegTokenTarg *targ,
786 size_t buf_size, buf_len;
789 buf = malloc(buf_size);
791 *minor_status = ENOMEM;
792 return GSS_S_FAILURE;
796 ret = encode_NegTokenTarg(buf + buf_size - 1,
802 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
813 if (ret == ASN1_OVERFLOW) {
817 tmp = realloc (buf, buf_size);
819 *minor_status = ENOMEM;
821 return GSS_S_FAILURE;
827 return GSS_S_FAILURE;
830 } while (ret == ASN1_OVERFLOW);
832 data->data = buf + buf_size - buf_len;
833 data->length = buf_len;
835 return GSS_S_COMPLETE;
839 send_reject (OM_uint32 *minor_status,
840 gss_buffer_t output_token)
847 ALLOC(targ.negResult, 1);
848 if (targ.negResult == NULL) {
849 *minor_status = ENOMEM;
850 return GSS_S_FAILURE;
852 *(targ.negResult) = reject;
853 targ.supportedMech = NULL;
854 targ.responseToken = NULL;
855 targ.mechListMIC = NULL;
857 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
858 free_NegTokenTarg(&targ);
863 ret = _gssapi_encapsulate(minor_status,
866 GSS_SPNEGO_MECHANISM);
868 output_token->value = malloc(data.length);
869 if (output_token->value == NULL) {
870 *minor_status = ENOMEM;
873 output_token->length = data.length;
874 memcpy(output_token->value, data.data, output_token->length);
880 return GSS_S_BAD_MECH;
884 send_accept (OM_uint32 *minor_status,
885 OM_uint32 major_status,
886 gss_buffer_t output_token,
887 gss_buffer_t mech_token,
888 gss_ctx_id_t context_handle,
889 const MechTypeList *mechtypelist)
895 gss_buffer_desc mech_buf, mech_mic_buf;
896 krb5_boolean require_mic;
898 memset(&targ, 0, sizeof(targ));
899 ALLOC(targ.negResult, 1);
900 if (targ.negResult == NULL) {
901 *minor_status = ENOMEM;
902 return GSS_S_FAILURE;
904 *(targ.negResult) = accept_completed;
906 ALLOC(targ.supportedMech, 1);
907 if (targ.supportedMech == NULL) {
908 free_NegTokenTarg(&targ);
909 *minor_status = ENOMEM;
910 return GSS_S_FAILURE;
913 ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
914 GSS_KRB5_MECHANISM->length,
918 free_NegTokenTarg(&targ);
919 *minor_status = ENOMEM;
920 return GSS_S_FAILURE;
923 if (mech_token != NULL && mech_token->length != 0) {
924 ALLOC(targ.responseToken, 1);
925 if (targ.responseToken == NULL) {
926 free_NegTokenTarg(&targ);
927 *minor_status = ENOMEM;
928 return GSS_S_FAILURE;
930 targ.responseToken->length = mech_token->length;
931 targ.responseToken->data = mech_token->value;
932 mech_token->length = 0;
933 mech_token->value = NULL;
935 targ.responseToken = NULL;
938 ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
941 free_NegTokenTarg(&targ);
945 if (major_status == GSS_S_COMPLETE && require_mic) {
948 ALLOC(targ.mechListMIC, 1);
949 if (targ.mechListMIC == NULL) {
950 free_NegTokenTarg(&targ);
951 *minor_status = ENOMEM;
952 return GSS_S_FAILURE;
955 ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
956 mechtypelist, &buf_len, ret);
958 free_NegTokenTarg(&targ);
961 if (mech_buf.length != buf_len)
964 ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
966 free (mech_buf.value);
968 free_NegTokenTarg(&targ);
972 targ.mechListMIC->length = mech_mic_buf.length;
973 targ.mechListMIC->data = mech_mic_buf.value;
975 targ.mechListMIC = NULL;
977 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
978 free_NegTokenTarg(&targ);
983 ret = _gssapi_encapsulate(minor_status,
986 GSS_SPNEGO_MECHANISM);
988 output_token->value = malloc(data.length);
989 if (output_token->value == NULL) {
990 *minor_status = ENOMEM;
993 output_token->length = data.length;
994 memcpy(output_token->value, data.data, output_token->length);
1000 return GSS_S_COMPLETE;
1004 spnego_accept_sec_context
1005 (OM_uint32 * minor_status,
1006 gss_ctx_id_t * context_handle,
1007 const gss_cred_id_t acceptor_cred_handle,
1008 const gss_buffer_t input_token_buffer,
1009 const gss_channel_bindings_t input_chan_bindings,
1010 gss_name_t * src_name,
1011 gss_OID * mech_type,
1012 gss_buffer_t output_token,
1013 OM_uint32 * ret_flags,
1014 OM_uint32 * time_rec,
1015 gss_cred_id_t * delegated_cred_handle
1018 OM_uint32 ret, ret2;
1026 output_token->length = 0;
1027 output_token->value = NULL;
1029 ret = _gssapi_decapsulate (minor_status,
1032 GSS_SPNEGO_MECHANISM);
1036 ret = der_match_tag_and_length(data.data, data.length,
1037 ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
1041 if(len > data.length - taglen)
1042 return ASN1_OVERRUN;
1044 ret = decode_NegTokenInit((const char *)data.data + taglen, len,
1047 return GSS_S_DEFECTIVE_TOKEN;
1049 if (ni.mechTypes == NULL) {
1050 free_NegTokenInit(&ni);
1051 return send_reject (minor_status, output_token);
1054 for (i = 0; !found && i < ni.mechTypes->len; ++i) {
1058 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
1060 &ni.mechTypes->val[i],
1063 free_NegTokenInit(&ni);
1064 return GSS_S_DEFECTIVE_TOKEN;
1066 if (mech_len == GSS_KRB5_MECHANISM->length
1067 && memcmp(GSS_KRB5_MECHANISM->elements,
1068 mechbuf + sizeof(mechbuf) - mech_len,
1073 gss_buffer_desc ibuf, obuf;
1074 gss_buffer_t ot = NULL;
1077 if (ni.mechToken != NULL) {
1078 ibuf.length = ni.mechToken->length;
1079 ibuf.value = ni.mechToken->data;
1081 ret = gsskrb5_accept_sec_context(&minor,
1083 acceptor_cred_handle,
1085 input_chan_bindings,
1091 delegated_cred_handle);
1092 if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
1095 free_NegTokenInit(&ni);
1096 send_reject (minor_status, output_token);
1100 ret2 = send_accept (minor_status, ret, output_token, ot,
1101 *context_handle, ni.mechTypes);
1102 if (ret2 != GSS_S_COMPLETE)
1105 gss_release_buffer(&minor, ot);
1106 free_NegTokenInit(&ni);
1109 free_NegTokenInit(&ni);
1110 return send_reject (minor_status, output_token);
1115 gss_accept_sec_context
1116 (OM_uint32 * minor_status,
1117 gss_ctx_id_t * context_handle,
1118 const gss_cred_id_t acceptor_cred_handle,
1119 const gss_buffer_t input_token_buffer,
1120 const gss_channel_bindings_t input_chan_bindings,
1121 gss_name_t * src_name,
1122 gss_OID * mech_type,
1123 gss_buffer_t output_token,
1124 OM_uint32 * ret_flags,
1125 OM_uint32 * time_rec,
1126 gss_cred_id_t * delegated_cred_handle
1135 mech_len = gssapi_krb5_get_mech (input_token_buffer->value,
1136 input_token_buffer->length,
1139 /* This could be 'dce style' kerberos, where the OID is missing :-( */
1140 if ((mech_len < 0) || ((mech_len == GSS_KRB5_MECHANISM->length)
1141 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0))
1142 ret = gsskrb5_accept_sec_context(minor_status,
1144 acceptor_cred_handle,
1146 input_chan_bindings,
1152 delegated_cred_handle);
1153 else if (mech_len == GSS_SPNEGO_MECHANISM->length
1154 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0)
1155 ret = spnego_accept_sec_context(minor_status,
1157 acceptor_cred_handle,
1159 input_chan_bindings,
1165 delegated_cred_handle);
1167 return GSS_S_BAD_MECH;