x
[heimdal.git] / lib / gssapi / krb5 / accept_sec_context.c
blobda3a4edc1b6e4a66aabb486f30aad33ca2bbdfd6
1 /*
2 * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
31 * SUCH DAMAGE.
34 #include "gssapi_locl.h"
36 RCSID("$Id$");
38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39 krb5_keytab gssapi_krb5_keytab;
41 OM_uint32
42 gsskrb5_register_acceptor_identity (const char *identity)
44 krb5_error_code ret;
46 ret = gssapi_krb5_init();
47 if(ret)
48 return GSS_S_FAILURE;
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);
58 } else {
59 char *p;
61 asprintf(&p, "FILE:%s", identity);
62 if(p == NULL) {
63 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
64 return GSS_S_FAILURE;
66 ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
67 free(p);
69 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
70 if(ret)
71 return GSS_S_FAILURE;
72 return GSS_S_COMPLETE;
75 void
76 gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx)
78 krb5_keyblock *key;
79 int acceptor = (context_handle->more_flags & LOCAL) == 0;
81 if (acceptor) {
82 if (context_handle->auth_context->local_subkey)
83 key = context_handle->auth_context->local_subkey;
84 else
85 key = context_handle->auth_context->remote_subkey;
86 } else {
87 if (context_handle->auth_context->remote_subkey)
88 key = context_handle->auth_context->remote_subkey;
89 else
90 key = context_handle->auth_context->local_subkey;
92 if (key == NULL)
93 key = context_handle->auth_context->keyblock;
95 if (key == NULL)
96 return;
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:
106 break;
107 default :
108 *is_cfx = 1;
109 if ((acceptor && context_handle->auth_context->local_subkey) ||
110 (!acceptor && context_handle->auth_context->remote_subkey))
111 context_handle->more_flags |= ACCEPTOR_SUBKEY;
112 break;
117 static OM_uint32
118 gsskrb5_accept_delegated_token
119 (OM_uint32 * minor_status,
120 gss_ctx_id_t * context_handle,
121 krb5_data *fwd_data,
122 OM_uint32 *flags,
123 krb5_principal principal,
124 gss_cred_id_t * delegated_cred_handle
127 krb5_ccache ccache = NULL;
128 krb5_error_code kret;
129 int32_t ac_flags, ret;
130 gss_cred_id_t handle = NULL;
132 if (delegated_cred_handle == NULL) {
133 /* XXX Create a new delegated_cred_handle? */
135 ret = 0;
137 kret = krb5_cc_default (gssapi_krb5_context, &ccache);
138 if (kret) {
139 *flags &= ~GSS_C_DELEG_FLAG;
140 goto end_fwd;
142 } else {
144 *delegated_cred_handle = NULL;
146 handle = calloc(1, sizeof(*handle));
147 if (handle == NULL) {
148 ret = GSS_S_FAILURE;
149 *minor_status = ENOMEM;
150 krb5_set_error_string(gssapi_krb5_context, "out of memory");
151 gssapi_krb5_set_error_string();
152 *flags &= ~GSS_C_DELEG_FLAG;
153 goto end_fwd;
155 if ((ret = gss_duplicate_name(minor_status, principal,
156 &handle->principal)) != 0) {
157 *flags &= ~GSS_C_DELEG_FLAG;
158 ret = 0;
159 goto end_fwd;
161 kret = krb5_cc_gen_new (gssapi_krb5_context,
162 &krb5_mcc_ops,
163 &handle->ccache);
164 if (kret) {
165 *flags &= ~GSS_C_DELEG_FLAG;
166 ret = 0;
167 goto end_fwd;
169 ccache = handle->ccache;
171 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
172 if (ret) {
173 *flags &= ~GSS_C_DELEG_FLAG;
174 goto end_fwd;
176 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
177 &handle->mechanisms);
178 if (ret) {
179 *flags &= ~GSS_C_DELEG_FLAG;
180 goto end_fwd;
184 kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal);
185 if (kret) {
186 *flags &= ~GSS_C_DELEG_FLAG;
187 ret = 0;
188 goto end_fwd;
191 krb5_auth_con_removeflags(gssapi_krb5_context,
192 (*context_handle)->auth_context,
193 KRB5_AUTH_CONTEXT_DO_TIME,
194 &ac_flags);
195 kret = krb5_rd_cred2(gssapi_krb5_context,
196 (*context_handle)->auth_context,
197 ccache,
198 fwd_data);
199 if (kret)
200 gssapi_krb5_set_error_string();
201 krb5_auth_con_setflags(gssapi_krb5_context,
202 (*context_handle)->auth_context,
203 ac_flags);
204 if (kret) {
205 *flags &= ~GSS_C_DELEG_FLAG;
206 ret = GSS_S_FAILURE;
207 *minor_status = kret;
208 goto end_fwd;
210 end_fwd:
211 /* if there was some kind of failure, clean up internal structures */
212 if ((*flags & GSS_C_DELEG_FLAG) == 0) {
213 if (handle) {
214 if (handle->principal)
215 gss_release_name(minor_status, &handle->principal);
216 if (handle->mechanisms)
217 gss_release_oid_set(NULL, &handle->mechanisms);
218 if (handle->ccache)
219 krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
220 free(handle);
221 handle = NULL;
224 if (delegated_cred_handle == NULL) {
225 if (ccache)
226 krb5_cc_close(gssapi_krb5_context, ccache);
228 if (handle)
229 *delegated_cred_handle = handle;
231 return ret;
235 static OM_uint32
236 gsskrb5_accept_sec_context
237 (OM_uint32 * minor_status,
238 gss_ctx_id_t * context_handle,
239 const gss_cred_id_t acceptor_cred_handle,
240 const gss_buffer_t input_token_buffer,
241 const gss_channel_bindings_t input_chan_bindings,
242 gss_name_t * src_name,
243 gss_OID * mech_type,
244 gss_buffer_t output_token,
245 OM_uint32 * ret_flags,
246 OM_uint32 * time_rec,
247 gss_cred_id_t * delegated_cred_handle
250 krb5_error_code kret;
251 OM_uint32 ret = GSS_S_COMPLETE;
252 krb5_data indata;
253 krb5_flags ap_options;
254 OM_uint32 flags;
255 krb5_ticket *ticket = NULL;
256 krb5_keytab keytab = NULL;
257 krb5_data fwd_data;
258 OM_uint32 minor;
259 int is_cfx = 0;
261 GSSAPI_KRB5_INIT();
263 krb5_data_zero (&fwd_data);
264 output_token->length = 0;
265 output_token->value = NULL;
267 if (src_name != NULL)
268 *src_name = NULL;
269 if (mech_type)
270 *mech_type = GSS_KRB5_MECHANISM;
272 if (*context_handle == GSS_C_NO_CONTEXT) {
273 *context_handle = malloc(sizeof(**context_handle));
274 if (*context_handle == GSS_C_NO_CONTEXT) {
275 *minor_status = ENOMEM;
276 return GSS_S_FAILURE;
280 HEIMDAL_MUTEX_init(&(*context_handle)->ctx_id_mutex);
281 (*context_handle)->auth_context = NULL;
282 (*context_handle)->source = NULL;
283 (*context_handle)->target = NULL;
284 (*context_handle)->flags = 0;
285 (*context_handle)->more_flags = 0;
286 (*context_handle)->ticket = NULL;
287 (*context_handle)->lifetime = GSS_C_INDEFINITE;
288 (*context_handle)->order = NULL;
290 kret = krb5_auth_con_init (gssapi_krb5_context,
291 &(*context_handle)->auth_context);
292 if (kret) {
293 ret = GSS_S_FAILURE;
294 *minor_status = kret;
295 gssapi_krb5_set_error_string ();
296 goto failure;
299 if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
300 && input_chan_bindings->application_data.length ==
301 2 * sizeof((*context_handle)->auth_context->local_port)
304 /* Port numbers are expected to be in application_data.value,
305 * initator's port first */
307 krb5_address initiator_addr, acceptor_addr;
309 memset(&initiator_addr, 0, sizeof(initiator_addr));
310 memset(&acceptor_addr, 0, sizeof(acceptor_addr));
312 (*context_handle)->auth_context->remote_port =
313 *(int16_t *) input_chan_bindings->application_data.value;
315 (*context_handle)->auth_context->local_port =
316 *((int16_t *) input_chan_bindings->application_data.value + 1);
319 kret = gss_address_to_krb5addr(input_chan_bindings->acceptor_addrtype,
320 &input_chan_bindings->acceptor_address,
321 (*context_handle)->auth_context->local_port,
322 &acceptor_addr);
323 if (kret) {
324 gssapi_krb5_set_error_string ();
325 ret = GSS_S_BAD_BINDINGS;
326 *minor_status = kret;
327 goto failure;
330 kret = gss_address_to_krb5addr(input_chan_bindings->initiator_addrtype,
331 &input_chan_bindings->initiator_address,
332 (*context_handle)->auth_context->remote_port,
333 &initiator_addr);
334 if (kret) {
335 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
336 gssapi_krb5_set_error_string ();
337 ret = GSS_S_BAD_BINDINGS;
338 *minor_status = kret;
339 goto failure;
342 kret = krb5_auth_con_setaddrs(gssapi_krb5_context,
343 (*context_handle)->auth_context,
344 &acceptor_addr, /* local address */
345 &initiator_addr); /* remote address */
347 krb5_free_address (gssapi_krb5_context, &initiator_addr);
348 krb5_free_address (gssapi_krb5_context, &acceptor_addr);
350 #if 0
351 free(input_chan_bindings->application_data.value);
352 input_chan_bindings->application_data.value = NULL;
353 input_chan_bindings->application_data.length = 0;
354 #endif
356 if (kret) {
357 gssapi_krb5_set_error_string ();
358 ret = GSS_S_BAD_BINDINGS;
359 *minor_status = kret;
360 goto failure;
364 krb5_auth_con_addflags(gssapi_krb5_context,
365 (*context_handle)->auth_context,
366 KRB5_AUTH_CONTEXT_DO_SEQUENCE,
367 NULL);
369 ret = gssapi_krb5_decapsulate (minor_status,
370 input_token_buffer,
371 &indata,
372 "\x01\x00",
373 GSS_KRB5_MECHANISM);
374 if (ret)
375 goto failure;
377 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
379 if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
380 if (gssapi_krb5_keytab != NULL) {
381 keytab = gssapi_krb5_keytab;
383 } else if (acceptor_cred_handle->keytab != NULL) {
384 keytab = acceptor_cred_handle->keytab;
387 kret = krb5_rd_req (gssapi_krb5_context,
388 &(*context_handle)->auth_context,
389 &indata,
390 (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL
391 : acceptor_cred_handle->principal,
392 keytab,
393 &ap_options,
394 &ticket);
396 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
398 if (kret) {
399 ret = GSS_S_FAILURE;
400 *minor_status = kret;
401 gssapi_krb5_set_error_string ();
402 goto failure;
405 kret = krb5_copy_principal (gssapi_krb5_context,
406 ticket->client,
407 &(*context_handle)->source);
408 if (kret) {
409 ret = GSS_S_FAILURE;
410 *minor_status = kret;
411 gssapi_krb5_set_error_string ();
412 goto failure;
415 kret = krb5_copy_principal (gssapi_krb5_context,
416 ticket->server,
417 &(*context_handle)->target);
418 if (kret) {
419 ret = GSS_S_FAILURE;
420 *minor_status = kret;
421 gssapi_krb5_set_error_string ();
422 goto failure;
425 ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
426 if (ret)
427 goto failure;
429 if (src_name != NULL) {
430 kret = krb5_copy_principal (gssapi_krb5_context,
431 ticket->client,
432 src_name);
433 if (kret) {
434 ret = GSS_S_FAILURE;
435 *minor_status = kret;
436 gssapi_krb5_set_error_string ();
437 goto failure;
442 krb5_authenticator authenticator;
444 kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
445 (*context_handle)->auth_context,
446 &authenticator);
447 if(kret) {
448 ret = GSS_S_FAILURE;
449 *minor_status = kret;
450 gssapi_krb5_set_error_string ();
451 goto failure;
454 ret = gssapi_krb5_verify_8003_checksum(minor_status,
455 input_chan_bindings,
456 authenticator->cksum,
457 &flags,
458 &fwd_data);
459 krb5_free_authenticator(gssapi_krb5_context, &authenticator);
460 if (ret)
461 goto failure;
464 flags |= GSS_C_TRANS_FLAG;
466 if (ret_flags)
467 *ret_flags = flags;
468 (*context_handle)->lifetime = ticket->ticket.endtime;
469 (*context_handle)->flags = flags;
470 (*context_handle)->more_flags |= OPEN;
472 if (mech_type)
473 *mech_type = GSS_KRB5_MECHANISM;
475 if (time_rec) {
476 ret = gssapi_lifetime_left(minor_status,
477 (*context_handle)->lifetime,
478 time_rec);
479 if (ret)
480 goto failure;
483 gsskrb5_is_cfx(*context_handle, &is_cfx);
485 if(flags & GSS_C_MUTUAL_FLAG) {
486 krb5_data outbuf;
488 if (is_cfx != 0
489 || (ap_options & AP_OPTS_USE_SUBKEY)) {
490 kret = krb5_auth_con_addflags(gssapi_krb5_context,
491 (*context_handle)->auth_context,
492 KRB5_AUTH_CONTEXT_USE_SUBKEY,
493 NULL);
494 (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
497 kret = krb5_mk_rep (gssapi_krb5_context,
498 (*context_handle)->auth_context,
499 &outbuf);
500 if (kret) {
501 ret = GSS_S_FAILURE;
502 *minor_status = kret;
503 gssapi_krb5_set_error_string ();
504 goto failure;
506 ret = gssapi_krb5_encapsulate (minor_status,
507 &outbuf,
508 output_token,
509 "\x02\x00",
510 GSS_KRB5_MECHANISM);
511 krb5_data_free (&outbuf);
512 if (ret)
513 goto failure;
516 (*context_handle)->ticket = ticket;
519 int32_t seq_number;
521 krb5_auth_getremoteseqnumber (gssapi_krb5_context,
522 (*context_handle)->auth_context,
523 &seq_number);
524 ret = _gssapi_msg_order_create(minor_status,
525 &(*context_handle)->order,
526 _gssapi_msg_order_f(flags),
527 seq_number, 0, is_cfx);
528 if (ret)
529 goto failure;
531 if ((flags & GSS_C_MUTUAL_FLAG) == 0 && _gssapi_msg_order_f(flags)) {
532 krb5_auth_con_setlocalseqnumber (gssapi_krb5_context,
533 (*context_handle)->auth_context,
534 seq_number);
538 if (fwd_data.length > 0) {
540 if (flags & GSS_C_DELEG_FLAG) {
541 ret = gsskrb5_accept_delegated_token(minor_status,
542 context_handle,
543 &fwd_data,
544 &flags,
545 ticket->client,
546 delegated_cred_handle);
547 if (ret)
548 goto failure;
550 free(fwd_data.data);
551 krb5_data_zero(&fwd_data);
554 *minor_status = 0;
555 return GSS_S_COMPLETE;
557 failure:
558 if (fwd_data.length > 0)
559 free(fwd_data.data);
560 if (ticket != NULL)
561 krb5_free_ticket (gssapi_krb5_context, ticket);
562 krb5_auth_con_free (gssapi_krb5_context,
563 (*context_handle)->auth_context);
564 if((*context_handle)->source)
565 krb5_free_principal (gssapi_krb5_context,
566 (*context_handle)->source);
567 if((*context_handle)->target)
568 krb5_free_principal (gssapi_krb5_context,
569 (*context_handle)->target);
570 if((*context_handle)->order)
571 _gssapi_msg_order_destroy(&(*context_handle)->order);
572 HEIMDAL_MUTEX_destroy(&(*context_handle)->ctx_id_mutex);
573 free (*context_handle);
574 if (src_name != NULL) {
575 gss_release_name (&minor, src_name);
576 *src_name = NULL;
578 *context_handle = GSS_C_NO_CONTEXT;
579 return ret;
582 static OM_uint32
583 code_NegTokenArg(OM_uint32 *minor_status,
584 const NegTokenTarg *targ,
585 krb5_data *data,
586 u_char **ret_buf)
588 OM_uint32 ret;
589 u_char *buf;
590 size_t buf_size, buf_len;
592 buf_size = 1024;
593 buf = malloc(buf_size);
594 if (buf == NULL) {
595 *minor_status = ENOMEM;
596 return GSS_S_FAILURE;
599 do {
600 ret = encode_NegTokenTarg(buf + buf_size - 1,
601 buf_size,
602 targ, &buf_len);
603 if (ret == 0) {
604 size_t tmp;
606 ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
607 buf_size - buf_len,
608 buf_len,
609 ASN1_C_CONTEXT,
610 CONS,
612 &tmp);
613 if (ret == 0)
614 buf_len += tmp;
616 if (ret) {
617 if (ret == ASN1_OVERFLOW) {
618 u_char *tmp;
620 buf_size *= 2;
621 tmp = realloc (buf, buf_size);
622 if (tmp == NULL) {
623 *minor_status = ENOMEM;
624 free(buf);
625 return GSS_S_FAILURE;
627 buf = tmp;
628 } else {
629 *minor_status = ret;
630 free(buf);
631 return GSS_S_FAILURE;
634 } while (ret == ASN1_OVERFLOW);
636 data->data = buf + buf_size - buf_len;
637 data->length = buf_len;
638 *ret_buf = buf;
639 return GSS_S_COMPLETE;
642 static OM_uint32
643 send_reject (OM_uint32 *minor_status,
644 gss_buffer_t output_token)
646 NegTokenTarg targ;
647 krb5_data data;
648 u_char *buf;
649 OM_uint32 ret;
651 ALLOC(targ.negResult, 1);
652 if (targ.negResult == NULL) {
653 *minor_status = ENOMEM;
654 return GSS_S_FAILURE;
656 *(targ.negResult) = reject;
657 targ.supportedMech = NULL;
658 targ.responseToken = NULL;
659 targ.mechListMIC = NULL;
661 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
662 free_NegTokenTarg(&targ);
663 if (ret)
664 return ret;
666 #if 0
667 ret = _gssapi_encapsulate(minor_status,
668 &data,
669 output_token,
670 GSS_SPNEGO_MECHANISM);
671 #else
672 output_token->value = malloc(data.length);
673 if (output_token->value == NULL) {
674 *minor_status = ENOMEM;
675 ret = GSS_S_FAILURE;
676 } else {
677 output_token->length = data.length;
678 memcpy(output_token->value, data.data, output_token->length);
680 #endif
681 free(buf);
682 if (ret)
683 return ret;
684 return GSS_S_BAD_MECH;
687 static OM_uint32
688 send_accept (OM_uint32 *minor_status,
689 OM_uint32 major_status,
690 gss_buffer_t output_token,
691 gss_buffer_t mech_token,
692 gss_ctx_id_t context_handle,
693 const MechTypeList *mechtypelist)
695 NegTokenTarg targ;
696 krb5_data data;
697 u_char *buf;
698 OM_uint32 ret;
699 gss_buffer_desc mech_buf, mech_mic_buf;
700 krb5_boolean require_mic;
702 memset(&targ, 0, sizeof(targ));
703 ALLOC(targ.negResult, 1);
704 if (targ.negResult == NULL) {
705 *minor_status = ENOMEM;
706 return GSS_S_FAILURE;
708 *(targ.negResult) = accept_completed;
710 ALLOC(targ.supportedMech, 1);
711 if (targ.supportedMech == NULL) {
712 free_NegTokenTarg(&targ);
713 *minor_status = ENOMEM;
714 return GSS_S_FAILURE;
717 ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
718 GSS_KRB5_MECHANISM->length,
719 targ.supportedMech,
720 NULL);
721 if (ret) {
722 free_NegTokenTarg(&targ);
723 *minor_status = ENOMEM;
724 return GSS_S_FAILURE;
727 if (mech_token != NULL && mech_token->length != 0) {
728 ALLOC(targ.responseToken, 1);
729 if (targ.responseToken == NULL) {
730 free_NegTokenTarg(&targ);
731 *minor_status = ENOMEM;
732 return GSS_S_FAILURE;
734 targ.responseToken->length = mech_token->length;
735 targ.responseToken->data = mech_token->value;
736 mech_token->length = 0;
737 mech_token->value = NULL;
738 } else {
739 targ.responseToken = NULL;
742 ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
743 &require_mic);
744 if (ret) {
745 free_NegTokenTarg(&targ);
746 return ret;
749 if (major_status == GSS_S_COMPLETE && require_mic) {
750 size_t buf_len;
752 ALLOC(targ.mechListMIC, 1);
753 if (targ.mechListMIC == NULL) {
754 free_NegTokenTarg(&targ);
755 *minor_status = ENOMEM;
756 return GSS_S_FAILURE;
759 ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
760 mechtypelist, &buf_len, ret);
761 if (ret) {
762 free_NegTokenTarg(&targ);
763 return ret;
765 if (mech_buf.length != buf_len)
766 abort();
768 ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
769 &mech_mic_buf);
770 free (mech_buf.value);
771 if (ret) {
772 free_NegTokenTarg(&targ);
773 return ret;
776 targ.mechListMIC->length = mech_mic_buf.length;
777 targ.mechListMIC->data = mech_mic_buf.value;
778 } else
779 targ.mechListMIC = NULL;
781 ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
782 free_NegTokenTarg(&targ);
783 if (ret)
784 return ret;
786 #if 0
787 ret = _gssapi_encapsulate(minor_status,
788 &data,
789 output_token,
790 GSS_SPNEGO_MECHANISM);
791 #else
792 output_token->value = malloc(data.length);
793 if (output_token->value == NULL) {
794 *minor_status = ENOMEM;
795 ret = GSS_S_FAILURE;
796 } else {
797 output_token->length = data.length;
798 memcpy(output_token->value, data.data, output_token->length);
800 #endif
801 free(buf);
802 if (ret)
803 return ret;
804 return GSS_S_COMPLETE;
807 static OM_uint32
808 spnego_accept_sec_context
809 (OM_uint32 * minor_status,
810 gss_ctx_id_t * context_handle,
811 const gss_cred_id_t acceptor_cred_handle,
812 const gss_buffer_t input_token_buffer,
813 const gss_channel_bindings_t input_chan_bindings,
814 gss_name_t * src_name,
815 gss_OID * mech_type,
816 gss_buffer_t output_token,
817 OM_uint32 * ret_flags,
818 OM_uint32 * time_rec,
819 gss_cred_id_t * delegated_cred_handle
822 OM_uint32 ret, ret2;
823 NegTokenInit ni;
824 size_t ni_len;
825 int i;
826 int found = 0;
827 krb5_data data;
828 size_t len, taglen;
830 output_token->length = 0;
831 output_token->value = NULL;
833 ret = _gssapi_decapsulate (minor_status,
834 input_token_buffer,
835 &data,
836 GSS_SPNEGO_MECHANISM);
837 if (ret)
838 return ret;
840 ret = der_match_tag_and_length(data.data, data.length,
841 ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
842 if (ret)
843 return ret;
845 if(len > data.length - taglen)
846 return ASN1_OVERRUN;
848 ret = decode_NegTokenInit((const char *)data.data + taglen, len,
849 &ni, &ni_len);
850 if (ret)
851 return GSS_S_DEFECTIVE_TOKEN;
853 if (ni.mechTypes == NULL) {
854 free_NegTokenInit(&ni);
855 return send_reject (minor_status, output_token);
858 for (i = 0; !found && i < ni.mechTypes->len; ++i) {
859 char mechbuf[17];
860 size_t mech_len;
862 ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
863 sizeof(mechbuf),
864 &ni.mechTypes->val[i],
865 &mech_len);
866 if (ret) {
867 free_NegTokenInit(&ni);
868 return GSS_S_DEFECTIVE_TOKEN;
870 if (mech_len == GSS_KRB5_MECHANISM->length
871 && memcmp(GSS_KRB5_MECHANISM->elements,
872 mechbuf + sizeof(mechbuf) - mech_len,
873 mech_len) == 0)
874 found = 1;
876 if (found) {
877 gss_buffer_desc ibuf, obuf;
878 gss_buffer_t ot = NULL;
879 OM_uint32 minor;
881 if (ni.mechToken != NULL) {
882 ibuf.length = ni.mechToken->length;
883 ibuf.value = ni.mechToken->data;
885 ret = gsskrb5_accept_sec_context(&minor,
886 context_handle,
887 acceptor_cred_handle,
888 &ibuf,
889 input_chan_bindings,
890 src_name,
891 mech_type,
892 &obuf,
893 ret_flags,
894 time_rec,
895 delegated_cred_handle);
896 if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
897 ot = &obuf;
898 } else {
899 free_NegTokenInit(&ni);
900 send_reject (minor_status, output_token);
901 return ret;
904 ret2 = send_accept (minor_status, ret, output_token, ot,
905 *context_handle, ni.mechTypes);
906 if (ret2 != GSS_S_COMPLETE)
907 ret = ret2;
908 if (ot != NULL)
909 gss_release_buffer(&minor, ot);
910 free_NegTokenInit(&ni);
911 return ret;
912 } else {
913 free_NegTokenInit(&ni);
914 return send_reject (minor_status, output_token);
918 OM_uint32
919 gss_accept_sec_context
920 (OM_uint32 * minor_status,
921 gss_ctx_id_t * context_handle,
922 const gss_cred_id_t acceptor_cred_handle,
923 const gss_buffer_t input_token_buffer,
924 const gss_channel_bindings_t input_chan_bindings,
925 gss_name_t * src_name,
926 gss_OID * mech_type,
927 gss_buffer_t output_token,
928 OM_uint32 * ret_flags,
929 OM_uint32 * time_rec,
930 gss_cred_id_t * delegated_cred_handle
933 OM_uint32 ret;
934 ssize_t mech_len;
935 const u_char *p;
937 *minor_status = 0;
939 mech_len = gssapi_krb5_get_mech (input_token_buffer->value,
940 input_token_buffer->length,
941 &p);
942 if (mech_len < 0)
943 return GSS_S_DEFECTIVE_TOKEN;
944 if (mech_len == GSS_KRB5_MECHANISM->length
945 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0)
946 ret = gsskrb5_accept_sec_context(minor_status,
947 context_handle,
948 acceptor_cred_handle,
949 input_token_buffer,
950 input_chan_bindings,
951 src_name,
952 mech_type,
953 output_token,
954 ret_flags,
955 time_rec,
956 delegated_cred_handle);
957 else if (mech_len == GSS_SPNEGO_MECHANISM->length
958 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0)
959 ret = spnego_accept_sec_context(minor_status,
960 context_handle,
961 acceptor_cred_handle,
962 input_token_buffer,
963 input_chan_bindings,
964 src_name,
965 mech_type,
966 output_token,
967 ret_flags,
968 time_rec,
969 delegated_cred_handle);
970 else
971 return GSS_S_BAD_MECH;
973 return ret;