]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - crypto/heimdal/lib/gssapi/krb5/accept_sec_context.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / crypto / 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 "gsskrb5_locl.h"
35
36 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
37 krb5_keytab _gsskrb5_keytab;
38
39 static krb5_error_code
40 validate_keytab(krb5_context context, const char *name, krb5_keytab *id)
41 {
42     krb5_error_code ret;
43
44     ret = krb5_kt_resolve(context, name, id);
45     if (ret)
46         return ret;
47
48     ret = krb5_kt_have_content(context, *id);
49     if (ret) {
50         krb5_kt_close(context, *id);
51         *id = NULL;
52     }
53
54     return ret;
55 }
56
57 OM_uint32
58 _gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity)
59 {
60     krb5_context context;
61     krb5_error_code ret;
62
63     *min_stat = 0;
64
65     ret = _gsskrb5_init(&context);
66     if(ret)
67         return GSS_S_FAILURE;
68
69     HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
70
71     if(_gsskrb5_keytab != NULL) {
72         krb5_kt_close(context, _gsskrb5_keytab);
73         _gsskrb5_keytab = NULL;
74     }
75     if (identity == NULL) {
76         ret = krb5_kt_default(context, &_gsskrb5_keytab);
77     } else {
78         /*
79          * First check if we can the keytab as is and if it has content...
80          */
81         ret = validate_keytab(context, identity, &_gsskrb5_keytab);
82         /*
83          * if it doesn't, lets prepend FILE: and try again
84          */
85         if (ret) {
86             char *p = NULL;
87             ret = asprintf(&p, "FILE:%s", identity);
88             if(ret < 0 || p == NULL) {
89                 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
90                 return GSS_S_FAILURE;
91             }
92             ret = validate_keytab(context, p, &_gsskrb5_keytab);
93             free(p);
94         }
95     }
96     HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
97     if(ret) {
98         *min_stat = ret;
99         return GSS_S_FAILURE;
100     }
101     return GSS_S_COMPLETE;
102 }
103
104 void
105 _gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor)
106 {
107     krb5_error_code ret;
108     krb5_keyblock *key;
109
110     if (acceptor) {
111         if (ctx->auth_context->local_subkey)
112             key = ctx->auth_context->local_subkey;
113         else
114             key = ctx->auth_context->remote_subkey;
115     } else {
116         if (ctx->auth_context->remote_subkey)
117             key = ctx->auth_context->remote_subkey;
118         else
119             key = ctx->auth_context->local_subkey;
120     }
121     if (key == NULL)
122         key = ctx->auth_context->keyblock;
123
124     if (key == NULL)
125         return;
126
127     switch (key->keytype) {
128     case ETYPE_DES_CBC_CRC:
129     case ETYPE_DES_CBC_MD4:
130     case ETYPE_DES_CBC_MD5:
131     case ETYPE_DES3_CBC_MD5:
132     case ETYPE_OLD_DES3_CBC_SHA1:
133     case ETYPE_DES3_CBC_SHA1:
134     case ETYPE_ARCFOUR_HMAC_MD5:
135     case ETYPE_ARCFOUR_HMAC_MD5_56:
136         break;
137     default :
138         ctx->more_flags |= IS_CFX;
139
140         if ((acceptor && ctx->auth_context->local_subkey) ||
141             (!acceptor && ctx->auth_context->remote_subkey))
142             ctx->more_flags |= ACCEPTOR_SUBKEY;
143         break;
144     }
145     if (ctx->crypto)
146         krb5_crypto_destroy(context, ctx->crypto);
147     ret = krb5_crypto_init(context, key, 0, &ctx->crypto);
148 }
149
150
151 static OM_uint32
152 gsskrb5_accept_delegated_token
153 (OM_uint32 * minor_status,
154  gsskrb5_ctx ctx,
155  krb5_context context,
156  gss_cred_id_t * delegated_cred_handle
157     )
158 {
159     krb5_ccache ccache = NULL;
160     krb5_error_code kret;
161     int32_t ac_flags, ret = GSS_S_COMPLETE;
162
163     *minor_status = 0;
164
165     /* XXX Create a new delegated_cred_handle? */
166     if (delegated_cred_handle == NULL) {
167         kret = krb5_cc_default (context, &ccache);
168     } else {
169         *delegated_cred_handle = NULL;
170         kret = krb5_cc_new_unique (context, krb5_cc_type_memory,
171                                    NULL, &ccache);
172     }
173     if (kret) {
174         ctx->flags &= ~GSS_C_DELEG_FLAG;
175         goto out;
176     }
177
178     kret = krb5_cc_initialize(context, ccache, ctx->source);
179     if (kret) {
180         ctx->flags &= ~GSS_C_DELEG_FLAG;
181         goto out;
182     }
183
184     krb5_auth_con_removeflags(context,
185                               ctx->auth_context,
186                               KRB5_AUTH_CONTEXT_DO_TIME,
187                               &ac_flags);
188     kret = krb5_rd_cred2(context,
189                          ctx->auth_context,
190                          ccache,
191                          &ctx->fwd_data);
192     krb5_auth_con_setflags(context,
193                            ctx->auth_context,
194                            ac_flags);
195     if (kret) {
196         ctx->flags &= ~GSS_C_DELEG_FLAG;
197         ret = GSS_S_FAILURE;
198         *minor_status = kret;
199         goto out;
200     }
201
202     if (delegated_cred_handle) {
203         gsskrb5_cred handle;
204
205         ret = _gsskrb5_krb5_import_cred(minor_status,
206                                         ccache,
207                                         NULL,
208                                         NULL,
209                                         delegated_cred_handle);
210         if (ret != GSS_S_COMPLETE)
211             goto out;
212
213         handle = (gsskrb5_cred) *delegated_cred_handle;
214
215         handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
216         krb5_cc_close(context, ccache);
217         ccache = NULL;
218     }
219
220 out:
221     if (ccache) {
222         /* Don't destroy the default cred cache */
223         if (delegated_cred_handle == NULL)
224             krb5_cc_close(context, ccache);
225         else
226             krb5_cc_destroy(context, ccache);
227     }
228     return ret;
229 }
230
231 static OM_uint32
232 gsskrb5_acceptor_ready(OM_uint32 * minor_status,
233                        gsskrb5_ctx ctx,
234                        krb5_context context,
235                        gss_cred_id_t *delegated_cred_handle)
236 {
237     OM_uint32 ret;
238     int32_t seq_number;
239     int is_cfx = 0;
240
241     krb5_auth_con_getremoteseqnumber (context,
242                                       ctx->auth_context,
243                                       &seq_number);
244
245     _gsskrb5i_is_cfx(context, ctx, 1);
246     is_cfx = (ctx->more_flags & IS_CFX);
247
248     ret = _gssapi_msg_order_create(minor_status,
249                                    &ctx->order,
250                                    _gssapi_msg_order_f(ctx->flags),
251                                    seq_number, 0, is_cfx);
252     if (ret)
253         return ret;
254
255     /*
256      * If requested, set local sequence num to remote sequence if this
257      * isn't a mutual authentication context
258      */
259     if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) {
260         krb5_auth_con_setlocalseqnumber(context,
261                                         ctx->auth_context,
262                                         seq_number);
263     }
264
265     /*
266      * We should handle the delegation ticket, in case it's there
267      */
268     if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) {
269         ret = gsskrb5_accept_delegated_token(minor_status,
270                                              ctx,
271                                              context,
272                                              delegated_cred_handle);
273         if (ret)
274             return ret;
275     } else {
276         /* Well, looks like it wasn't there after all */
277         ctx->flags &= ~GSS_C_DELEG_FLAG;
278     }
279
280     ctx->state = ACCEPTOR_READY;
281     ctx->more_flags |= OPEN;
282
283     return GSS_S_COMPLETE;
284 }
285
286 static OM_uint32
287 send_error_token(OM_uint32 *minor_status,
288                  krb5_context context,
289                  krb5_error_code kret,
290                  krb5_principal server,
291                  krb5_data *indata,
292                  gss_buffer_t output_token)
293 {
294     krb5_principal ap_req_server = NULL;
295     krb5_error_code ret;
296     krb5_data outbuf;
297     /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which
298        tells windows to try again with the corrected timestamp. See
299        [MS-KILE] 2.2.1 KERB-ERROR-DATA */
300     krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") };
301
302     /* build server from request if the acceptor had not selected one */
303     if (server == NULL) {
304         AP_REQ ap_req;
305
306         ret = krb5_decode_ap_req(context, indata, &ap_req);
307         if (ret) {
308             *minor_status = ret;
309             return GSS_S_FAILURE;
310         }
311         ret = _krb5_principalname2krb5_principal(context,
312                                                   &ap_req_server,
313                                                   ap_req.ticket.sname,
314                                                   ap_req.ticket.realm);
315         free_AP_REQ(&ap_req);
316         if (ret) {
317             *minor_status = ret;
318             return GSS_S_FAILURE;
319         }
320         server = ap_req_server;
321     }
322
323     ret = krb5_mk_error(context, kret, NULL, &e_data, NULL,
324                         server, NULL, NULL, &outbuf);
325     if (ap_req_server)
326         krb5_free_principal(context, ap_req_server);
327     if (ret) {
328         *minor_status = ret;
329         return GSS_S_FAILURE;
330     }
331
332     ret = _gsskrb5_encapsulate(minor_status,
333                                &outbuf,
334                                output_token,
335                                "\x03\x00",
336                                GSS_KRB5_MECHANISM);
337     krb5_data_free (&outbuf);
338     if (ret)
339         return ret;
340
341     *minor_status = 0;
342     return GSS_S_CONTINUE_NEEDED;
343 }
344
345
346 static OM_uint32
347 gsskrb5_acceptor_start(OM_uint32 * minor_status,
348                        gsskrb5_ctx ctx,
349                        krb5_context context,
350                        const gss_cred_id_t acceptor_cred_handle,
351                        const gss_buffer_t input_token_buffer,
352                        const gss_channel_bindings_t input_chan_bindings,
353                        gss_name_t * src_name,
354                        gss_OID * mech_type,
355                        gss_buffer_t output_token,
356                        OM_uint32 * ret_flags,
357                        OM_uint32 * time_rec,
358                        gss_cred_id_t * delegated_cred_handle)
359 {
360     krb5_error_code kret;
361     OM_uint32 ret = GSS_S_COMPLETE;
362     krb5_data indata;
363     krb5_flags ap_options;
364     krb5_keytab keytab = NULL;
365     int is_cfx = 0;
366     const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
367
368     /*
369      * We may, or may not, have an escapsulation.
370      */
371     ret = _gsskrb5_decapsulate (minor_status,
372                                 input_token_buffer,
373                                 &indata,
374                                 "\x01\x00",
375                                 GSS_KRB5_MECHANISM);
376
377     if (ret) {
378         /* Assume that there is no OID wrapping. */
379         indata.length   = input_token_buffer->length;
380         indata.data     = input_token_buffer->value;
381     }
382
383     /*
384      * We need to get our keytab
385      */
386     if (acceptor_cred == NULL) {
387         if (_gsskrb5_keytab != NULL)
388             keytab = _gsskrb5_keytab;
389     } else if (acceptor_cred->keytab != NULL) {
390         keytab = acceptor_cred->keytab;
391     }
392
393     /*
394      * We need to check the ticket and create the AP-REP packet
395      */
396
397     {
398         krb5_rd_req_in_ctx in = NULL;
399         krb5_rd_req_out_ctx out = NULL;
400         krb5_principal server = NULL;
401
402         if (acceptor_cred)
403             server = acceptor_cred->principal;
404
405         kret = krb5_rd_req_in_ctx_alloc(context, &in);
406         if (kret == 0)
407             kret = krb5_rd_req_in_set_keytab(context, in, keytab);
408         if (kret) {
409             if (in)
410                 krb5_rd_req_in_ctx_free(context, in);
411             *minor_status = kret;
412             return GSS_S_FAILURE;
413         }
414
415         kret = krb5_rd_req_ctx(context,
416                                &ctx->auth_context,
417                                &indata,
418                                server,
419                                in, &out);
420         krb5_rd_req_in_ctx_free(context, in);
421         if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {
422             /*
423              * No reply in non-MUTUAL mode, but we don't know that its
424              * non-MUTUAL mode yet, thats inside the 8003 checksum, so
425              * lets only send the error token on clock skew, that
426              * limit when send error token for non-MUTUAL.
427              */
428             return send_error_token(minor_status, context, kret,
429                                     server, &indata, output_token);
430         } else if (kret) {
431             *minor_status = kret;
432             return GSS_S_FAILURE;
433         }
434
435         /*
436          * we need to remember some data on the context_handle.
437          */
438         kret = krb5_rd_req_out_get_ap_req_options(context, out,
439                                                   &ap_options);
440         if (kret == 0)
441             kret = krb5_rd_req_out_get_ticket(context, out,
442                                               &ctx->ticket);
443         if (kret == 0)
444             kret = krb5_rd_req_out_get_keyblock(context, out,
445                                                 &ctx->service_keyblock);
446         ctx->lifetime = ctx->ticket->ticket.endtime;
447
448         krb5_rd_req_out_ctx_free(context, out);
449         if (kret) {
450             ret = GSS_S_FAILURE;
451             *minor_status = kret;
452             return ret;
453         }
454     }
455
456
457     /*
458      * We need to copy the principal names to the context and the
459      * calling layer.
460      */
461     kret = krb5_copy_principal(context,
462                                ctx->ticket->client,
463                                &ctx->source);
464     if (kret) {
465         ret = GSS_S_FAILURE;
466         *minor_status = kret;
467     }
468
469     kret = krb5_copy_principal(context,
470                                ctx->ticket->server,
471                                &ctx->target);
472     if (kret) {
473         ret = GSS_S_FAILURE;
474         *minor_status = kret;
475         return ret;
476     }
477
478     /*
479      * We need to setup some compat stuff, this assumes that
480      * context_handle->target is already set.
481      */
482     ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
483     if (ret)
484         return ret;
485
486     if (src_name != NULL) {
487         kret = krb5_copy_principal (context,
488                                     ctx->ticket->client,
489                                     (gsskrb5_name*)src_name);
490         if (kret) {
491             ret = GSS_S_FAILURE;
492             *minor_status = kret;
493             return ret;
494         }
495     }
496
497     /*
498      * We need to get the flags out of the 8003 checksum.
499      */
500
501     {
502         krb5_authenticator authenticator;
503
504         kret = krb5_auth_con_getauthenticator(context,
505                                               ctx->auth_context,
506                                               &authenticator);
507         if(kret) {
508             ret = GSS_S_FAILURE;
509             *minor_status = kret;
510             return ret;
511         }
512
513         if (authenticator->cksum == NULL) {
514             krb5_free_authenticator(context, &authenticator);
515             *minor_status = 0;
516             return GSS_S_BAD_BINDINGS;
517         }
518
519         if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
520             ret = _gsskrb5_verify_8003_checksum(minor_status,
521                                                 input_chan_bindings,
522                                                 authenticator->cksum,
523                                                 &ctx->flags,
524                                                 &ctx->fwd_data);
525
526             krb5_free_authenticator(context, &authenticator);
527             if (ret) {
528                 return ret;
529             }
530         } else {
531             krb5_crypto crypto;
532
533             kret = krb5_crypto_init(context,
534                                     ctx->auth_context->keyblock,
535                                     0, &crypto);
536             if(kret) {
537                 krb5_free_authenticator(context, &authenticator);
538
539                 ret = GSS_S_FAILURE;
540                 *minor_status = kret;
541                 return ret;
542             }
543
544             /*
545              * Windows accepts Samba3's use of a kerberos, rather than
546              * GSSAPI checksum here
547              */
548
549             kret = krb5_verify_checksum(context,
550                                         crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
551                                         authenticator->cksum);
552             krb5_free_authenticator(context, &authenticator);
553             krb5_crypto_destroy(context, crypto);
554
555             if(kret) {
556                 ret = GSS_S_BAD_SIG;
557                 *minor_status = kret;
558                 return ret;
559             }
560
561             /*
562              * Samba style get some flags (but not DCE-STYLE), use
563              * ap_options to guess the mutual flag.
564              */
565             ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
566             if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
567                 ctx->flags |= GSS_C_MUTUAL_FLAG;
568         }
569     }
570
571     if(ctx->flags & GSS_C_MUTUAL_FLAG) {
572         krb5_data outbuf;
573         int use_subkey = 0;
574
575         _gsskrb5i_is_cfx(context, ctx, 1);
576         is_cfx = (ctx->more_flags & IS_CFX);
577
578         if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
579             use_subkey = 1;
580         } else {
581             krb5_keyblock *rkey;
582
583             /*
584              * If there is a initiator subkey, copy that to acceptor
585              * subkey to match Windows behavior
586              */
587             kret = krb5_auth_con_getremotesubkey(context,
588                                                  ctx->auth_context,
589                                                  &rkey);
590             if (kret == 0) {
591                 kret = krb5_auth_con_setlocalsubkey(context,
592                                                     ctx->auth_context,
593                                                     rkey);
594                 if (kret == 0)
595                     use_subkey = 1;
596                 krb5_free_keyblock(context, rkey);
597             }
598         }
599         if (use_subkey) {
600             ctx->more_flags |= ACCEPTOR_SUBKEY;
601             krb5_auth_con_addflags(context, ctx->auth_context,
602                                    KRB5_AUTH_CONTEXT_USE_SUBKEY,
603                                    NULL);
604         }
605
606         kret = krb5_mk_rep(context,
607                            ctx->auth_context,
608                            &outbuf);
609         if (kret) {
610             *minor_status = kret;
611             return GSS_S_FAILURE;
612         }
613
614         if (IS_DCE_STYLE(ctx)) {
615             output_token->length = outbuf.length;
616             output_token->value = outbuf.data;
617         } else {
618             ret = _gsskrb5_encapsulate(minor_status,
619                                        &outbuf,
620                                        output_token,
621                                        "\x02\x00",
622                                        GSS_KRB5_MECHANISM);
623             krb5_data_free (&outbuf);
624             if (ret)
625                 return ret;
626         }
627     }
628
629     ctx->flags |= GSS_C_TRANS_FLAG;
630
631     /* Remember the flags */
632
633     ctx->lifetime = ctx->ticket->ticket.endtime;
634     ctx->more_flags |= OPEN;
635
636     if (mech_type)
637         *mech_type = GSS_KRB5_MECHANISM;
638
639     if (time_rec) {
640         ret = _gsskrb5_lifetime_left(minor_status,
641                                      context,
642                                      ctx->lifetime,
643                                      time_rec);
644         if (ret) {
645             return ret;
646         }
647     }
648
649     /*
650      * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
651      * the client.
652      */
653     if (IS_DCE_STYLE(ctx)) {
654         /*
655          * Return flags to caller, but we haven't processed
656          * delgations yet
657          */
658         if (ret_flags)
659             *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);
660
661         ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
662         return GSS_S_CONTINUE_NEEDED;
663     }
664
665     ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
666                                  delegated_cred_handle);
667
668     if (ret_flags)
669         *ret_flags = ctx->flags;
670
671     return ret;
672 }
673
674 static OM_uint32
675 acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
676                            gsskrb5_ctx ctx,
677                            krb5_context context,
678                            const gss_cred_id_t acceptor_cred_handle,
679                            const gss_buffer_t input_token_buffer,
680                            const gss_channel_bindings_t input_chan_bindings,
681                            gss_name_t * src_name,
682                            gss_OID * mech_type,
683                            gss_buffer_t output_token,
684                            OM_uint32 * ret_flags,
685                            OM_uint32 * time_rec,
686                            gss_cred_id_t * delegated_cred_handle)
687 {
688     OM_uint32 ret;
689     krb5_error_code kret;
690     krb5_data inbuf;
691     int32_t r_seq_number, l_seq_number;
692
693     /*
694      * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
695      */
696
697     inbuf.length = input_token_buffer->length;
698     inbuf.data = input_token_buffer->value;
699
700     /*
701      * We need to remeber the old remote seq_number, then check if the
702      * client has replied with our local seq_number, and then reset
703      * the remote seq_number to the old value
704      */
705     {
706         kret = krb5_auth_con_getlocalseqnumber(context,
707                                                ctx->auth_context,
708                                                &l_seq_number);
709         if (kret) {
710             *minor_status = kret;
711             return GSS_S_FAILURE;
712         }
713
714         kret = krb5_auth_con_getremoteseqnumber(context,
715                                                 ctx->auth_context,
716                                                 &r_seq_number);
717         if (kret) {
718             *minor_status = kret;
719             return GSS_S_FAILURE;
720         }
721
722         kret = krb5_auth_con_setremoteseqnumber(context,
723                                                 ctx->auth_context,
724                                                 l_seq_number);
725         if (kret) {
726             *minor_status = kret;
727             return GSS_S_FAILURE;
728         }
729     }
730
731     /*
732      * We need to verify the AP_REP, but we need to flag that this is
733      * DCE_STYLE, so don't check the timestamps this time, but put the
734      * flag DO_TIME back afterward.
735     */
736     {
737         krb5_ap_rep_enc_part *repl;
738         int32_t auth_flags;
739
740         krb5_auth_con_removeflags(context,
741                                   ctx->auth_context,
742                                   KRB5_AUTH_CONTEXT_DO_TIME,
743                                   &auth_flags);
744
745         kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
746         if (kret) {
747             *minor_status = kret;
748             return GSS_S_FAILURE;
749         }
750         krb5_free_ap_rep_enc_part(context, repl);
751         krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
752     }
753
754     /* We need to check the liftime */
755     {
756         OM_uint32 lifetime_rec;
757
758         ret = _gsskrb5_lifetime_left(minor_status,
759                                      context,
760                                      ctx->lifetime,
761                                      &lifetime_rec);
762         if (ret) {
763             return ret;
764         }
765         if (lifetime_rec == 0) {
766             return GSS_S_CONTEXT_EXPIRED;
767         }
768
769         if (time_rec) *time_rec = lifetime_rec;
770     }
771
772     /* We need to give the caller the flags which are in use */
773     if (ret_flags) *ret_flags = ctx->flags;
774
775     if (src_name) {
776         kret = krb5_copy_principal(context,
777                                    ctx->source,
778                                    (gsskrb5_name*)src_name);
779         if (kret) {
780             *minor_status = kret;
781             return GSS_S_FAILURE;
782         }
783     }
784
785     /*
786      * After the krb5_rd_rep() the remote and local seq_number should
787      * be the same, because the client just replies the seq_number
788      * from our AP-REP in its AP-REP, but then the client uses the
789      * seq_number from its AP-REQ for GSS_wrap()
790      */
791     {
792         int32_t tmp_r_seq_number, tmp_l_seq_number;
793
794         kret = krb5_auth_con_getremoteseqnumber(context,
795                                                 ctx->auth_context,
796                                                 &tmp_r_seq_number);
797         if (kret) {
798             *minor_status = kret;
799             return GSS_S_FAILURE;
800         }
801
802         kret = krb5_auth_con_getlocalseqnumber(context,
803                                                ctx->auth_context,
804                                                &tmp_l_seq_number);
805         if (kret) {
806
807             *minor_status = kret;
808             return GSS_S_FAILURE;
809         }
810
811         /*
812          * Here we check if the client has responsed with our local seq_number,
813          */
814         if (tmp_r_seq_number != tmp_l_seq_number) {
815             return GSS_S_UNSEQ_TOKEN;
816         }
817     }
818
819     /*
820      * We need to reset the remote seq_number, because the client will use,
821      * the old one for the GSS_wrap() calls
822      */
823     {
824         kret = krb5_auth_con_setremoteseqnumber(context,
825                                                 ctx->auth_context,
826                                                 r_seq_number);
827         if (kret) {
828             *minor_status = kret;
829             return GSS_S_FAILURE;
830         }
831     }
832
833     return gsskrb5_acceptor_ready(minor_status, ctx, context,
834                                   delegated_cred_handle);
835 }
836
837
838 OM_uint32 GSSAPI_CALLCONV
839 _gsskrb5_accept_sec_context(OM_uint32 * minor_status,
840                             gss_ctx_id_t * context_handle,
841                             const gss_cred_id_t acceptor_cred_handle,
842                             const gss_buffer_t input_token_buffer,
843                             const gss_channel_bindings_t input_chan_bindings,
844                             gss_name_t * src_name,
845                             gss_OID * mech_type,
846                             gss_buffer_t output_token,
847                             OM_uint32 * ret_flags,
848                             OM_uint32 * time_rec,
849                             gss_cred_id_t * delegated_cred_handle)
850 {
851     krb5_context context;
852     OM_uint32 ret;
853     gsskrb5_ctx ctx;
854
855     GSSAPI_KRB5_INIT(&context);
856
857     output_token->length = 0;
858     output_token->value = NULL;
859
860     if (src_name != NULL)
861         *src_name = NULL;
862     if (mech_type)
863         *mech_type = GSS_KRB5_MECHANISM;
864
865     if (*context_handle == GSS_C_NO_CONTEXT) {
866         ret = _gsskrb5_create_ctx(minor_status,
867                                   context_handle,
868                                   context,
869                                   input_chan_bindings,
870                                   ACCEPTOR_START);
871         if (ret)
872             return ret;
873     }
874
875     ctx = (gsskrb5_ctx)*context_handle;
876
877
878     /*
879      * TODO: check the channel_bindings
880      * (above just sets them to krb5 layer)
881      */
882
883     HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
884
885     switch (ctx->state) {
886     case ACCEPTOR_START:
887         ret = gsskrb5_acceptor_start(minor_status,
888                                      ctx,
889                                      context,
890                                      acceptor_cred_handle,
891                                      input_token_buffer,
892                                      input_chan_bindings,
893                                      src_name,
894                                      mech_type,
895                                      output_token,
896                                      ret_flags,
897                                      time_rec,
898                                      delegated_cred_handle);
899         break;
900     case ACCEPTOR_WAIT_FOR_DCESTYLE:
901         ret = acceptor_wait_for_dcestyle(minor_status,
902                                          ctx,
903                                          context,
904                                          acceptor_cred_handle,
905                                          input_token_buffer,
906                                          input_chan_bindings,
907                                          src_name,
908                                          mech_type,
909                                          output_token,
910                                          ret_flags,
911                                          time_rec,
912                                          delegated_cred_handle);
913         break;
914     case ACCEPTOR_READY:
915         /*
916          * If we get there, the caller have called
917          * gss_accept_sec_context() one time too many.
918          */
919         ret =  GSS_S_BAD_STATUS;
920         break;
921     default:
922         /* TODO: is this correct here? --metze */
923         ret =  GSS_S_BAD_STATUS;
924         break;
925     }
926
927     HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
928
929     if (GSS_ERROR(ret)) {
930         OM_uint32 min2;
931         _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER);
932     }
933
934     return ret;
935 }