r11452: Update Heimdal to current lorikeet, including removing the ccache side
[gd/samba-autobuild/.git] / source4 / heimdal / lib / gssapi / accept_sec_context.c
1 /*
2  * Copyright (c) 1997 - 2003 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 "gssapi_locl.h"
35
36 RCSID("$Id: accept_sec_context.c,v 1.53 2005/05/29 15:12:41 lha Exp $");
37
38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER;
39 krb5_keytab gssapi_krb5_keytab;
40
41 OM_uint32
42 gsskrb5_register_acceptor_identity (const char *identity)
43 {
44     krb5_error_code ret;
45
46     ret = gssapi_krb5_init();
47     if(ret)
48         return GSS_S_FAILURE;
49     
50     HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
51
52     if(gssapi_krb5_keytab != NULL) {
53         krb5_kt_close(gssapi_krb5_context, gssapi_krb5_keytab);
54         gssapi_krb5_keytab = NULL;
55     }
56     if (identity == NULL) {
57         ret = krb5_kt_default(gssapi_krb5_context, &gssapi_krb5_keytab);
58     } else {
59         char *p;
60
61         asprintf(&p, "FILE:%s", identity);
62         if(p == NULL) {
63             HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
64             return GSS_S_FAILURE;
65         }
66         ret = krb5_kt_resolve(gssapi_krb5_context, p, &gssapi_krb5_keytab);
67         free(p);
68     }
69     HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
70     if(ret)
71         return GSS_S_FAILURE;
72     return GSS_S_COMPLETE;
73 }
74
75 void
76 gsskrb5_is_cfx(gss_ctx_id_t context_handle, int *is_cfx)
77 {
78     krb5_keyblock *key;
79     int acceptor = (context_handle->more_flags & LOCAL) == 0;
80
81     if (acceptor) {
82         if (context_handle->auth_context->local_subkey)
83             key = context_handle->auth_context->local_subkey;
84         else
85             key = context_handle->auth_context->remote_subkey;
86     } else {
87         if (context_handle->auth_context->remote_subkey)
88             key = context_handle->auth_context->remote_subkey;
89         else
90             key = context_handle->auth_context->local_subkey;
91     }
92     if (key == NULL)
93         key = context_handle->auth_context->keyblock;
94
95     if (key == NULL)
96         return;
97             
98     switch (key->keytype) {
99     case ETYPE_DES_CBC_CRC:
100     case ETYPE_DES_CBC_MD4:
101     case ETYPE_DES_CBC_MD5:
102     case ETYPE_DES3_CBC_MD5:
103     case ETYPE_DES3_CBC_SHA1:
104     case ETYPE_ARCFOUR_HMAC_MD5:
105     case ETYPE_ARCFOUR_HMAC_MD5_56:
106         break;
107     default :
108         *is_cfx = 1;
109         if ((acceptor && context_handle->auth_context->local_subkey) ||
110             (!acceptor && context_handle->auth_context->remote_subkey))
111             context_handle->more_flags |= ACCEPTOR_SUBKEY;
112         break;
113     }
114 }
115
116
117 static OM_uint32
118 gsskrb5_accept_delegated_token
119            (OM_uint32 * minor_status,
120             gss_ctx_id_t * context_handle,
121             gss_cred_id_t * delegated_cred_handle)
122 {
123     krb5_data *fwd_data = &(*context_handle)->fwd_data;
124     OM_uint32 *flags = &(*context_handle)->flags;
125     krb5_principal principal = (*context_handle)->source;
126     krb5_ccache ccache = NULL;
127     krb5_error_code kret;
128     int32_t ac_flags, ret;
129     gss_cred_id_t handle = NULL;
130       
131     if (delegated_cred_handle == NULL) {
132         /* XXX Create a new delegated_cred_handle? */
133
134         ret = 0;
135
136         kret = krb5_cc_default (gssapi_krb5_context, &ccache);
137         if (kret) {
138             *flags &= ~GSS_C_DELEG_FLAG;
139             goto end_fwd;
140         }
141     } else {
142
143         *delegated_cred_handle = NULL;
144         
145         handle = calloc(1, sizeof(*handle));
146         if (handle == NULL) {
147             ret = GSS_S_FAILURE;
148             *minor_status = ENOMEM;
149             krb5_set_error_string(gssapi_krb5_context, "out of memory");
150             gssapi_krb5_set_error_string();
151             *flags &= ~GSS_C_DELEG_FLAG;
152             goto end_fwd;
153         }
154         if ((ret = gss_duplicate_name(minor_status, principal,
155                                       &handle->principal)) != 0) {
156             *flags &= ~GSS_C_DELEG_FLAG;
157             ret = 0;
158             goto end_fwd;
159         }
160         kret = krb5_cc_gen_new (gssapi_krb5_context,
161                                 &krb5_mcc_ops,
162                                 &handle->ccache);
163         if (kret) {
164             *flags &= ~GSS_C_DELEG_FLAG;
165             ret = 0;
166             goto end_fwd;
167         }
168         ccache = handle->ccache;
169
170         ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
171         if (ret) {
172             *flags &= ~GSS_C_DELEG_FLAG;
173             goto end_fwd;
174         }
175         ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
176                                      &handle->mechanisms);
177         if (ret) {
178             *flags &= ~GSS_C_DELEG_FLAG;
179             goto end_fwd;
180         }
181     }
182
183     kret = krb5_cc_initialize(gssapi_krb5_context, ccache, principal);
184     if (kret) {
185         *flags &= ~GSS_C_DELEG_FLAG;
186         ret = 0;
187         goto end_fwd;
188     }
189       
190     krb5_auth_con_removeflags(gssapi_krb5_context,
191                               (*context_handle)->auth_context,
192                               KRB5_AUTH_CONTEXT_DO_TIME,
193                               &ac_flags);
194     kret = krb5_rd_cred2(gssapi_krb5_context,
195                          (*context_handle)->auth_context,
196                          ccache,
197                          fwd_data);
198     if (kret)
199         gssapi_krb5_set_error_string();
200     krb5_auth_con_setflags(gssapi_krb5_context,
201                            (*context_handle)->auth_context,
202                            ac_flags);
203     if (kret) {
204         *flags &= ~GSS_C_DELEG_FLAG;
205         ret = GSS_S_FAILURE;
206         *minor_status = kret;
207         goto end_fwd;
208     }
209  end_fwd:
210     /* if there was some kind of failure, clean up internal structures */
211     if ((*flags & GSS_C_DELEG_FLAG) == 0) {
212         if (handle) {
213             if (handle->principal)
214                 gss_release_name(minor_status, &handle->principal);
215             if (handle->mechanisms)
216                 gss_release_oid_set(NULL, &handle->mechanisms);
217             if (handle->ccache)
218                 krb5_cc_destroy(gssapi_krb5_context, handle->ccache);
219             free(handle);
220             handle = NULL;
221         }
222     }
223     if (delegated_cred_handle == NULL) {
224         if (ccache)
225             krb5_cc_close(gssapi_krb5_context, ccache);
226     }
227     if (handle)
228         *delegated_cred_handle = handle;
229
230     return ret;
231 }
232
233 static OM_uint32
234 gsskrb5_acceptor_ready(
235         OM_uint32 * minor_status,
236         gss_ctx_id_t * context_handle,
237         gss_cred_id_t * delegated_cred_handle)
238 {
239         OM_uint32 ret;
240         int32_t seq_number;
241         int is_cfx = 0;
242         u_int32_t *flags = &(*context_handle)->flags;
243
244         krb5_auth_getremoteseqnumber (gssapi_krb5_context,
245                                       (*context_handle)->auth_context,
246                                       &seq_number);
247
248         gsskrb5_is_cfx(*context_handle, &is_cfx);
249
250         ret = _gssapi_msg_order_create(minor_status,
251                                        &(*context_handle)->order,
252                                        _gssapi_msg_order_f(*flags),
253                                        seq_number, 0, is_cfx);
254         if (ret) return ret;
255
256         if (!(*flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(*flags)) {
257                 krb5_auth_con_setlocalseqnumber(gssapi_krb5_context,
258                                                 (*context_handle)->auth_context,
259                                                 seq_number);
260         }
261
262         /*
263          * We should handle the delegation ticket, in case it's there
264          */
265         if ((*context_handle)->fwd_data.length > 0 && (*flags & GSS_C_DELEG_FLAG)) {
266                 ret = gsskrb5_accept_delegated_token(minor_status,
267                                                      context_handle,
268                                                      delegated_cred_handle);
269                 if (ret) return ret;
270         } else {
271                 /* Well, looks like it wasn't there after all */
272                 *flags &= ~GSS_C_DELEG_FLAG;
273         }
274
275         (*context_handle)->state        = ACCEPTOR_READY;
276         (*context_handle)->more_flags   |= OPEN;
277
278         return GSS_S_COMPLETE;
279 }
280 static OM_uint32
281 gsskrb5_acceptor_start
282            (OM_uint32 * minor_status,
283             gss_ctx_id_t * context_handle,
284             const gss_cred_id_t acceptor_cred_handle,
285             const gss_buffer_t input_token_buffer,
286             const gss_channel_bindings_t input_chan_bindings,
287             gss_name_t * src_name,
288             gss_OID * mech_type,
289             gss_buffer_t output_token,
290             OM_uint32 * ret_flags,
291             OM_uint32 * time_rec,
292             gss_cred_id_t * delegated_cred_handle
293            )
294 {
295     krb5_error_code kret;
296     OM_uint32 ret = GSS_S_COMPLETE;
297     krb5_data indata;
298     krb5_flags ap_options;
299     OM_uint32 flags;
300     krb5_ticket *ticket = NULL;
301     krb5_keytab keytab = NULL;
302     krb5_keyblock *keyblock = NULL;
303     int is_cfx = 0;
304
305     krb5_data_zero (&(*context_handle)->fwd_data);
306
307     /*
308      * We may, or may not, have an escapsulation.
309      */
310     ret = gssapi_krb5_decapsulate (minor_status,
311                                    input_token_buffer,
312                                    &indata,
313                                    "\x01\x00",
314                                    GSS_KRB5_MECHANISM);
315
316     if (ret) {
317         /* No OID wrapping apparently available. */
318         indata.length   = input_token_buffer->length;
319         indata.data     = input_token_buffer->value;
320     }
321
322     /*
323      * We need to get our keytab
324      */
325     if (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) {
326         if (gssapi_krb5_keytab != NULL) {
327             keytab = gssapi_krb5_keytab;
328         }
329     } else if (acceptor_cred_handle->keytab != NULL) {
330         keytab = acceptor_cred_handle->keytab;
331     }
332     
333     /*
334      * We need to check the ticket and create the AP-REP packet
335      */
336     kret = krb5_rd_req_return_keyblock(gssapi_krb5_context,
337                                        &(*context_handle)->auth_context,
338                                        &indata,
339                                        (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred_handle->principal,
340                                        keytab,
341                                        &ap_options,
342                                        &ticket,
343                                        &keyblock);
344     if (kret) {
345         ret = GSS_S_FAILURE;
346         *minor_status = kret;
347         gssapi_krb5_set_error_string ();
348         return ret;
349     }
350     
351     /*
352      * We need to remember some data on the context_handle
353      */
354     (*context_handle)->ticket = ticket;
355     (*context_handle)->service_keyblock = keyblock;
356     (*context_handle)->lifetime = ticket->ticket.endtime;
357     
358     /*
359      * We need to copy the principal names to the context and the calling layer
360      */
361     kret = krb5_copy_principal(gssapi_krb5_context,
362                                ticket->client,
363                                &(*context_handle)->source);
364     if (kret) {
365         ret = GSS_S_FAILURE;
366         *minor_status = kret;
367         gssapi_krb5_set_error_string ();
368     }
369
370     kret = krb5_copy_principal (gssapi_krb5_context,
371                                 ticket->server,
372                                 &(*context_handle)->target);
373     if (kret) {
374         ret = GSS_S_FAILURE;
375         *minor_status = kret;
376         gssapi_krb5_set_error_string ();
377         return ret;
378     }
379     
380     /*
381      * We need to setup some compat stuff, this assumes that context_handle->target is already set
382      */
383     ret = _gss_DES3_get_mic_compat(minor_status, *context_handle);
384     if (ret) {
385         return ret;
386     }
387
388     if (src_name != NULL) {
389         kret = krb5_copy_principal (gssapi_krb5_context,
390                                     ticket->client,
391                                     src_name);
392         if (kret) {
393             ret = GSS_S_FAILURE;
394             *minor_status = kret;
395             gssapi_krb5_set_error_string ();
396             return ret;
397         }
398     }
399
400     /*
401      * We need to get the flags out of the 8003 checksum
402      */
403     {
404         krb5_authenticator authenticator;
405       
406         kret = krb5_auth_con_getauthenticator(gssapi_krb5_context,
407                                               (*context_handle)->auth_context,
408                                               &authenticator);
409         if(kret) {
410             ret = GSS_S_FAILURE;
411             *minor_status = kret;
412             gssapi_krb5_set_error_string ();
413             return ret;
414         }
415
416         ret = gssapi_krb5_verify_8003_checksum(minor_status,
417                                                input_chan_bindings,
418                                                authenticator->cksum,
419                                                &flags,
420                                                &(*context_handle)->fwd_data);
421         krb5_free_authenticator(gssapi_krb5_context, &authenticator);
422         if (ret) {
423             return ret;
424         }
425     }
426     
427     if(flags & GSS_C_MUTUAL_FLAG) {
428             krb5_data outbuf;
429             
430             gsskrb5_is_cfx(*context_handle, &is_cfx);
431             
432             if (is_cfx != 0 
433                 || (ap_options & AP_OPTS_USE_SUBKEY)) {
434                     kret = krb5_auth_con_addflags(gssapi_krb5_context,
435                                                   (*context_handle)->auth_context,
436                                                   KRB5_AUTH_CONTEXT_USE_SUBKEY,
437                                                   NULL);
438                     (*context_handle)->more_flags |= ACCEPTOR_SUBKEY;
439             }
440             
441             kret = krb5_mk_rep(gssapi_krb5_context,
442                                (*context_handle)->auth_context,
443                                &outbuf);
444             if (kret) {
445                     *minor_status = kret;
446                     gssapi_krb5_set_error_string ();
447                     return GSS_S_FAILURE;
448             }
449             
450             if (!(flags & GSS_C_DCE_STYLE)) {
451                     ret = gssapi_krb5_encapsulate(minor_status,
452                                                   &outbuf,
453                                                   output_token,
454                                                   "\x02\x00",
455                                                   GSS_KRB5_MECHANISM);
456                     krb5_data_free (&outbuf);
457                     if (ret) {
458                             return ret;
459                     }
460             } else {
461                     output_token->length        = outbuf.length;
462                     output_token->value = outbuf.data;
463             }
464     }
465     
466     flags |= GSS_C_TRANS_FLAG;
467
468     /* Remember the flags */
469     
470     (*context_handle)->lifetime = ticket->ticket.endtime;
471     (*context_handle)->flags = flags;
472     (*context_handle)->more_flags |= OPEN;
473     
474     if (mech_type)
475         *mech_type = GSS_KRB5_MECHANISM;
476     
477     if (time_rec) {
478         ret = gssapi_lifetime_left(minor_status,
479                                    (*context_handle)->lifetime,
480                                    time_rec);
481         if (ret) {
482             return ret;
483         }
484     }
485
486     /*
487      * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from the client
488      */
489     if (flags & GSS_C_DCE_STYLE) {
490             if (ret_flags) {
491                     /* Return flags to caller, but we haven't processed delgations yet */
492                     *ret_flags = flags & ~GSS_C_DELEG_FLAG;
493             }
494     
495             (*context_handle)->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
496             return GSS_S_CONTINUE_NEEDED;
497     }
498
499     ret = gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
500
501     /*
502      * We need to send the flags back to the caller
503      */
504     
505     *ret_flags = (*context_handle)->flags;
506     return ret;
507 }
508
509 static OM_uint32
510 gsskrb5_acceptor_wait_for_dcestyle(
511         OM_uint32 * minor_status,
512         gss_ctx_id_t * context_handle,
513         const gss_cred_id_t acceptor_cred_handle,
514         const gss_buffer_t input_token_buffer,
515         const gss_channel_bindings_t input_chan_bindings,
516         gss_name_t * src_name,
517         gss_OID * mech_type,
518         gss_buffer_t output_token,
519         OM_uint32 * ret_flags,
520         OM_uint32 * time_rec,
521         gss_cred_id_t * delegated_cred_handle)
522 {
523         OM_uint32 ret;
524         krb5_error_code kret;
525         krb5_data inbuf;
526         OM_uint32 r_seq_number;
527         OM_uint32 l_seq_number;
528         
529         /* We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP */
530         inbuf.length    = input_token_buffer->length;
531         inbuf.data      = input_token_buffer->value;
532
533         /* 
534          * We need to remeber the old remote seq_number, then check if the client has replied with our local seq_number,
535          * and then reset the remote seq_number to the old value 
536          */
537         {
538                 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
539                                                     (*context_handle)->auth_context,
540                                                     &l_seq_number);
541                 if (kret) {
542                         gssapi_krb5_set_error_string ();
543                         *minor_status = kret;
544                         return GSS_S_FAILURE;
545                 }
546
547                 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
548                                                     (*context_handle)->auth_context,
549                                                     &r_seq_number);
550                 if (kret) {
551                         gssapi_krb5_set_error_string ();
552                         *minor_status = kret;
553                         return GSS_S_FAILURE;
554                 }
555
556                 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
557                                                     (*context_handle)->auth_context,
558                                                     l_seq_number);
559                 if (kret) {
560                         gssapi_krb5_set_error_string ();
561                         *minor_status = kret;
562                         return GSS_S_FAILURE;
563                 }
564         }
565
566         /* We need to verify the AP_REP, but we need to flag that this
567            is DCE_STYLE, so don't check the timestamps this time 
568         */ 
569         {
570                 krb5_ap_rep_enc_part *repl;
571                 int32_t auth_flags;
572                 
573                 kret = krb5_auth_con_removeflags(gssapi_krb5_context,
574                                                  (*context_handle)->auth_context,
575                                                  KRB5_AUTH_CONTEXT_DO_TIME, &auth_flags);
576                 if (kret) { /* Can't happen */
577                         gssapi_krb5_set_error_string ();
578                         *minor_status = kret;
579                         return GSS_S_FAILURE;
580                 }
581
582                 kret = krb5_rd_rep(gssapi_krb5_context,
583                                    (*context_handle)->auth_context,
584                                    &inbuf,
585                                    &repl);
586                 if (kret) {
587                         gssapi_krb5_set_error_string ();
588                         *minor_status = kret;
589                         return GSS_S_FAILURE;
590                 }
591                 
592                 /* Because the inbuf above is a final leg from client
593                  * to server, we don't have a use for a 'reply'
594                  * here */
595                 krb5_free_ap_rep_enc_part(gssapi_krb5_context, repl);
596
597                 /* Do no harm, put the flags back */
598                 kret = krb5_auth_con_setflags(gssapi_krb5_context,
599                                               (*context_handle)->auth_context,
600                                               auth_flags);
601                 if (kret) { /* Can't happen */
602                         gssapi_krb5_set_error_string ();
603                         *minor_status = kret;
604                         return GSS_S_FAILURE;
605                 }
606         }
607
608         /* We need to check the liftime */
609         {
610                 OM_uint32 lifetime_rec;
611
612                 ret = gssapi_lifetime_left(minor_status,
613                                            (*context_handle)->lifetime,
614                                            &lifetime_rec);
615                 if (ret) {
616                         return ret;
617                 }
618                 if (lifetime_rec == 0) {
619                         return GSS_S_CONTEXT_EXPIRED;
620                 }
621         
622                 if (time_rec) *time_rec = lifetime_rec;
623         }
624
625         /* We need to give the caller the flags which are in use */
626         if (ret_flags) *ret_flags = (*context_handle)->flags;
627
628         if (src_name) {
629                 kret = krb5_copy_principal(gssapi_krb5_context,
630                                            (*context_handle)->source,
631                                            src_name);
632                 if (kret) {
633                         *minor_status = kret;
634                         gssapi_krb5_set_error_string ();
635                         return GSS_S_FAILURE;
636                 }
637         }
638
639         /*
640          * After the krb5_rd_rep() the remote and local seq_number should be the same,
641          * because the client just replies the seq_number from our AP-REP in its AP-REP,
642          * but then the client uses the seq_number from its AP-REQ for GSS_wrap()
643          */
644         {
645                 OM_uint32 tmp_r_seq_number;
646                 OM_uint32 tmp_l_seq_number;
647
648                 kret = krb5_auth_getremoteseqnumber(gssapi_krb5_context,
649                                                     (*context_handle)->auth_context,
650                                                     &tmp_r_seq_number);
651                 if (kret) {
652                         gssapi_krb5_set_error_string ();
653                         *minor_status = kret;
654                         return GSS_S_FAILURE;
655                 }
656
657                 kret = krb5_auth_con_getlocalseqnumber(gssapi_krb5_context,
658                                                     (*context_handle)->auth_context,
659                                                     &tmp_l_seq_number);
660                 if (kret) {
661                         gssapi_krb5_set_error_string ();
662                         *minor_status = kret;
663                         return GSS_S_FAILURE;
664                 }
665
666                 /*
667                  * Here we check if the client has responsed with our local seq_number,
668                  */
669                 if (tmp_r_seq_number != tmp_l_seq_number) {
670                         return GSS_S_UNSEQ_TOKEN;
671                 }
672         }
673
674         /*
675          * We need to reset the remote seq_number, because the client will use,
676          * the old one for the GSS_wrap() calls
677          */
678         {
679                 kret = krb5_auth_con_setremoteseqnumber(gssapi_krb5_context,
680                                                        (*context_handle)->auth_context,
681                                                        r_seq_number);   
682                 if (kret) {
683                         gssapi_krb5_set_error_string ();
684                         *minor_status = kret;
685                         return GSS_S_FAILURE;
686                 }
687         }
688
689         return gsskrb5_acceptor_ready(minor_status, context_handle, delegated_cred_handle);
690 }
691
692 static OM_uint32
693 gsskrb5_accept_sec_context
694            (OM_uint32 * minor_status,
695             gss_ctx_id_t * context_handle,
696             const gss_cred_id_t acceptor_cred_handle,
697             const gss_buffer_t input_token_buffer,
698             const gss_channel_bindings_t input_chan_bindings,
699             gss_name_t * src_name,
700             gss_OID * mech_type,
701             gss_buffer_t output_token,
702             OM_uint32 * ret_flags,
703             OM_uint32 * time_rec,
704             gss_cred_id_t * delegated_cred_handle
705            )
706 {
707     OM_uint32 ret = GSS_S_COMPLETE;
708     krb5_data fwd_data;
709     gss_ctx_id_t local_context;
710
711     GSSAPI_KRB5_INIT();
712
713     krb5_data_zero (&fwd_data);
714     output_token->length = 0;
715     output_token->value = NULL;
716
717     if (src_name != NULL)
718         *src_name = NULL;
719     if (mech_type)
720         *mech_type = GSS_KRB5_MECHANISM;
721
722     if (*context_handle == GSS_C_NO_CONTEXT) {
723         ret = _gsskrb5_create_ctx(minor_status,
724                                   &local_context,
725                                   input_chan_bindings,
726                                   ACCEPTOR_START);
727         if (ret) return ret;
728     } else {
729         local_context = *context_handle;
730     }
731     
732     /*
733      * TODO: check the channel_bindings 
734      * (above just sets them to krb5 layer)
735      */
736
737     HEIMDAL_MUTEX_lock(&(local_context)->ctx_id_mutex);
738     
739     switch ((local_context)->state) {
740     case ACCEPTOR_START:
741         ret = gsskrb5_acceptor_start(minor_status,
742                                      &local_context,
743                                      acceptor_cred_handle,
744                                      input_token_buffer,
745                                      input_chan_bindings,
746                                      src_name,
747                                      mech_type,
748                                      output_token,
749                                      ret_flags,
750                                      time_rec,
751                                      delegated_cred_handle);
752         break;
753     case ACCEPTOR_WAIT_FOR_DCESTYLE:
754         ret = gsskrb5_acceptor_wait_for_dcestyle(minor_status,
755                                                  &local_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_READY:
767         /* this function should not be called after it has returned GSS_S_COMPLETE */
768         ret =  GSS_S_BAD_STATUS;
769         break;
770     default:
771         /* TODO: is this correct here? --metze */
772         ret =  GSS_S_BAD_STATUS;
773         break;
774     }
775     
776     HEIMDAL_MUTEX_unlock(&(local_context)->ctx_id_mutex);
777     
778     if (*context_handle == GSS_C_NO_CONTEXT) {
779         if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
780             *context_handle = local_context;
781         } else {
782             gss_delete_sec_context(minor_status, 
783                                    &local_context, 
784                                    NULL);
785         }
786     }
787
788     return ret;
789 }
790
791 static OM_uint32
792 code_NegTokenArg(OM_uint32 *minor_status,
793                  const NegTokenTarg *targ,
794                  krb5_data *data,
795                  u_char **ret_buf)
796 {
797     OM_uint32 ret;
798     u_char *buf;
799     size_t buf_size, buf_len;
800
801     buf_size = 1024;
802     buf = malloc(buf_size);
803     if (buf == NULL) {
804         *minor_status = ENOMEM;
805         return GSS_S_FAILURE;
806     }
807
808     do {
809         ret = encode_NegTokenTarg(buf + buf_size - 1,
810                                   buf_size,
811                                   targ, &buf_len);
812         if (ret == 0) {
813             size_t tmp;
814
815             ret = der_put_length_and_tag(buf + buf_size - buf_len - 1,
816                                          buf_size - buf_len,
817                                          buf_len,
818                                          ASN1_C_CONTEXT,
819                                          CONS,
820                                          1,
821                                          &tmp);
822             if (ret == 0)
823                 buf_len += tmp;
824         }
825         if (ret) {
826             if (ret == ASN1_OVERFLOW) {
827                 u_char *tmp;
828
829                 buf_size *= 2;
830                 tmp = realloc (buf, buf_size);
831                 if (tmp == NULL) {
832                     *minor_status = ENOMEM;
833                     free(buf);
834                     return GSS_S_FAILURE;
835                 }
836                 buf = tmp;
837             } else {
838                 *minor_status = ret;
839                 free(buf);
840                 return GSS_S_FAILURE;
841             }
842         }
843     } while (ret == ASN1_OVERFLOW);
844
845     data->data   = buf + buf_size - buf_len;
846     data->length = buf_len;
847     *ret_buf     = buf;
848     return GSS_S_COMPLETE;
849 }
850
851 static OM_uint32
852 send_reject (OM_uint32 *minor_status,
853              gss_buffer_t output_token)
854 {
855     NegTokenTarg targ;
856     krb5_data data;
857     u_char *buf;
858     OM_uint32 ret;
859
860     ALLOC(targ.negResult, 1);
861     if (targ.negResult == NULL) {
862         *minor_status = ENOMEM;
863         return GSS_S_FAILURE;
864     }
865     *(targ.negResult) = reject;
866     targ.supportedMech = NULL;
867     targ.responseToken = NULL;
868     targ.mechListMIC   = NULL;
869     
870     ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
871     free_NegTokenTarg(&targ);
872     if (ret)
873         return ret;
874
875 #if 0
876     ret = _gssapi_encapsulate(minor_status,
877                               &data,
878                               output_token,
879                               GSS_SPNEGO_MECHANISM);
880 #else
881     output_token->value = malloc(data.length);
882     if (output_token->value == NULL) {
883         *minor_status = ENOMEM;
884         ret = GSS_S_FAILURE;
885     } else {
886         output_token->length = data.length;
887         memcpy(output_token->value, data.data, output_token->length);
888     }
889 #endif
890     free(buf);
891     if (ret)
892         return ret;
893     return GSS_S_BAD_MECH;
894 }
895
896 static OM_uint32
897 send_accept (OM_uint32 *minor_status,
898              OM_uint32 major_status,
899              gss_buffer_t output_token,
900              gss_buffer_t mech_token,
901              gss_ctx_id_t context_handle,
902              const MechTypeList *mechtypelist)
903 {
904     NegTokenTarg targ;
905     krb5_data data;
906     u_char *buf;
907     OM_uint32 ret;
908     gss_buffer_desc mech_buf, mech_mic_buf;
909     krb5_boolean require_mic;
910
911     memset(&targ, 0, sizeof(targ));
912     ALLOC(targ.negResult, 1);
913     if (targ.negResult == NULL) {
914         *minor_status = ENOMEM;
915         return GSS_S_FAILURE;
916     }
917     *(targ.negResult) = accept_completed;
918
919     ALLOC(targ.supportedMech, 1);
920     if (targ.supportedMech == NULL) {
921         free_NegTokenTarg(&targ);
922         *minor_status = ENOMEM;
923         return GSS_S_FAILURE;
924     }
925
926     ret = der_get_oid(GSS_KRB5_MECHANISM->elements,
927                       GSS_KRB5_MECHANISM->length,
928                       targ.supportedMech,
929                       NULL);
930     if (ret) {
931         free_NegTokenTarg(&targ);
932         *minor_status = ENOMEM;
933         return GSS_S_FAILURE;
934     }
935
936     if (mech_token != NULL && mech_token->length != 0) {
937         ALLOC(targ.responseToken, 1);
938         if (targ.responseToken == NULL) {
939             free_NegTokenTarg(&targ);
940             *minor_status = ENOMEM;
941             return GSS_S_FAILURE;
942         }
943         targ.responseToken->length = mech_token->length;
944         targ.responseToken->data   = mech_token->value;
945         mech_token->length = 0;
946         mech_token->value  = NULL;
947     } else {
948         targ.responseToken = NULL;
949     }
950
951     ret = _gss_spnego_require_mechlist_mic(minor_status, context_handle,
952                                            &require_mic);
953     if (ret) {
954         free_NegTokenTarg(&targ);
955         return ret;
956     }
957
958     if (major_status == GSS_S_COMPLETE && require_mic) {
959         size_t buf_len;
960
961         ALLOC(targ.mechListMIC, 1);
962         if (targ.mechListMIC == NULL) {
963             free_NegTokenTarg(&targ);
964             *minor_status = ENOMEM;
965             return GSS_S_FAILURE;
966         }
967         
968         ASN1_MALLOC_ENCODE(MechTypeList, mech_buf.value, mech_buf.length,
969                            mechtypelist, &buf_len, ret);
970         if (ret) {
971             free_NegTokenTarg(&targ);
972             return ret;
973         }
974         if (mech_buf.length != buf_len)
975             abort();
976
977         ret = gss_get_mic(minor_status, context_handle, 0, &mech_buf,
978                           &mech_mic_buf);
979         free (mech_buf.value);
980         if (ret) {
981             free_NegTokenTarg(&targ);
982             return ret;
983         }
984
985         targ.mechListMIC->length = mech_mic_buf.length;
986         targ.mechListMIC->data   = mech_mic_buf.value;
987     } else
988         targ.mechListMIC = NULL;
989
990     ret = code_NegTokenArg (minor_status, &targ, &data, &buf);
991     free_NegTokenTarg(&targ);
992     if (ret)
993         return ret;
994
995 #if 0
996     ret = _gssapi_encapsulate(minor_status,
997                               &data,
998                               output_token,
999                               GSS_SPNEGO_MECHANISM);
1000 #else
1001     output_token->value = malloc(data.length);
1002     if (output_token->value == NULL) {
1003         *minor_status = ENOMEM;
1004         ret = GSS_S_FAILURE;
1005     } else {
1006         output_token->length = data.length;
1007         memcpy(output_token->value, data.data, output_token->length);
1008     }
1009 #endif
1010     free(buf);
1011     if (ret)
1012         return ret;
1013     return GSS_S_COMPLETE;
1014 }
1015
1016 static OM_uint32
1017 spnego_accept_sec_context
1018            (OM_uint32 * minor_status,
1019             gss_ctx_id_t * context_handle,
1020             const gss_cred_id_t acceptor_cred_handle,
1021             const gss_buffer_t input_token_buffer,
1022             const gss_channel_bindings_t input_chan_bindings,
1023             gss_name_t * src_name,
1024             gss_OID * mech_type,
1025             gss_buffer_t output_token,
1026             OM_uint32 * ret_flags,
1027             OM_uint32 * time_rec,
1028             gss_cred_id_t * delegated_cred_handle
1029            )
1030 {
1031     OM_uint32 ret, ret2;
1032     NegTokenInit ni;
1033     size_t ni_len;
1034     int i;
1035     int found = 0;
1036     krb5_data data;
1037     size_t len, taglen;
1038
1039     output_token->length = 0;
1040     output_token->value  = NULL;
1041
1042     ret = _gssapi_decapsulate (minor_status,
1043                                input_token_buffer,
1044                                &data,
1045                                GSS_SPNEGO_MECHANISM);
1046     if (ret)
1047         return ret;
1048
1049     ret = der_match_tag_and_length(data.data, data.length,
1050                                    ASN1_C_CONTEXT, CONS, 0, &len, &taglen);
1051     if (ret)
1052         return ret;
1053
1054     if(len > data.length - taglen)
1055         return ASN1_OVERRUN;
1056
1057     ret = decode_NegTokenInit((const char *)data.data + taglen, len,
1058                               &ni, &ni_len);
1059     if (ret)
1060         return GSS_S_DEFECTIVE_TOKEN;
1061
1062     if (ni.mechTypes == NULL) {
1063         free_NegTokenInit(&ni);
1064         return send_reject (minor_status, output_token);
1065     }
1066
1067     for (i = 0; !found && i < ni.mechTypes->len; ++i) {
1068         char mechbuf[17];
1069         size_t mech_len;
1070
1071         ret = der_put_oid (mechbuf + sizeof(mechbuf) - 1,
1072                            sizeof(mechbuf),
1073                            &ni.mechTypes->val[i],
1074                            &mech_len);
1075         if (ret) {
1076             free_NegTokenInit(&ni);
1077             return GSS_S_DEFECTIVE_TOKEN;
1078         }
1079         if (mech_len == GSS_KRB5_MECHANISM->length
1080             && memcmp(GSS_KRB5_MECHANISM->elements,
1081                       mechbuf + sizeof(mechbuf) - mech_len,
1082                       mech_len) == 0)
1083             found = 1;
1084     }
1085     if (found) {
1086         gss_buffer_desc ibuf, obuf;
1087         gss_buffer_t ot = NULL;
1088         OM_uint32 minor;
1089
1090         if (ni.mechToken != NULL) {
1091             ibuf.length = ni.mechToken->length;
1092             ibuf.value  = ni.mechToken->data;
1093
1094             ret = gsskrb5_accept_sec_context(&minor,
1095                                              context_handle,
1096                                              acceptor_cred_handle,
1097                                              &ibuf,
1098                                              input_chan_bindings,
1099                                              src_name,
1100                                              mech_type,
1101                                              &obuf,
1102                                              ret_flags,
1103                                              time_rec,
1104                                              delegated_cred_handle);
1105             if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
1106                 ot = &obuf;
1107             } else {
1108                 free_NegTokenInit(&ni);
1109                 send_reject (minor_status, output_token);
1110                 return ret;
1111             }
1112         }
1113         ret2 = send_accept (minor_status, ret, output_token, ot,
1114                            *context_handle, ni.mechTypes);
1115         if (ret2 != GSS_S_COMPLETE)
1116             ret = ret2;
1117         if (ot != NULL)
1118             gss_release_buffer(&minor, ot);
1119         free_NegTokenInit(&ni);
1120         return ret;
1121     } else {
1122         free_NegTokenInit(&ni);
1123         return send_reject (minor_status, output_token);
1124     }
1125 }
1126
1127 OM_uint32
1128 gss_accept_sec_context
1129            (OM_uint32 * minor_status,
1130             gss_ctx_id_t * context_handle,
1131             const gss_cred_id_t acceptor_cred_handle,
1132             const gss_buffer_t input_token_buffer,
1133             const gss_channel_bindings_t input_chan_bindings,
1134             gss_name_t * src_name,
1135             gss_OID * mech_type,
1136             gss_buffer_t output_token,
1137             OM_uint32 * ret_flags,
1138             OM_uint32 * time_rec,
1139             gss_cred_id_t * delegated_cred_handle
1140            )
1141 {
1142     OM_uint32 ret;
1143     ssize_t mech_len;
1144     const u_char *p;
1145
1146     *minor_status = 0;
1147
1148     mech_len = gssapi_krb5_get_mech (input_token_buffer->value,
1149                                      input_token_buffer->length,
1150                                      &p);
1151
1152     /* This could be 'dce style' kerberos, where the OID is missing :-( */
1153     if ((mech_len < 0) || ((mech_len == GSS_KRB5_MECHANISM->length)
1154                            && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_len) == 0))
1155         ret = gsskrb5_accept_sec_context(minor_status,
1156                                          context_handle,
1157                                          acceptor_cred_handle,
1158                                          input_token_buffer,
1159                                          input_chan_bindings,
1160                                          src_name,
1161                                          mech_type,
1162                                          output_token,
1163                                          ret_flags,
1164                                          time_rec,
1165                                          delegated_cred_handle);
1166     else if (mech_len == GSS_SPNEGO_MECHANISM->length
1167              && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_len) == 0)
1168         ret = spnego_accept_sec_context(minor_status,
1169                                         context_handle,
1170                                         acceptor_cred_handle,
1171                                         input_token_buffer,
1172                                         input_chan_bindings,
1173                                         src_name,
1174                                         mech_type,
1175                                         output_token,
1176                                         ret_flags,
1177                                         time_rec,
1178                                         delegated_cred_handle);
1179     else
1180         return GSS_S_BAD_MECH;
1181
1182     return ret;
1183 }