heimdal: import heimdal's trunk svn rev 23697 + lorikeet-heimdal patches
[metze/samba/wip.git] / source / heimdal / lib / gssapi / krb5 / accept_sec_context.c
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
36 RCSID("$Id$");
37
38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39 krb5_keytab _gsskrb5_keytab;
40
41 OM_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
76 void
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
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
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
188 out:
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
199 static OM_uint32
200 gsskrb5_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
253 static OM_uint32
254 send_error_token(OM_uint32 *minor_status,
255                  krb5_context context,
256                  krb5_error_code kret,
257                  krb5_principal server,
258                  krb5_data *indata,
259                  gss_buffer_t output_token)
260 {
261     krb5_principal ap_req_server = NULL;
262     krb5_error_code ret;
263     krb5_data outbuf;
264
265     /* build server from request if the acceptor had not selected one */
266     if (server == NULL) {
267         AP_REQ ap_req;
268
269         ret = krb5_decode_ap_req(context, indata, &ap_req);
270         if (ret) {
271             *minor_status = ret;
272             return GSS_S_FAILURE;
273         }
274         ret = _krb5_principalname2krb5_principal(context,
275                                                   &ap_req_server,
276                                                   ap_req.ticket.sname,
277                                                   ap_req.ticket.realm);
278         free_AP_REQ(&ap_req);
279         if (ret) {
280             *minor_status = ret;
281             return GSS_S_FAILURE;
282         }
283         server = ap_req_server;
284     }
285     
286     ret = krb5_mk_error(context, kret, NULL, NULL, NULL,
287                         server, NULL, NULL, &outbuf);
288     if (ap_req_server)
289         krb5_free_principal(context, ap_req_server);
290     if (ret) {
291         *minor_status = ret;
292         return GSS_S_FAILURE;
293     }
294     
295     ret = _gsskrb5_encapsulate(minor_status,
296                                &outbuf,
297                                output_token,
298                                "\x03\x00",
299                                GSS_KRB5_MECHANISM);
300     krb5_data_free (&outbuf);
301     if (ret)
302         return ret;
303
304     *minor_status = 0;
305     return GSS_S_CONTINUE_NEEDED;
306 }
307
308
309 static OM_uint32
310 gsskrb5_acceptor_start(OM_uint32 * minor_status,
311                        gsskrb5_ctx ctx,
312                        krb5_context context,
313                        const gss_cred_id_t acceptor_cred_handle,
314                        const gss_buffer_t input_token_buffer,
315                        const gss_channel_bindings_t input_chan_bindings,
316                        gss_name_t * src_name,
317                        gss_OID * mech_type,
318                        gss_buffer_t output_token,
319                        OM_uint32 * ret_flags,
320                        OM_uint32 * time_rec,
321                        gss_cred_id_t * delegated_cred_handle)
322 {
323     krb5_error_code kret;
324     OM_uint32 ret = GSS_S_COMPLETE;
325     krb5_data indata;
326     krb5_flags ap_options;
327     krb5_keytab keytab = NULL;
328     int is_cfx = 0;
329     const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
330
331     /*
332      * We may, or may not, have an escapsulation.
333      */
334     ret = _gsskrb5_decapsulate (minor_status,
335                                 input_token_buffer,
336                                 &indata,
337                                 "\x01\x00",
338                                 GSS_KRB5_MECHANISM);
339
340     if (ret) {
341         /* Assume that there is no OID wrapping. */
342         indata.length   = input_token_buffer->length;
343         indata.data     = input_token_buffer->value;
344     }
345
346     /*
347      * We need to get our keytab
348      */
349     if (acceptor_cred == NULL) {
350         if (_gsskrb5_keytab != NULL)
351             keytab = _gsskrb5_keytab;
352     } else if (acceptor_cred->keytab != NULL) {
353         keytab = acceptor_cred->keytab;
354     }
355     
356     /*
357      * We need to check the ticket and create the AP-REP packet
358      */
359
360     {
361         krb5_rd_req_in_ctx in = NULL;
362         krb5_rd_req_out_ctx out = NULL;
363         krb5_principal server = NULL;
364
365         if (acceptor_cred)
366             server = acceptor_cred->principal;
367
368         kret = krb5_rd_req_in_ctx_alloc(context, &in);
369         if (kret == 0)
370             kret = krb5_rd_req_in_set_keytab(context, in, keytab);
371         if (kret) {
372             if (in)
373                 krb5_rd_req_in_ctx_free(context, in);
374             *minor_status = kret;
375             return GSS_S_FAILURE;
376         }
377
378         kret = krb5_rd_req_ctx(context,
379                                &ctx->auth_context,
380                                &indata,
381                                server,
382                                in, &out);
383         krb5_rd_req_in_ctx_free(context, in);
384         if (kret == KRB5KRB_AP_ERR_SKEW) {
385             /* 
386              * No reply in non-MUTUAL mode, but we don't know that its
387              * non-MUTUAL mode yet, thats inside the 8003 checksum, so
388              * lets only send the error token on clock skew, that
389              * limit when send error token for non-MUTUAL.
390              */
391             return send_error_token(minor_status, context, kret,
392                                     server, &indata, output_token);
393         } else if (kret) {
394             *minor_status = kret;
395             return GSS_S_FAILURE;
396         }
397
398         /*
399          * we need to remember some data on the context_handle.
400          */
401         kret = krb5_rd_req_out_get_ap_req_options(context, out,
402                                                   &ap_options);
403         if (kret == 0)
404             kret = krb5_rd_req_out_get_ticket(context, out, 
405                                               &ctx->ticket);
406         if (kret == 0)
407             kret = krb5_rd_req_out_get_keyblock(context, out,
408                                                 &ctx->service_keyblock);
409         ctx->lifetime = ctx->ticket->ticket.endtime;
410
411         krb5_rd_req_out_ctx_free(context, out);
412         if (kret) {
413             ret = GSS_S_FAILURE;
414             *minor_status = kret;
415             return ret;
416         }
417     }
418     
419     
420     /*
421      * We need to copy the principal names to the context and the
422      * calling layer.
423      */
424     kret = krb5_copy_principal(context,
425                                ctx->ticket->client,
426                                &ctx->source);
427     if (kret) {
428         ret = GSS_S_FAILURE;
429         *minor_status = kret;
430     }
431
432     kret = krb5_copy_principal(context, 
433                                ctx->ticket->server,
434                                &ctx->target);
435     if (kret) {
436         ret = GSS_S_FAILURE;
437         *minor_status = kret;
438         return ret;
439     }
440     
441     /*
442      * We need to setup some compat stuff, this assumes that
443      * context_handle->target is already set.
444      */
445     ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
446     if (ret)
447         return ret;
448
449     if (src_name != NULL) {
450         kret = krb5_copy_principal (context,
451                                     ctx->ticket->client,
452                                     (gsskrb5_name*)src_name);
453         if (kret) {
454             ret = GSS_S_FAILURE;
455             *minor_status = kret;
456             return ret;
457         }
458     }
459
460     /*
461      * We need to get the flags out of the 8003 checksum.
462      */
463     {
464         krb5_authenticator authenticator;
465       
466         kret = krb5_auth_con_getauthenticator(context,
467                                               ctx->auth_context,
468                                               &authenticator);
469         if(kret) {
470             ret = GSS_S_FAILURE;
471             *minor_status = kret;
472             return ret;
473         }
474
475         if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
476             ret = _gsskrb5_verify_8003_checksum(minor_status,
477                                                 input_chan_bindings,
478                                                 authenticator->cksum,
479                                                 &ctx->flags,
480                                                 &ctx->fwd_data);
481
482             krb5_free_authenticator(context, &authenticator);
483             if (ret) {
484                 return ret;
485             }
486         } else {
487             krb5_crypto crypto;
488
489             kret = krb5_crypto_init(context, 
490                                     ctx->auth_context->keyblock, 
491                                     0, &crypto);
492             if(kret) {
493                 krb5_free_authenticator(context, &authenticator);
494
495                 ret = GSS_S_FAILURE;
496                 *minor_status = kret;
497                 return ret;
498             }
499
500             /* 
501              * Windows accepts Samba3's use of a kerberos, rather than
502              * GSSAPI checksum here 
503              */
504
505             kret = krb5_verify_checksum(context,
506                                         crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
507                                         authenticator->cksum);
508             krb5_free_authenticator(context, &authenticator);
509             krb5_crypto_destroy(context, crypto);
510
511             if(kret) {
512                 ret = GSS_S_BAD_SIG;
513                 *minor_status = kret;
514                 return ret;
515             }
516
517             /* 
518              * Samba style get some flags (but not DCE-STYLE)
519              */
520             ctx->flags = 
521                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
522         }
523     }
524     
525     if(ctx->flags & GSS_C_MUTUAL_FLAG) {
526         krb5_data outbuf;
527         int use_subkey = 0;
528             
529         _gsskrb5i_is_cfx(ctx, &is_cfx);
530             
531         if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
532             use_subkey = 1;
533         } else {
534             krb5_keyblock *rkey;
535
536             /* 
537              * If there is a initiator subkey, copy that to acceptor
538              * subkey to match Windows behavior
539              */
540             kret = krb5_auth_con_getremotesubkey(context,
541                                                  ctx->auth_context,
542                                                  &rkey);
543             if (kret == 0) {
544                 kret = krb5_auth_con_setlocalsubkey(context, 
545                                                     ctx->auth_context,
546                                                     rkey);
547                 if (kret == 0)
548                     use_subkey = 1;
549                 krb5_free_keyblock(context, rkey);
550             }
551         }
552         if (use_subkey) {
553             ctx->more_flags |= ACCEPTOR_SUBKEY;
554             krb5_auth_con_addflags(context, ctx->auth_context,
555                                    KRB5_AUTH_CONTEXT_USE_SUBKEY,
556                                    NULL);
557         }
558             
559         kret = krb5_mk_rep(context,
560                            ctx->auth_context,
561                            &outbuf);
562         if (kret) {
563             *minor_status = kret;
564             return GSS_S_FAILURE;
565         }
566             
567         if (IS_DCE_STYLE(ctx)) {
568             output_token->length = outbuf.length;
569             output_token->value = outbuf.data;
570         } else {
571             ret = _gsskrb5_encapsulate(minor_status,
572                                        &outbuf,
573                                        output_token,
574                                        "\x02\x00",
575                                        GSS_KRB5_MECHANISM);
576             krb5_data_free (&outbuf);
577             if (ret)
578                 return ret;
579         }
580     }
581     
582     ctx->flags |= GSS_C_TRANS_FLAG;
583
584     /* Remember the flags */
585     
586     ctx->lifetime = ctx->ticket->ticket.endtime;
587     ctx->more_flags |= OPEN;
588     
589     if (mech_type)
590         *mech_type = GSS_KRB5_MECHANISM;
591     
592     if (time_rec) {
593         ret = _gsskrb5_lifetime_left(minor_status,
594                                      context,
595                                      ctx->lifetime,
596                                      time_rec);
597         if (ret) {
598             return ret;
599         }
600     }
601
602     /*
603      * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
604      * the client.
605      */
606     if (IS_DCE_STYLE(ctx)) {
607         /*
608          * Return flags to caller, but we haven't processed
609          * delgations yet
610          */
611         if (ret_flags)
612             *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
613
614         ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
615         return GSS_S_CONTINUE_NEEDED;
616     }
617
618     ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 
619                                  delegated_cred_handle);
620
621     if (ret_flags)
622         *ret_flags = ctx->flags;
623
624     return ret;
625 }
626
627 static OM_uint32
628 acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
629                            gsskrb5_ctx ctx,
630                            krb5_context context,
631                            const gss_cred_id_t acceptor_cred_handle,
632                            const gss_buffer_t input_token_buffer,
633                            const gss_channel_bindings_t input_chan_bindings,
634                            gss_name_t * src_name,
635                            gss_OID * mech_type,
636                            gss_buffer_t output_token,
637                            OM_uint32 * ret_flags,
638                            OM_uint32 * time_rec,
639                            gss_cred_id_t * delegated_cred_handle)
640 {
641     OM_uint32 ret;
642     krb5_error_code kret;
643     krb5_data inbuf;
644     int32_t r_seq_number, l_seq_number;
645         
646     /* 
647      * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
648      */
649
650     inbuf.length = input_token_buffer->length;
651     inbuf.data = input_token_buffer->value;
652
653     /* 
654      * We need to remeber the old remote seq_number, then check if the
655      * client has replied with our local seq_number, and then reset
656      * the remote seq_number to the old value
657      */
658     {
659         kret = krb5_auth_con_getlocalseqnumber(context,
660                                                ctx->auth_context,
661                                                &l_seq_number);
662         if (kret) {
663             *minor_status = kret;
664             return GSS_S_FAILURE;
665         }
666
667         kret = krb5_auth_getremoteseqnumber(context,
668                                             ctx->auth_context,
669                                             &r_seq_number);
670         if (kret) {
671             *minor_status = kret;
672             return GSS_S_FAILURE;
673         }
674
675         kret = krb5_auth_con_setremoteseqnumber(context,
676                                                 ctx->auth_context,
677                                                 l_seq_number);
678         if (kret) {
679             *minor_status = kret;
680             return GSS_S_FAILURE;
681         }
682     }
683
684     /* 
685      * We need to verify the AP_REP, but we need to flag that this is
686      * DCE_STYLE, so don't check the timestamps this time, but put the
687      * flag DO_TIME back afterward.
688     */ 
689     {
690         krb5_ap_rep_enc_part *repl;
691         int32_t auth_flags;
692                 
693         krb5_auth_con_removeflags(context,
694                                   ctx->auth_context,
695                                   KRB5_AUTH_CONTEXT_DO_TIME,
696                                   &auth_flags);
697
698         kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
699         if (kret) {
700             *minor_status = kret;
701             return GSS_S_FAILURE;
702         }
703         krb5_free_ap_rep_enc_part(context, repl);
704         krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
705     }
706
707     /* We need to check the liftime */
708     {
709         OM_uint32 lifetime_rec;
710
711         ret = _gsskrb5_lifetime_left(minor_status,
712                                      context,
713                                      ctx->lifetime,
714                                      &lifetime_rec);
715         if (ret) {
716             return ret;
717         }
718         if (lifetime_rec == 0) {
719             return GSS_S_CONTEXT_EXPIRED;
720         }
721         
722         if (time_rec) *time_rec = lifetime_rec;
723     }
724
725     /* We need to give the caller the flags which are in use */
726     if (ret_flags) *ret_flags = ctx->flags;
727
728     if (src_name) {
729         kret = krb5_copy_principal(context,
730                                    ctx->source,
731                                    (gsskrb5_name*)src_name);
732         if (kret) {
733             *minor_status = kret;
734             return GSS_S_FAILURE;
735         }
736     }
737
738     /*
739      * After the krb5_rd_rep() the remote and local seq_number should
740      * be the same, because the client just replies the seq_number
741      * from our AP-REP in its AP-REP, but then the client uses the
742      * seq_number from its AP-REQ for GSS_wrap()
743      */
744     {
745         int32_t tmp_r_seq_number, tmp_l_seq_number;
746
747         kret = krb5_auth_getremoteseqnumber(context,
748                                             ctx->auth_context,
749                                             &tmp_r_seq_number);
750         if (kret) {
751             *minor_status = kret;
752             return GSS_S_FAILURE;
753         }
754
755         kret = krb5_auth_con_getlocalseqnumber(context,
756                                                ctx->auth_context,
757                                                &tmp_l_seq_number);
758         if (kret) {
759
760             *minor_status = kret;
761             return GSS_S_FAILURE;
762         }
763
764         /*
765          * Here we check if the client has responsed with our local seq_number,
766          */
767         if (tmp_r_seq_number != tmp_l_seq_number) {
768             return GSS_S_UNSEQ_TOKEN;
769         }
770     }
771
772     /*
773      * We need to reset the remote seq_number, because the client will use,
774      * the old one for the GSS_wrap() calls
775      */
776     {
777         kret = krb5_auth_con_setremoteseqnumber(context,
778                                                 ctx->auth_context,
779                                                 r_seq_number);  
780         if (kret) {
781             *minor_status = kret;
782             return GSS_S_FAILURE;
783         }
784     }
785
786     return gsskrb5_acceptor_ready(minor_status, ctx, context, 
787                                   delegated_cred_handle);
788 }
789
790
791 OM_uint32
792 _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
793                             gss_ctx_id_t * context_handle,
794                             const gss_cred_id_t acceptor_cred_handle,
795                             const gss_buffer_t input_token_buffer,
796                             const gss_channel_bindings_t input_chan_bindings,
797                             gss_name_t * src_name,
798                             gss_OID * mech_type,
799                             gss_buffer_t output_token,
800                             OM_uint32 * ret_flags,
801                             OM_uint32 * time_rec,
802                             gss_cred_id_t * delegated_cred_handle)
803 {
804     krb5_context context;
805     OM_uint32 ret;
806     gsskrb5_ctx ctx;
807
808     GSSAPI_KRB5_INIT(&context);
809
810     output_token->length = 0;
811     output_token->value = NULL;
812
813     if (src_name != NULL)
814         *src_name = NULL;
815     if (mech_type)
816         *mech_type = GSS_KRB5_MECHANISM;
817
818     if (*context_handle == GSS_C_NO_CONTEXT) {
819         ret = _gsskrb5_create_ctx(minor_status,
820                                   context_handle,
821                                   context,
822                                   input_chan_bindings,
823                                   ACCEPTOR_START);
824         if (ret)
825             return ret;
826     }
827     
828     ctx = (gsskrb5_ctx)*context_handle;
829
830     
831     /*
832      * TODO: check the channel_bindings 
833      * (above just sets them to krb5 layer)
834      */
835
836     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
837     
838     switch (ctx->state) {
839     case ACCEPTOR_START:
840         ret = gsskrb5_acceptor_start(minor_status,
841                                      ctx,
842                                      context,
843                                      acceptor_cred_handle,
844                                      input_token_buffer,
845                                      input_chan_bindings,
846                                      src_name,
847                                      mech_type,
848                                      output_token,
849                                      ret_flags,
850                                      time_rec,
851                                      delegated_cred_handle);
852         break;
853     case ACCEPTOR_WAIT_FOR_DCESTYLE:
854         ret = acceptor_wait_for_dcestyle(minor_status,
855                                          ctx,
856                                          context,
857                                          acceptor_cred_handle,
858                                          input_token_buffer,
859                                          input_chan_bindings,
860                                          src_name,
861                                          mech_type,
862                                          output_token,
863                                          ret_flags,
864                                          time_rec,
865                                          delegated_cred_handle);
866         break;
867     case ACCEPTOR_READY:
868         /* 
869          * If we get there, the caller have called
870          * gss_accept_sec_context() one time too many.
871          */
872         ret =  GSS_S_BAD_STATUS;
873         break;
874     default:
875         /* TODO: is this correct here? --metze */
876         ret =  GSS_S_BAD_STATUS;
877         break;
878     }
879     
880     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
881     
882     if (GSS_ERROR(ret)) {
883         OM_uint32 min2;
884         _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
885     }
886
887     return ret;
888 }