accept_sec_context.c revision 178826
1/*
2 * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
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.
16 *
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.
20 *
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.
32 */
33
34#include "krb5/gsskrb5_locl.h"
35
36RCSID("$Id: accept_sec_context.c 20199 2007-02-07 22:36:39Z lha $");
37
38HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39krb5_keytab _gsskrb5_keytab;
40
41OM_uint32
42_gsskrb5_register_acceptor_identity (const char *identity)
43{
44    krb5_context context;
45    krb5_error_code ret;
46
47    ret = _gsskrb5_init(&context);
48    if(ret)
49	return GSS_S_FAILURE;
50
51    HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
52
53    if(_gsskrb5_keytab != NULL) {
54	krb5_kt_close(context, _gsskrb5_keytab);
55	_gsskrb5_keytab = NULL;
56    }
57    if (identity == NULL) {
58	ret = krb5_kt_default(context, &_gsskrb5_keytab);
59    } else {
60	char *p;
61
62	asprintf(&p, "FILE:%s", identity);
63	if(p == NULL) {
64	    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
65	    return GSS_S_FAILURE;
66	}
67	ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab);
68	free(p);
69    }
70    HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
71    if(ret)
72	return GSS_S_FAILURE;
73    return GSS_S_COMPLETE;
74}
75
76void
77_gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx)
78{
79    krb5_keyblock *key;
80    int acceptor = (ctx->more_flags & LOCAL) == 0;
81
82    *is_cfx = 0;
83
84    if (acceptor) {
85	if (ctx->auth_context->local_subkey)
86	    key = ctx->auth_context->local_subkey;
87	else
88	    key = ctx->auth_context->remote_subkey;
89    } else {
90	if (ctx->auth_context->remote_subkey)
91	    key = ctx->auth_context->remote_subkey;
92	else
93	    key = ctx->auth_context->local_subkey;
94    }
95    if (key == NULL)
96	key = ctx->auth_context->keyblock;
97
98    if (key == NULL)
99	return;
100
101    switch (key->keytype) {
102    case ETYPE_DES_CBC_CRC:
103    case ETYPE_DES_CBC_MD4:
104    case ETYPE_DES_CBC_MD5:
105    case ETYPE_DES3_CBC_MD5:
106    case ETYPE_DES3_CBC_SHA1:
107    case ETYPE_ARCFOUR_HMAC_MD5:
108    case ETYPE_ARCFOUR_HMAC_MD5_56:
109	break;
110    default :
111	*is_cfx = 1;
112	if ((acceptor && ctx->auth_context->local_subkey) ||
113	    (!acceptor && ctx->auth_context->remote_subkey))
114	    ctx->more_flags |= ACCEPTOR_SUBKEY;
115	break;
116    }
117}
118
119
120static OM_uint32
121gsskrb5_accept_delegated_token
122(OM_uint32 * minor_status,
123 gsskrb5_ctx ctx,
124 krb5_context context,
125 gss_cred_id_t * delegated_cred_handle
126    )
127{
128    krb5_ccache ccache = NULL;
129    krb5_error_code kret;
130    int32_t ac_flags, ret = GSS_S_COMPLETE;
131
132    *minor_status = 0;
133
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_gen_new (context, &krb5_mcc_ops, &ccache);
140    }
141    if (kret) {
142	ctx->flags &= ~GSS_C_DELEG_FLAG;
143	goto out;
144    }
145
146    kret = krb5_cc_initialize(context, ccache, ctx->source);
147    if (kret) {
148	ctx->flags &= ~GSS_C_DELEG_FLAG;
149	goto out;
150    }
151
152    krb5_auth_con_removeflags(context,
153			      ctx->auth_context,
154			      KRB5_AUTH_CONTEXT_DO_TIME,
155			      &ac_flags);
156    kret = krb5_rd_cred2(context,
157			 ctx->auth_context,
158			 ccache,
159			 &ctx->fwd_data);
160    krb5_auth_con_setflags(context,
161			   ctx->auth_context,
162			   ac_flags);
163    if (kret) {
164	ctx->flags &= ~GSS_C_DELEG_FLAG;
165	ret = GSS_S_FAILURE;
166	*minor_status = kret;
167	goto out;
168    }
169
170    if (delegated_cred_handle) {
171	gsskrb5_cred handle;
172
173	ret = _gsskrb5_import_cred(minor_status,
174				   ccache,
175				   NULL,
176				   NULL,
177				   delegated_cred_handle);
178	if (ret != GSS_S_COMPLETE)
179	    goto out;
180
181	handle = (gsskrb5_cred) *delegated_cred_handle;
182
183	handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
184	krb5_cc_close(context, ccache);
185	ccache = NULL;
186    }
187
188out:
189    if (ccache) {
190	/* Don't destroy the default cred cache */
191	if (delegated_cred_handle == NULL)
192	    krb5_cc_close(context, ccache);
193	else
194	    krb5_cc_destroy(context, ccache);
195    }
196    return ret;
197}
198
199static OM_uint32
200gsskrb5_acceptor_ready(OM_uint32 * minor_status,
201		       gsskrb5_ctx ctx,
202		       krb5_context context,
203		       gss_cred_id_t *delegated_cred_handle)
204{
205    OM_uint32 ret;
206    int32_t seq_number;
207    int is_cfx = 0;
208
209    krb5_auth_getremoteseqnumber (context,
210				  ctx->auth_context,
211				  &seq_number);
212
213    _gsskrb5i_is_cfx(ctx, &is_cfx);
214
215    ret = _gssapi_msg_order_create(minor_status,
216				   &ctx->order,
217				   _gssapi_msg_order_f(ctx->flags),
218				   seq_number, 0, is_cfx);
219    if (ret)
220	return ret;
221
222    /*
223     * If requested, set local sequence num to remote sequence if this
224     * isn't a mutual authentication context
225     */
226    if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
227	krb5_auth_con_setlocalseqnumber(context,
228					ctx->auth_context,
229					seq_number);
230    }
231
232    /*
233     * We should handle the delegation ticket, in case it's there
234     */
235    if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
236	ret = gsskrb5_accept_delegated_token(minor_status,
237					     ctx,
238					     context,
239					     delegated_cred_handle);
240	if (ret)
241	    return ret;
242    } else {
243	/* Well, looks like it wasn't there after all */
244	ctx->flags &= ~GSS_C_DELEG_FLAG;
245    }
246
247    ctx->state = ACCEPTOR_READY;
248    ctx->more_flags |= OPEN;
249
250    return GSS_S_COMPLETE;
251}
252
253static OM_uint32
254gsskrb5_acceptor_start(OM_uint32 * minor_status,
255		       gsskrb5_ctx ctx,
256		       krb5_context context,
257		       const gss_cred_id_t acceptor_cred_handle,
258		       const gss_buffer_t input_token_buffer,
259		       const gss_channel_bindings_t input_chan_bindings,
260		       gss_name_t * src_name,
261		       gss_OID * mech_type,
262		       gss_buffer_t output_token,
263		       OM_uint32 * ret_flags,
264		       OM_uint32 * time_rec,
265		       gss_cred_id_t * delegated_cred_handle)
266{
267    krb5_error_code kret;
268    OM_uint32 ret = GSS_S_COMPLETE;
269    krb5_data indata;
270    krb5_flags ap_options;
271    krb5_keytab keytab = NULL;
272    int is_cfx = 0;
273    const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
274
275    /*
276     * We may, or may not, have an escapsulation.
277     */
278    ret = _gsskrb5_decapsulate (minor_status,
279				input_token_buffer,
280				&indata,
281				"\x01\x00",
282				GSS_KRB5_MECHANISM);
283
284    if (ret) {
285	/* Assume that there is no OID wrapping. */
286	indata.length	= input_token_buffer->length;
287	indata.data	= input_token_buffer->value;
288    }
289
290    /*
291     * We need to get our keytab
292     */
293    if (acceptor_cred == NULL) {
294	if (_gsskrb5_keytab != NULL)
295	    keytab = _gsskrb5_keytab;
296    } else if (acceptor_cred->keytab != NULL) {
297	keytab = acceptor_cred->keytab;
298    }
299
300    /*
301     * We need to check the ticket and create the AP-REP packet
302     */
303
304    {
305	krb5_rd_req_in_ctx in = NULL;
306	krb5_rd_req_out_ctx out = NULL;
307
308	kret = krb5_rd_req_in_ctx_alloc(context, &in);
309	if (kret == 0)
310	    kret = krb5_rd_req_in_set_keytab(context, in, keytab);
311	if (kret) {
312	    if (in)
313		krb5_rd_req_in_ctx_free(context, in);
314	    ret = GSS_S_FAILURE;
315	    *minor_status = kret;
316	    return ret;
317	}
318
319	kret = krb5_rd_req_ctx(context,
320			       &ctx->auth_context,
321			       &indata,
322			       (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal,
323			       in, &out);
324	krb5_rd_req_in_ctx_free(context, in);
325	if (kret) {
326	    ret = GSS_S_FAILURE;
327	    *minor_status = kret;
328	    return ret;
329	}
330
331	/*
332	 * We need to remember some data on the context_handle.
333	 */
334	kret = krb5_rd_req_out_get_ap_req_options(context, out,
335						  &ap_options);
336	if (kret == 0)
337	    kret = krb5_rd_req_out_get_ticket(context, out,
338					      &ctx->ticket);
339	if (kret == 0)
340	    kret = krb5_rd_req_out_get_keyblock(context, out,
341						&ctx->service_keyblock);
342	ctx->lifetime = ctx->ticket->ticket.endtime;
343
344	krb5_rd_req_out_ctx_free(context, out);
345	if (kret) {
346	    ret = GSS_S_FAILURE;
347	    *minor_status = kret;
348	    return ret;
349	}
350    }
351
352
353    /*
354     * We need to copy the principal names to the context and the
355     * calling layer.
356     */
357    kret = krb5_copy_principal(context,
358			       ctx->ticket->client,
359			       &ctx->source);
360    if (kret) {
361	ret = GSS_S_FAILURE;
362	*minor_status = kret;
363    }
364
365    kret = krb5_copy_principal(context,
366			       ctx->ticket->server,
367			       &ctx->target);
368    if (kret) {
369	ret = GSS_S_FAILURE;
370	*minor_status = kret;
371	return ret;
372    }
373
374    /*
375     * We need to setup some compat stuff, this assumes that
376     * context_handle->target is already set.
377     */
378    ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
379    if (ret)
380	return ret;
381
382    if (src_name != NULL) {
383	kret = krb5_copy_principal (context,
384				    ctx->ticket->client,
385				    (gsskrb5_name*)src_name);
386	if (kret) {
387	    ret = GSS_S_FAILURE;
388	    *minor_status = kret;
389	    return ret;
390	}
391    }
392
393    /*
394     * We need to get the flags out of the 8003 checksum.
395     */
396    {
397	krb5_authenticator authenticator;
398
399	kret = krb5_auth_con_getauthenticator(context,
400					      ctx->auth_context,
401					      &authenticator);
402	if(kret) {
403	    ret = GSS_S_FAILURE;
404	    *minor_status = kret;
405	    return ret;
406	}
407
408        if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
409            ret = _gsskrb5_verify_8003_checksum(minor_status,
410						input_chan_bindings,
411						authenticator->cksum,
412						&ctx->flags,
413						&ctx->fwd_data);
414
415	    krb5_free_authenticator(context, &authenticator);
416	    if (ret) {
417		return ret;
418	    }
419        } else {
420	    krb5_crypto crypto;
421
422	    kret = krb5_crypto_init(context,
423				    ctx->auth_context->keyblock,
424				    0, &crypto);
425	    if(kret) {
426		krb5_free_authenticator(context, &authenticator);
427
428		ret = GSS_S_FAILURE;
429		*minor_status = kret;
430		return ret;
431	    }
432
433	    /*
434	     * Windows accepts Samba3's use of a kerberos, rather than
435	     * GSSAPI checksum here
436	     */
437
438	    kret = krb5_verify_checksum(context,
439					crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
440					authenticator->cksum);
441	    krb5_free_authenticator(context, &authenticator);
442	    krb5_crypto_destroy(context, crypto);
443
444	    if(kret) {
445		ret = GSS_S_BAD_SIG;
446		*minor_status = kret;
447		return ret;
448	    }
449
450	    /*
451	     * Samba style get some flags (but not DCE-STYLE)
452	     */
453	    ctx->flags =
454		GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
455        }
456    }
457
458    if(ctx->flags & GSS_C_MUTUAL_FLAG) {
459	krb5_data outbuf;
460
461	_gsskrb5i_is_cfx(ctx, &is_cfx);
462
463	if (is_cfx != 0
464	    || (ap_options & AP_OPTS_USE_SUBKEY)) {
465	    kret = krb5_auth_con_addflags(context,
466					  ctx->auth_context,
467					  KRB5_AUTH_CONTEXT_USE_SUBKEY,
468					  NULL);
469	    ctx->more_flags |= ACCEPTOR_SUBKEY;
470	}
471
472	kret = krb5_mk_rep(context,
473			   ctx->auth_context,
474			   &outbuf);
475	if (kret) {
476	    *minor_status = kret;
477	    return GSS_S_FAILURE;
478	}
479
480	if (IS_DCE_STYLE(ctx)) {
481	    output_token->length = outbuf.length;
482	    output_token->value = outbuf.data;
483	} else {
484	    ret = _gsskrb5_encapsulate(minor_status,
485				       &outbuf,
486				       output_token,
487				       "\x02\x00",
488				       GSS_KRB5_MECHANISM);
489	    krb5_data_free (&outbuf);
490	    if (ret)
491		return ret;
492	}
493    }
494
495    ctx->flags |= GSS_C_TRANS_FLAG;
496
497    /* Remember the flags */
498
499    ctx->lifetime = ctx->ticket->ticket.endtime;
500    ctx->more_flags |= OPEN;
501
502    if (mech_type)
503	*mech_type = GSS_KRB5_MECHANISM;
504
505    if (time_rec) {
506	ret = _gsskrb5_lifetime_left(minor_status,
507				     context,
508				     ctx->lifetime,
509				     time_rec);
510	if (ret) {
511	    return ret;
512	}
513    }
514
515    /*
516     * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
517     * the client.
518     */
519    if (IS_DCE_STYLE(ctx)) {
520	/*
521	 * Return flags to caller, but we haven't processed
522	 * delgations yet
523	 */
524	if (ret_flags)
525	    *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
526
527	ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
528	return GSS_S_CONTINUE_NEEDED;
529    }
530
531    ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
532				 delegated_cred_handle);
533
534    if (ret_flags)
535	*ret_flags = ctx->flags;
536
537    return ret;
538}
539
540static OM_uint32
541acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
542			   gsskrb5_ctx ctx,
543			   krb5_context context,
544			   const gss_cred_id_t acceptor_cred_handle,
545			   const gss_buffer_t input_token_buffer,
546			   const gss_channel_bindings_t input_chan_bindings,
547			   gss_name_t * src_name,
548			   gss_OID * mech_type,
549			   gss_buffer_t output_token,
550			   OM_uint32 * ret_flags,
551			   OM_uint32 * time_rec,
552			   gss_cred_id_t * delegated_cred_handle)
553{
554    OM_uint32 ret;
555    krb5_error_code kret;
556    krb5_data inbuf;
557    int32_t r_seq_number, l_seq_number;
558
559    /*
560     * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
561     */
562
563    inbuf.length = input_token_buffer->length;
564    inbuf.data = input_token_buffer->value;
565
566    /*
567     * We need to remeber the old remote seq_number, then check if the
568     * client has replied with our local seq_number, and then reset
569     * the remote seq_number to the old value
570     */
571    {
572	kret = krb5_auth_con_getlocalseqnumber(context,
573					       ctx->auth_context,
574					       &l_seq_number);
575	if (kret) {
576	    *minor_status = kret;
577	    return GSS_S_FAILURE;
578	}
579
580	kret = krb5_auth_getremoteseqnumber(context,
581					    ctx->auth_context,
582					    &r_seq_number);
583	if (kret) {
584	    *minor_status = kret;
585	    return GSS_S_FAILURE;
586	}
587
588	kret = krb5_auth_con_setremoteseqnumber(context,
589						ctx->auth_context,
590						l_seq_number);
591	if (kret) {
592	    *minor_status = kret;
593	    return GSS_S_FAILURE;
594	}
595    }
596
597    /*
598     * We need to verify the AP_REP, but we need to flag that this is
599     * DCE_STYLE, so don't check the timestamps this time, but put the
600     * flag DO_TIME back afterward.
601    */
602    {
603	krb5_ap_rep_enc_part *repl;
604	int32_t auth_flags;
605
606	krb5_auth_con_removeflags(context,
607				  ctx->auth_context,
608				  KRB5_AUTH_CONTEXT_DO_TIME,
609				  &auth_flags);
610
611	kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
612	if (kret) {
613	    *minor_status = kret;
614	    return GSS_S_FAILURE;
615	}
616	krb5_free_ap_rep_enc_part(context, repl);
617	krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
618    }
619
620    /* We need to check the liftime */
621    {
622	OM_uint32 lifetime_rec;
623
624	ret = _gsskrb5_lifetime_left(minor_status,
625				     context,
626				     ctx->lifetime,
627				     &lifetime_rec);
628	if (ret) {
629	    return ret;
630	}
631	if (lifetime_rec == 0) {
632	    return GSS_S_CONTEXT_EXPIRED;
633	}
634
635	if (time_rec) *time_rec = lifetime_rec;
636    }
637
638    /* We need to give the caller the flags which are in use */
639    if (ret_flags) *ret_flags = ctx->flags;
640
641    if (src_name) {
642	kret = krb5_copy_principal(context,
643				   ctx->source,
644				   (gsskrb5_name*)src_name);
645	if (kret) {
646	    *minor_status = kret;
647	    return GSS_S_FAILURE;
648	}
649    }
650
651    /*
652     * After the krb5_rd_rep() the remote and local seq_number should
653     * be the same, because the client just replies the seq_number
654     * from our AP-REP in its AP-REP, but then the client uses the
655     * seq_number from its AP-REQ for GSS_wrap()
656     */
657    {
658	int32_t tmp_r_seq_number, tmp_l_seq_number;
659
660	kret = krb5_auth_getremoteseqnumber(context,
661					    ctx->auth_context,
662					    &tmp_r_seq_number);
663	if (kret) {
664	    *minor_status = kret;
665	    return GSS_S_FAILURE;
666	}
667
668	kret = krb5_auth_con_getlocalseqnumber(context,
669					       ctx->auth_context,
670					       &tmp_l_seq_number);
671	if (kret) {
672
673	    *minor_status = kret;
674	    return GSS_S_FAILURE;
675	}
676
677	/*
678	 * Here we check if the client has responsed with our local seq_number,
679	 */
680	if (tmp_r_seq_number != tmp_l_seq_number) {
681	    return GSS_S_UNSEQ_TOKEN;
682	}
683    }
684
685    /*
686     * We need to reset the remote seq_number, because the client will use,
687     * the old one for the GSS_wrap() calls
688     */
689    {
690	kret = krb5_auth_con_setremoteseqnumber(context,
691						ctx->auth_context,
692						r_seq_number);
693	if (kret) {
694	    *minor_status = kret;
695	    return GSS_S_FAILURE;
696	}
697    }
698
699    return gsskrb5_acceptor_ready(minor_status, ctx, context,
700				  delegated_cred_handle);
701}
702
703
704OM_uint32
705_gsskrb5_accept_sec_context(OM_uint32 * minor_status,
706			    gss_ctx_id_t * context_handle,
707			    const gss_cred_id_t acceptor_cred_handle,
708			    const gss_buffer_t input_token_buffer,
709			    const gss_channel_bindings_t input_chan_bindings,
710			    gss_name_t * src_name,
711			    gss_OID * mech_type,
712			    gss_buffer_t output_token,
713			    OM_uint32 * ret_flags,
714			    OM_uint32 * time_rec,
715			    gss_cred_id_t * delegated_cred_handle)
716{
717    krb5_context context;
718    OM_uint32 ret;
719    gsskrb5_ctx ctx;
720
721    GSSAPI_KRB5_INIT(&context);
722
723    output_token->length = 0;
724    output_token->value = NULL;
725
726    if (src_name != NULL)
727	*src_name = NULL;
728    if (mech_type)
729	*mech_type = GSS_KRB5_MECHANISM;
730
731    if (*context_handle == GSS_C_NO_CONTEXT) {
732	ret = _gsskrb5_create_ctx(minor_status,
733				  context_handle,
734				  context,
735				  input_chan_bindings,
736				  ACCEPTOR_START);
737	if (ret)
738	    return ret;
739    }
740
741    ctx = (gsskrb5_ctx)*context_handle;
742
743
744    /*
745     * TODO: check the channel_bindings
746     * (above just sets them to krb5 layer)
747     */
748
749    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
750
751    switch (ctx->state) {
752    case ACCEPTOR_START:
753	ret = gsskrb5_acceptor_start(minor_status,
754				     ctx,
755				     context,
756				     acceptor_cred_handle,
757				     input_token_buffer,
758				     input_chan_bindings,
759				     src_name,
760				     mech_type,
761				     output_token,
762				     ret_flags,
763				     time_rec,
764				     delegated_cred_handle);
765	break;
766    case ACCEPTOR_WAIT_FOR_DCESTYLE:
767	ret = acceptor_wait_for_dcestyle(minor_status,
768					 ctx,
769					 context,
770					 acceptor_cred_handle,
771					 input_token_buffer,
772					 input_chan_bindings,
773					 src_name,
774					 mech_type,
775					 output_token,
776					 ret_flags,
777					 time_rec,
778					 delegated_cred_handle);
779	break;
780    case ACCEPTOR_READY:
781	/*
782	 * If we get there, the caller have called
783	 * gss_accept_sec_context() one time too many.
784	 */
785	ret =  GSS_S_BAD_STATUS;
786	break;
787    default:
788	/* TODO: is this correct here? --metze */
789	ret =  GSS_S_BAD_STATUS;
790	break;
791    }
792
793    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
794
795    if (GSS_ERROR(ret)) {
796	OM_uint32 min2;
797	_gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
798    }
799
800    return ret;
801}
802