Check the GSS-API checksum exists before trying to use it [CVE-2010-1321]
[heimdal.git] / lib / gssapi / krb5 / accept_sec_context.c
blobbbfb0f9b77135f9d9ca8f374937ae1b362b43a44
1 /*
2 * Copyright (c) 1997 - 2006 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 "gsskrb5_locl.h"
36 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
37 krb5_keytab _gsskrb5_keytab;
39 OM_uint32
40 _gsskrb5_register_acceptor_identity (const char *identity)
42 krb5_context context;
43 krb5_error_code ret;
45 ret = _gsskrb5_init(&context);
46 if(ret)
47 return GSS_S_FAILURE;
49 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
51 if(_gsskrb5_keytab != NULL) {
52 krb5_kt_close(context, _gsskrb5_keytab);
53 _gsskrb5_keytab = NULL;
55 if (identity == NULL) {
56 ret = krb5_kt_default(context, &_gsskrb5_keytab);
57 } else {
58 char *p;
60 asprintf(&p, "FILE:%s", identity);
61 if(p == NULL) {
62 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
63 return GSS_S_FAILURE;
65 ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab);
66 free(p);
68 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
69 if(ret)
70 return GSS_S_FAILURE;
71 return GSS_S_COMPLETE;
74 void
75 _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)
77 krb5_error_code ret;
78 krb5_keyblock *key;
80 if (acceptor) {
81 if (ctx->auth_context->local_subkey)
82 key = ctx->auth_context->local_subkey;
83 else
84 key = ctx->auth_context->remote_subkey;
85 } else {
86 if (ctx->auth_context->remote_subkey)
87 key = ctx->auth_context->remote_subkey;
88 else
89 key = ctx->auth_context->local_subkey;
91 if (key == NULL)
92 key = ctx->auth_context->keyblock;
94 if (key == NULL)
95 return;
97 switch (key->keytype) {
98 case ETYPE_DES_CBC_CRC:
99 case ETYPE_DES_CBC_MD4:
100 case ETYPE_DES_CBC_MD5:
101 case ETYPE_DES3_CBC_MD5:
102 case ETYPE_DES3_CBC_SHA1:
103 case ETYPE_ARCFOUR_HMAC_MD5:
104 case ETYPE_ARCFOUR_HMAC_MD5_56:
105 break;
106 default :
107 ctx->more_flags |= IS_CFX;
109 if ((acceptor && ctx->auth_context->local_subkey) ||
110 (!acceptor && ctx->auth_context->remote_subkey))
111 ctx->more_flags |= ACCEPTOR_SUBKEY;
112 break;
114 if (ctx->crypto)
115 krb5_crypto_destroy(context, ctx->crypto);
116 ret = krb5_crypto_init(context, key, 0, &ctx->crypto);
120 static OM_uint32
121 gsskrb5_accept_delegated_token
122 (OM_uint32 * minor_status,
123 gsskrb5_ctx ctx,
124 krb5_context context,
125 gss_cred_id_t * delegated_cred_handle
128 krb5_ccache ccache = NULL;
129 krb5_error_code kret;
130 int32_t ac_flags, ret = GSS_S_COMPLETE;
132 *minor_status = 0;
134 /* XXX Create a new delegated_cred_handle? */
135 if (delegated_cred_handle == NULL) {
136 kret = krb5_cc_default (context, &ccache);
137 } else {
138 *delegated_cred_handle = NULL;
139 kret = krb5_cc_new_unique (context, krb5_cc_type_memory,
140 NULL, &ccache);
142 if (kret) {
143 ctx->flags &= ~GSS_C_DELEG_FLAG;
144 goto out;
147 kret = krb5_cc_initialize(context, ccache, ctx->source);
148 if (kret) {
149 ctx->flags &= ~GSS_C_DELEG_FLAG;
150 goto out;
153 krb5_auth_con_removeflags(context,
154 ctx->auth_context,
155 KRB5_AUTH_CONTEXT_DO_TIME,
156 &ac_flags);
157 kret = krb5_rd_cred2(context,
158 ctx->auth_context,
159 ccache,
160 &ctx->fwd_data);
161 krb5_auth_con_setflags(context,
162 ctx->auth_context,
163 ac_flags);
164 if (kret) {
165 ctx->flags &= ~GSS_C_DELEG_FLAG;
166 ret = GSS_S_FAILURE;
167 *minor_status = kret;
168 goto out;
171 if (delegated_cred_handle) {
172 gsskrb5_cred handle;
174 ret = _gsskrb5_krb5_import_cred(minor_status,
175 ccache,
176 NULL,
177 NULL,
178 delegated_cred_handle);
179 if (ret != GSS_S_COMPLETE)
180 goto out;
182 handle = (gsskrb5_cred) *delegated_cred_handle;
184 handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
185 krb5_cc_close(context, ccache);
186 ccache = NULL;
189 out:
190 if (ccache) {
191 /* Don't destroy the default cred cache */
192 if (delegated_cred_handle == NULL)
193 krb5_cc_close(context, ccache);
194 else
195 krb5_cc_destroy(context, ccache);
197 return ret;
200 static OM_uint32
201 gsskrb5_acceptor_ready(OM_uint32 * minor_status,
202 gsskrb5_ctx ctx,
203 krb5_context context,
204 gss_cred_id_t *delegated_cred_handle)
206 OM_uint32 ret;
207 int32_t seq_number;
208 int is_cfx = 0;
210 krb5_auth_getremoteseqnumber (context,
211 ctx->auth_context,
212 &seq_number);
214 _gsskrb5i_is_cfx(context, ctx, 1);
215 is_cfx = (ctx->more_flags & IS_CFX);
217 ret = _gssapi_msg_order_create(minor_status,
218 &ctx->order,
219 _gssapi_msg_order_f(ctx->flags),
220 seq_number, 0, is_cfx);
221 if (ret)
222 return ret;
225 * If requested, set local sequence num to remote sequence if this
226 * isn't a mutual authentication context
228 if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
229 krb5_auth_con_setlocalseqnumber(context,
230 ctx->auth_context,
231 seq_number);
235 * We should handle the delegation ticket, in case it's there
237 if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
238 ret = gsskrb5_accept_delegated_token(minor_status,
239 ctx,
240 context,
241 delegated_cred_handle);
242 if (ret)
243 return ret;
244 } else {
245 /* Well, looks like it wasn't there after all */
246 ctx->flags &= ~GSS_C_DELEG_FLAG;
249 ctx->state = ACCEPTOR_READY;
250 ctx->more_flags |= OPEN;
252 return GSS_S_COMPLETE;
255 static OM_uint32
256 send_error_token(OM_uint32 *minor_status,
257 krb5_context context,
258 krb5_error_code kret,
259 krb5_principal server,
260 krb5_data *indata,
261 gss_buffer_t output_token)
263 krb5_principal ap_req_server = NULL;
264 krb5_error_code ret;
265 krb5_data outbuf;
267 /* build server from request if the acceptor had not selected one */
268 if (server == NULL) {
269 AP_REQ ap_req;
271 ret = krb5_decode_ap_req(context, indata, &ap_req);
272 if (ret) {
273 *minor_status = ret;
274 return GSS_S_FAILURE;
276 ret = _krb5_principalname2krb5_principal(context,
277 &ap_req_server,
278 ap_req.ticket.sname,
279 ap_req.ticket.realm);
280 free_AP_REQ(&ap_req);
281 if (ret) {
282 *minor_status = ret;
283 return GSS_S_FAILURE;
285 server = ap_req_server;
288 ret = krb5_mk_error(context, kret, NULL, NULL, NULL,
289 server, NULL, NULL, &outbuf);
290 if (ap_req_server)
291 krb5_free_principal(context, ap_req_server);
292 if (ret) {
293 *minor_status = ret;
294 return GSS_S_FAILURE;
297 ret = _gsskrb5_encapsulate(minor_status,
298 &outbuf,
299 output_token,
300 "\x03\x00",
301 GSS_KRB5_MECHANISM);
302 krb5_data_free (&outbuf);
303 if (ret)
304 return ret;
306 *minor_status = 0;
307 return GSS_S_CONTINUE_NEEDED;
311 static OM_uint32
312 gsskrb5_acceptor_start(OM_uint32 * minor_status,
313 gsskrb5_ctx ctx,
314 krb5_context context,
315 const gss_cred_id_t acceptor_cred_handle,
316 const gss_buffer_t input_token_buffer,
317 const gss_channel_bindings_t input_chan_bindings,
318 gss_name_t * src_name,
319 gss_OID * mech_type,
320 gss_buffer_t output_token,
321 OM_uint32 * ret_flags,
322 OM_uint32 * time_rec,
323 gss_cred_id_t * delegated_cred_handle)
325 krb5_error_code kret;
326 OM_uint32 ret = GSS_S_COMPLETE;
327 krb5_data indata;
328 krb5_flags ap_options;
329 krb5_keytab keytab = NULL;
330 int is_cfx = 0;
331 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
334 * We may, or may not, have an escapsulation.
336 ret = _gsskrb5_decapsulate (minor_status,
337 input_token_buffer,
338 &indata,
339 "\x01\x00",
340 GSS_KRB5_MECHANISM);
342 if (ret) {
343 /* Assume that there is no OID wrapping. */
344 indata.length = input_token_buffer->length;
345 indata.data = input_token_buffer->value;
349 * We need to get our keytab
351 if (acceptor_cred == NULL) {
352 if (_gsskrb5_keytab != NULL)
353 keytab = _gsskrb5_keytab;
354 } else if (acceptor_cred->keytab != NULL) {
355 keytab = acceptor_cred->keytab;
359 * We need to check the ticket and create the AP-REP packet
363 krb5_rd_req_in_ctx in = NULL;
364 krb5_rd_req_out_ctx out = NULL;
365 krb5_principal server = NULL;
367 if (acceptor_cred)
368 server = acceptor_cred->principal;
370 kret = krb5_rd_req_in_ctx_alloc(context, &in);
371 if (kret == 0)
372 kret = krb5_rd_req_in_set_keytab(context, in, keytab);
373 if (kret) {
374 if (in)
375 krb5_rd_req_in_ctx_free(context, in);
376 *minor_status = kret;
377 return GSS_S_FAILURE;
380 kret = krb5_rd_req_ctx(context,
381 &ctx->auth_context,
382 &indata,
383 server,
384 in, &out);
385 krb5_rd_req_in_ctx_free(context, in);
386 if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {
388 * No reply in non-MUTUAL mode, but we don't know that its
389 * non-MUTUAL mode yet, thats inside the 8003 checksum, so
390 * lets only send the error token on clock skew, that
391 * limit when send error token for non-MUTUAL.
393 return send_error_token(minor_status, context, kret,
394 server, &indata, output_token);
395 } else if (kret) {
396 *minor_status = kret;
397 return GSS_S_FAILURE;
401 * we need to remember some data on the context_handle.
403 kret = krb5_rd_req_out_get_ap_req_options(context, out,
404 &ap_options);
405 if (kret == 0)
406 kret = krb5_rd_req_out_get_ticket(context, out,
407 &ctx->ticket);
408 if (kret == 0)
409 kret = krb5_rd_req_out_get_keyblock(context, out,
410 &ctx->service_keyblock);
411 ctx->lifetime = ctx->ticket->ticket.endtime;
413 krb5_rd_req_out_ctx_free(context, out);
414 if (kret) {
415 ret = GSS_S_FAILURE;
416 *minor_status = kret;
417 return ret;
423 * We need to copy the principal names to the context and the
424 * calling layer.
426 kret = krb5_copy_principal(context,
427 ctx->ticket->client,
428 &ctx->source);
429 if (kret) {
430 ret = GSS_S_FAILURE;
431 *minor_status = kret;
434 kret = krb5_copy_principal(context,
435 ctx->ticket->server,
436 &ctx->target);
437 if (kret) {
438 ret = GSS_S_FAILURE;
439 *minor_status = kret;
440 return ret;
444 * We need to setup some compat stuff, this assumes that
445 * context_handle->target is already set.
447 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
448 if (ret)
449 return ret;
451 if (src_name != NULL) {
452 kret = krb5_copy_principal (context,
453 ctx->ticket->client,
454 (gsskrb5_name*)src_name);
455 if (kret) {
456 ret = GSS_S_FAILURE;
457 *minor_status = kret;
458 return ret;
463 * We need to get the flags out of the 8003 checksum.
467 krb5_authenticator authenticator;
469 kret = krb5_auth_con_getauthenticator(context,
470 ctx->auth_context,
471 &authenticator);
472 if(kret) {
473 ret = GSS_S_FAILURE;
474 *minor_status = kret;
475 return ret;
478 if (authenticator->cksum == NULL) {
479 krb5_free_authenticator(context, &authenticator);
480 *minor_status = 0;
481 return GSS_S_BAD_BINDINGS;
484 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
485 ret = _gsskrb5_verify_8003_checksum(minor_status,
486 input_chan_bindings,
487 authenticator->cksum,
488 &ctx->flags,
489 &ctx->fwd_data);
491 krb5_free_authenticator(context, &authenticator);
492 if (ret) {
493 return ret;
495 } else {
496 krb5_crypto crypto;
498 kret = krb5_crypto_init(context,
499 ctx->auth_context->keyblock,
500 0, &crypto);
501 if(kret) {
502 krb5_free_authenticator(context, &authenticator);
504 ret = GSS_S_FAILURE;
505 *minor_status = kret;
506 return ret;
510 * Windows accepts Samba3's use of a kerberos, rather than
511 * GSSAPI checksum here
514 kret = krb5_verify_checksum(context,
515 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
516 authenticator->cksum);
517 krb5_free_authenticator(context, &authenticator);
518 krb5_crypto_destroy(context, crypto);
520 if(kret) {
521 ret = GSS_S_BAD_SIG;
522 *minor_status = kret;
523 return ret;
527 * Samba style get some flags (but not DCE-STYLE), use
528 * ap_options to guess the mutual flag.
530 ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
531 if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
532 ctx->flags |= GSS_C_MUTUAL_FLAG;
536 if(ctx->flags & GSS_C_MUTUAL_FLAG) {
537 krb5_data outbuf;
538 int use_subkey = 0;
540 _gsskrb5i_is_cfx(context, ctx, 1);
541 is_cfx = (ctx->more_flags & IS_CFX);
543 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
544 use_subkey = 1;
545 } else {
546 krb5_keyblock *rkey;
549 * If there is a initiator subkey, copy that to acceptor
550 * subkey to match Windows behavior
552 kret = krb5_auth_con_getremotesubkey(context,
553 ctx->auth_context,
554 &rkey);
555 if (kret == 0) {
556 kret = krb5_auth_con_setlocalsubkey(context,
557 ctx->auth_context,
558 rkey);
559 if (kret == 0)
560 use_subkey = 1;
561 krb5_free_keyblock(context, rkey);
564 if (use_subkey) {
565 ctx->more_flags |= ACCEPTOR_SUBKEY;
566 krb5_auth_con_addflags(context, ctx->auth_context,
567 KRB5_AUTH_CONTEXT_USE_SUBKEY,
568 NULL);
571 kret = krb5_mk_rep(context,
572 ctx->auth_context,
573 &outbuf);
574 if (kret) {
575 *minor_status = kret;
576 return GSS_S_FAILURE;
579 if (IS_DCE_STYLE(ctx)) {
580 output_token->length = outbuf.length;
581 output_token->value = outbuf.data;
582 } else {
583 ret = _gsskrb5_encapsulate(minor_status,
584 &outbuf,
585 output_token,
586 "\x02\x00",
587 GSS_KRB5_MECHANISM);
588 krb5_data_free (&outbuf);
589 if (ret)
590 return ret;
594 ctx->flags |= GSS_C_TRANS_FLAG;
596 /* Remember the flags */
598 ctx->lifetime = ctx->ticket->ticket.endtime;
599 ctx->more_flags |= OPEN;
601 if (mech_type)
602 *mech_type = GSS_KRB5_MECHANISM;
604 if (time_rec) {
605 ret = _gsskrb5_lifetime_left(minor_status,
606 context,
607 ctx->lifetime,
608 time_rec);
609 if (ret) {
610 return ret;
615 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
616 * the client.
618 if (IS_DCE_STYLE(ctx)) {
620 * Return flags to caller, but we haven't processed
621 * delgations yet
623 if (ret_flags)
624 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
626 ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
627 return GSS_S_CONTINUE_NEEDED;
630 ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
631 delegated_cred_handle);
633 if (ret_flags)
634 *ret_flags = ctx->flags;
636 return ret;
639 static OM_uint32
640 acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
641 gsskrb5_ctx ctx,
642 krb5_context context,
643 const gss_cred_id_t acceptor_cred_handle,
644 const gss_buffer_t input_token_buffer,
645 const gss_channel_bindings_t input_chan_bindings,
646 gss_name_t * src_name,
647 gss_OID * mech_type,
648 gss_buffer_t output_token,
649 OM_uint32 * ret_flags,
650 OM_uint32 * time_rec,
651 gss_cred_id_t * delegated_cred_handle)
653 OM_uint32 ret;
654 krb5_error_code kret;
655 krb5_data inbuf;
656 int32_t r_seq_number, l_seq_number;
659 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
662 inbuf.length = input_token_buffer->length;
663 inbuf.data = input_token_buffer->value;
666 * We need to remeber the old remote seq_number, then check if the
667 * client has replied with our local seq_number, and then reset
668 * the remote seq_number to the old value
671 kret = krb5_auth_con_getlocalseqnumber(context,
672 ctx->auth_context,
673 &l_seq_number);
674 if (kret) {
675 *minor_status = kret;
676 return GSS_S_FAILURE;
679 kret = krb5_auth_getremoteseqnumber(context,
680 ctx->auth_context,
681 &r_seq_number);
682 if (kret) {
683 *minor_status = kret;
684 return GSS_S_FAILURE;
687 kret = krb5_auth_con_setremoteseqnumber(context,
688 ctx->auth_context,
689 l_seq_number);
690 if (kret) {
691 *minor_status = kret;
692 return GSS_S_FAILURE;
697 * We need to verify the AP_REP, but we need to flag that this is
698 * DCE_STYLE, so don't check the timestamps this time, but put the
699 * flag DO_TIME back afterward.
702 krb5_ap_rep_enc_part *repl;
703 int32_t auth_flags;
705 krb5_auth_con_removeflags(context,
706 ctx->auth_context,
707 KRB5_AUTH_CONTEXT_DO_TIME,
708 &auth_flags);
710 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
711 if (kret) {
712 *minor_status = kret;
713 return GSS_S_FAILURE;
715 krb5_free_ap_rep_enc_part(context, repl);
716 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
719 /* We need to check the liftime */
721 OM_uint32 lifetime_rec;
723 ret = _gsskrb5_lifetime_left(minor_status,
724 context,
725 ctx->lifetime,
726 &lifetime_rec);
727 if (ret) {
728 return ret;
730 if (lifetime_rec == 0) {
731 return GSS_S_CONTEXT_EXPIRED;
734 if (time_rec) *time_rec = lifetime_rec;
737 /* We need to give the caller the flags which are in use */
738 if (ret_flags) *ret_flags = ctx->flags;
740 if (src_name) {
741 kret = krb5_copy_principal(context,
742 ctx->source,
743 (gsskrb5_name*)src_name);
744 if (kret) {
745 *minor_status = kret;
746 return GSS_S_FAILURE;
751 * After the krb5_rd_rep() the remote and local seq_number should
752 * be the same, because the client just replies the seq_number
753 * from our AP-REP in its AP-REP, but then the client uses the
754 * seq_number from its AP-REQ for GSS_wrap()
757 int32_t tmp_r_seq_number, tmp_l_seq_number;
759 kret = krb5_auth_getremoteseqnumber(context,
760 ctx->auth_context,
761 &tmp_r_seq_number);
762 if (kret) {
763 *minor_status = kret;
764 return GSS_S_FAILURE;
767 kret = krb5_auth_con_getlocalseqnumber(context,
768 ctx->auth_context,
769 &tmp_l_seq_number);
770 if (kret) {
772 *minor_status = kret;
773 return GSS_S_FAILURE;
777 * Here we check if the client has responsed with our local seq_number,
779 if (tmp_r_seq_number != tmp_l_seq_number) {
780 return GSS_S_UNSEQ_TOKEN;
785 * We need to reset the remote seq_number, because the client will use,
786 * the old one for the GSS_wrap() calls
789 kret = krb5_auth_con_setremoteseqnumber(context,
790 ctx->auth_context,
791 r_seq_number);
792 if (kret) {
793 *minor_status = kret;
794 return GSS_S_FAILURE;
798 return gsskrb5_acceptor_ready(minor_status, ctx, context,
799 delegated_cred_handle);
803 OM_uint32
804 _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
805 gss_ctx_id_t * context_handle,
806 const gss_cred_id_t acceptor_cred_handle,
807 const gss_buffer_t input_token_buffer,
808 const gss_channel_bindings_t input_chan_bindings,
809 gss_name_t * src_name,
810 gss_OID * mech_type,
811 gss_buffer_t output_token,
812 OM_uint32 * ret_flags,
813 OM_uint32 * time_rec,
814 gss_cred_id_t * delegated_cred_handle)
816 krb5_context context;
817 OM_uint32 ret;
818 gsskrb5_ctx ctx;
820 GSSAPI_KRB5_INIT(&context);
822 output_token->length = 0;
823 output_token->value = NULL;
825 if (src_name != NULL)
826 *src_name = NULL;
827 if (mech_type)
828 *mech_type = GSS_KRB5_MECHANISM;
830 if (*context_handle == GSS_C_NO_CONTEXT) {
831 ret = _gsskrb5_create_ctx(minor_status,
832 context_handle,
833 context,
834 input_chan_bindings,
835 ACCEPTOR_START);
836 if (ret)
837 return ret;
840 ctx = (gsskrb5_ctx)*context_handle;
844 * TODO: check the channel_bindings
845 * (above just sets them to krb5 layer)
848 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
850 switch (ctx->state) {
851 case ACCEPTOR_START:
852 ret = gsskrb5_acceptor_start(minor_status,
853 ctx,
854 context,
855 acceptor_cred_handle,
856 input_token_buffer,
857 input_chan_bindings,
858 src_name,
859 mech_type,
860 output_token,
861 ret_flags,
862 time_rec,
863 delegated_cred_handle);
864 break;
865 case ACCEPTOR_WAIT_FOR_DCESTYLE:
866 ret = acceptor_wait_for_dcestyle(minor_status,
867 ctx,
868 context,
869 acceptor_cred_handle,
870 input_token_buffer,
871 input_chan_bindings,
872 src_name,
873 mech_type,
874 output_token,
875 ret_flags,
876 time_rec,
877 delegated_cred_handle);
878 break;
879 case ACCEPTOR_READY:
881 * If we get there, the caller have called
882 * gss_accept_sec_context() one time too many.
884 ret = GSS_S_BAD_STATUS;
885 break;
886 default:
887 /* TODO: is this correct here? --metze */
888 ret = GSS_S_BAD_STATUS;
889 break;
892 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
894 if (GSS_ERROR(ret)) {
895 OM_uint32 min2;
896 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
899 return ret;