40dfa8bd26604436899f79007cb08b94256d2fdb
[krb5.git] / src / lib / gssapi / krb5 / accept_sec_context.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 2000, 2004, 2007, 2008  by the Massachusetts Institute of Technology.
4  * All Rights Reserved.
5  *
6  * Export of this software from the United States of America may
7  *   require a specific license from the United States Government.
8  *   It is the responsibility of any person or organization contemplating
9  *   export to obtain such a license before exporting.
10  *
11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12  * distribute this software and its documentation for any purpose and
13  * without fee is hereby granted, provided that the above copyright
14  * notice appear in all copies and that both that copyright notice and
15  * this permission notice appear in supporting documentation, and that
16  * the name of M.I.T. not be used in advertising or publicity pertaining
17  * to distribution of the software without specific, written prior
18  * permission.  Furthermore if you modify this software you must label
19  * your software as modified software and not distribute it in such a
20  * fashion that it might be confused with the original M.I.T. software.
21  * M.I.T. makes no representations about the suitability of
22  * this software for any purpose.  It is provided "as is" without express
23  * or implied warranty.
24  */
25 /*
26  * Copyright 1993 by OpenVision Technologies, Inc.
27  *
28  * Permission to use, copy, modify, distribute, and sell this software
29  * and its documentation for any purpose is hereby granted without fee,
30  * provided that the above copyright notice appears in all copies and
31  * that both that copyright notice and this permission notice appear in
32  * supporting documentation, and that the name of OpenVision not be used
33  * in advertising or publicity pertaining to distribution of the software
34  * without specific, written prior permission. OpenVision makes no
35  * representations about the suitability of this software for any
36  * purpose.  It is provided "as is" without express or implied warranty.
37  *
38  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
39  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
40  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
41  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
42  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
43  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
44  * PERFORMANCE OF THIS SOFTWARE.
45  */
46
47 /*
48  * Copyright (C) 1998 by the FundsXpress, INC.
49  *
50  * All rights reserved.
51  *
52  * Export of this software from the United States of America may require
53  * a specific license from the United States Government.  It is the
54  * responsibility of any person or organization contemplating export to
55  * obtain such a license before exporting.
56  *
57  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
58  * distribute this software and its documentation for any purpose and
59  * without fee is hereby granted, provided that the above copyright
60  * notice appear in all copies and that both that copyright notice and
61  * this permission notice appear in supporting documentation, and that
62  * the name of FundsXpress. not be used in advertising or publicity pertaining
63  * to distribution of the software without specific, written prior
64  * permission.  FundsXpress makes no representations about the suitability of
65  * this software for any purpose.  It is provided "as is" without express
66  * or implied warranty.
67  *
68  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
69  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
70  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
71  */
72 /*
73  * Copyright (c) 2006-2008, Novell, Inc.
74  * All rights reserved.
75  *
76  * Redistribution and use in source and binary forms, with or without
77  * modification, are permitted provided that the following conditions are met:
78  *
79  *   * Redistributions of source code must retain the above copyright notice,
80  *       this list of conditions and the following disclaimer.
81  *   * Redistributions in binary form must reproduce the above copyright
82  *       notice, this list of conditions and the following disclaimer in the
83  *       documentation and/or other materials provided with the distribution.
84  *   * The copyright holder's name is not used to endorse or promote products
85  *       derived from this software without specific prior written permission.
86  *
87  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
88  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
91  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
92  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
93  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
94  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
95  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
96  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
97  * POSSIBILITY OF SUCH DAMAGE.
98  */
99
100 #include "k5-int.h"
101 #include "gssapiP_krb5.h"
102 #ifdef HAVE_MEMORY_H
103 #include <memory.h>
104 #endif
105 #include <assert.h>
106
107 #ifdef CFX_EXERCISE
108 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
109 #else
110 #define CFX_ACCEPTOR_SUBKEY 1
111 #endif
112
113 #ifndef LEAN_CLIENT
114
115 static OM_uint32
116 create_constrained_deleg_creds(OM_uint32 *minor_status,
117                                krb5_gss_cred_id_t verifier_cred_handle,
118                                krb5_ticket *ticket,
119                                krb5_gss_cred_id_t *out_cred,
120                                krb5_context context)
121 {
122     OM_uint32 major_status;
123     krb5_creds krb_creds;
124     krb5_data *data;
125     krb5_error_code code;
126
127     assert(out_cred != NULL);
128     assert(verifier_cred_handle->usage == GSS_C_BOTH);
129
130     memset(&krb_creds, 0, sizeof(krb_creds));
131     krb_creds.client = ticket->enc_part2->client;
132     krb_creds.server = ticket->server;
133     krb_creds.keyblock = *(ticket->enc_part2->session);
134     krb_creds.ticket_flags = ticket->enc_part2->flags;
135     krb_creds.times = ticket->enc_part2->times;
136     krb_creds.magic = KV5M_CREDS;
137     krb_creds.authdata = NULL;
138
139     code = encode_krb5_ticket(ticket, &data);
140     if (code) {
141         *minor_status = code;
142         return GSS_S_FAILURE;
143     }
144
145     krb_creds.ticket = *data;
146
147     major_status = kg_compose_deleg_cred(minor_status,
148                                          verifier_cred_handle,
149                                          &krb_creds,
150                                          GSS_C_INDEFINITE,
151                                          out_cred,
152                                          NULL,
153                                          context);
154
155     krb5_free_data(context, data);
156
157     return major_status;
158 }
159
160 /* Decode, decrypt and store the forwarded creds in the local ccache. */
161 static krb5_error_code
162 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
163     krb5_context context;
164     krb5_auth_context auth_context;
165     krb5_data *inbuf;
166     krb5_gss_cred_id_t *out_cred;
167 {
168     krb5_creds ** creds = NULL;
169     krb5_error_code retval;
170     krb5_ccache ccache = NULL;
171     krb5_gss_cred_id_t cred = NULL;
172     krb5_auth_context new_auth_ctx = NULL;
173     krb5_int32 flags_org;
174
175     if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
176         return retval;
177     krb5_auth_con_setflags(context, auth_context,
178                            0);
179
180     /*
181      * By the time krb5_rd_cred is called here (after krb5_rd_req has been
182      * called in krb5_gss_accept_sec_context), the "keyblock" field of
183      * auth_context contains a pointer to the session key, and the
184      * "recv_subkey" field might contain a session subkey.  Either of
185      * these (the "recv_subkey" if it isn't NULL, otherwise the
186      * "keyblock") might have been used to encrypt the encrypted part of
187      * the KRB_CRED message that contains the forwarded credentials.  (The
188      * Java Crypto and Security Implementation from the DSTC in Australia
189      * always uses the session key.  But apparently it never negotiates a
190      * subkey, so this code works fine against a JCSI client.)  Up to the
191      * present, though, GSSAPI clients linked against the MIT code (which
192      * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
193      * all -- at this level.  So if the first call to krb5_rd_cred fails,
194      * we should call it a second time with another auth context freshly
195      * created by krb5_auth_con_init.  All of its keyblock fields will be
196      * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
197      * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
198      * message in the clear -- the "authenticator" whose "checksum" ends up
199      * containing the KRB_CRED message does get encrypted.)
200      */
201     if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
202         if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
203             goto cleanup;
204         krb5_auth_con_setflags(context, new_auth_ctx, 0);
205         if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
206                                    &creds, NULL)))
207             goto cleanup;
208     }
209
210     if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
211         ccache = NULL;
212         goto cleanup;
213     }
214
215     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
216         goto cleanup;
217
218     if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
219         goto cleanup;
220
221     /* generate a delegated credential handle */
222     if (out_cred) {
223         /* allocate memory for a cred_t... */
224         if (!(cred =
225               (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
226             retval = ENOMEM; /* out of memory? */
227             goto cleanup;
228         }
229
230         /* zero it out... */
231         memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
232
233         retval = k5_mutex_init(&cred->lock);
234         if (retval) {
235             xfree(cred);
236             cred = NULL;
237             goto cleanup;
238         }
239
240         /* copy the client principle into it... */
241         if ((retval =
242              kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
243                           &cred->name))) {
244             k5_mutex_destroy(&cred->lock);
245             retval = ENOMEM; /* out of memory? */
246             xfree(cred); /* clean up memory on failure */
247             cred = NULL;
248             goto cleanup;
249         }
250
251         cred->usage = GSS_C_INITIATE; /* we can't accept with this */
252         /* cred->name already set */
253         cred->keytab = NULL; /* no keytab associated with this... */
254         cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
255         cred->ccache = ccache; /* the ccache containing the credential */
256         cred->destroy_ccache = 1;
257         ccache = NULL; /* cred takes ownership so don't destroy */
258     }
259
260     /* If there were errors, there might have been a memory leak
261        if (!cred)
262        if ((retval = krb5_cc_close(context, ccache)))
263        goto cleanup;
264     */
265 cleanup:
266     if (creds)
267         krb5_free_tgt_creds(context, creds);
268
269     if (ccache)
270         (void)krb5_cc_destroy(context, ccache);
271
272     if (out_cred)
273         *out_cred = cred; /* return credential */
274
275     if (new_auth_ctx)
276         krb5_auth_con_free(context, new_auth_ctx);
277
278     krb5_auth_con_setflags(context, auth_context, flags_org);
279
280     return retval;
281 }
282
283
284 /*
285  * Performs third leg of DCE authentication
286  */
287 static OM_uint32
288 kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
289               input_token, input_chan_bindings, src_name, mech_type,
290               output_token, ret_flags, time_rec, delegated_cred_handle)
291     OM_uint32 *minor_status;
292     gss_ctx_id_t *context_handle;
293     gss_cred_id_t verifier_cred_handle;
294     gss_buffer_t input_token;
295     gss_channel_bindings_t input_chan_bindings;
296     gss_name_t *src_name;
297     gss_OID *mech_type;
298     gss_buffer_t output_token;
299     OM_uint32 *ret_flags;
300     OM_uint32 *time_rec;
301     gss_cred_id_t *delegated_cred_handle;
302 {
303     krb5_error_code code;
304     krb5_gss_ctx_id_rec *ctx = 0;
305     krb5_timestamp now;
306     krb5_gss_name_t name = NULL;
307     krb5_ui_4 nonce = 0;
308     krb5_data ap_rep;
309     OM_uint32 major_status = GSS_S_FAILURE;
310
311     output_token->length = 0;
312     output_token->value = NULL;
313
314     if (mech_type)
315         *mech_type = GSS_C_NULL_OID;
316     /* return a bogus cred handle */
317     if (delegated_cred_handle)
318         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
319
320     ctx = (krb5_gss_ctx_id_rec *)*context_handle;
321
322     code = krb5_timeofday(ctx->k5_context, &now);
323     if (code != 0) {
324         major_status = GSS_S_FAILURE;
325         goto fail;
326     }
327
328     if (ctx->krb_times.endtime < now) {
329         code = 0;
330         major_status = GSS_S_CREDENTIALS_EXPIRED;
331         goto fail;
332     }
333
334     ap_rep.data = input_token->value;
335     ap_rep.length = input_token->length;
336
337     code = krb5_rd_rep_dce(ctx->k5_context,
338                            ctx->auth_context,
339                            &ap_rep,
340                            &nonce);
341     if (code != 0) {
342         major_status = GSS_S_FAILURE;
343         goto fail;
344     }
345
346     ctx->established = 1;
347
348     if (src_name) {
349         code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
350         if (code) {
351             major_status = GSS_S_FAILURE;
352             goto fail;
353         }
354         *src_name = (gss_name_t) name;
355     }
356
357     if (mech_type)
358         *mech_type = ctx->mech_used;
359
360     if (time_rec)
361         *time_rec = ctx->krb_times.endtime - now;
362
363     if (ret_flags)
364         *ret_flags = ctx->gss_flags;
365
366     /* XXX no support for delegated credentials yet */
367
368     *minor_status = 0;
369
370     return GSS_S_COMPLETE;
371
372 fail:
373     /* real failure code follows */
374
375     (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
376                                        NULL);
377     *context_handle = GSS_C_NO_CONTEXT;
378     *minor_status = code;
379
380     return major_status;
381 }
382
383 static krb5_error_code
384 kg_process_extension(krb5_context context,
385                      krb5_auth_context auth_context,
386                      int ext_type,
387                      krb5_data *ext_data,
388                      krb5_gss_ctx_ext_t exts)
389 {
390     krb5_error_code code = 0;
391
392     assert(exts != NULL);
393
394     switch (ext_type) {
395     case KRB5_GSS_EXTS_IAKERB_FINISHED:
396         if (exts->iakerb.conv == NULL) {
397             code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
398         } else {
399             krb5_key key;
400
401             code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
402             if (code != 0)
403                 break;
404
405             code = iakerb_verify_finished(context, key, exts->iakerb.conv,
406                                           ext_data);
407             if (code == 0)
408                 exts->iakerb.verified = 1;
409
410             krb5_k_free_key(context, key);
411         }
412         break;
413     default:
414         break;
415     }
416
417     return code;
418 }
419
420 static OM_uint32
421 kg_accept_krb5(minor_status, context_handle,
422                verifier_cred_handle, input_token,
423                input_chan_bindings, src_name, mech_type,
424                output_token, ret_flags, time_rec,
425                delegated_cred_handle, exts)
426     OM_uint32 *minor_status;
427     gss_ctx_id_t *context_handle;
428     gss_cred_id_t verifier_cred_handle;
429     gss_buffer_t input_token;
430     gss_channel_bindings_t input_chan_bindings;
431     gss_name_t *src_name;
432     gss_OID *mech_type;
433     gss_buffer_t output_token;
434     OM_uint32 *ret_flags;
435     OM_uint32 *time_rec;
436     gss_cred_id_t *delegated_cred_handle;
437     krb5_gss_ctx_ext_t exts;
438 {
439     krb5_context context;
440     unsigned char *ptr, *ptr2;
441     char *sptr;
442     OM_uint32 tmp;
443     size_t md5len;
444     int bigend;
445     krb5_gss_cred_id_t cred = 0;
446     krb5_data ap_rep, ap_req;
447     unsigned int i;
448     krb5_error_code code;
449     krb5_address addr, *paddr;
450     krb5_authenticator *authdat = 0;
451     krb5_checksum reqcksum;
452     krb5_gss_name_t name = NULL;
453     krb5_ui_4 gss_flags = 0;
454     int decode_req_message = 0;
455     krb5_gss_ctx_id_rec *ctx = NULL;
456     krb5_timestamp now;
457     gss_buffer_desc token;
458     krb5_auth_context auth_context = NULL;
459     krb5_ticket * ticket = NULL;
460     int option_id;
461     krb5_data option;
462     const gss_OID_desc *mech_used = NULL;
463     OM_uint32 major_status = GSS_S_FAILURE;
464     OM_uint32 tmp_minor_status;
465     krb5_error krb_error_data;
466     krb5_data scratch;
467     gss_cred_id_t cred_handle = NULL;
468     krb5_gss_cred_id_t deleg_cred = NULL;
469     krb5int_access kaccess;
470     int cred_rcache = 0;
471     int no_encap = 0;
472     krb5_flags ap_req_options = 0;
473     krb5_enctype negotiated_etype;
474     krb5_authdata_context ad_context = NULL;
475     krb5_principal accprinc = NULL;
476
477     code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
478     if (code) {
479         *minor_status = code;
480         return(GSS_S_FAILURE);
481     }
482
483     code = krb5_gss_init_context(&context);
484     if (code) {
485         *minor_status = code;
486         return GSS_S_FAILURE;
487     }
488
489     /* set up returns to be freeable */
490
491     if (src_name)
492         *src_name = (gss_name_t) NULL;
493     output_token->length = 0;
494     output_token->value = NULL;
495     token.value = 0;
496     reqcksum.contents = 0;
497     ap_req.data = 0;
498     ap_rep.data = 0;
499
500     if (mech_type)
501         *mech_type = GSS_C_NULL_OID;
502     /* return a bogus cred handle */
503     if (delegated_cred_handle)
504         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
505
506     /* handle default cred handle */
507     if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
508         major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
509                                              GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
510                                              GSS_C_ACCEPT, &cred_handle,
511                                              NULL, NULL);
512         if (major_status != GSS_S_COMPLETE) {
513             code = *minor_status;
514             goto fail;
515         }
516     } else {
517         major_status = krb5_gss_validate_cred(minor_status,
518                                               verifier_cred_handle);
519         if (GSS_ERROR(major_status)) {
520             code = *minor_status;
521             goto fail;
522         }
523         cred_handle = verifier_cred_handle;
524     }
525
526     cred = (krb5_gss_cred_id_t) cred_handle;
527
528     /* make sure the supplied credentials are valid for accept */
529
530     if ((cred->usage != GSS_C_ACCEPT) &&
531         (cred->usage != GSS_C_BOTH)) {
532         code = 0;
533         major_status = GSS_S_NO_CRED;
534         goto fail;
535     }
536
537     /* verify the token's integrity, and leave the token in ap_req.
538        figure out which mech oid was used, and save it */
539
540     ptr = (unsigned char *) input_token->value;
541
542     if (!(code = g_verify_token_header(gss_mech_krb5,
543                                        &(ap_req.length),
544                                        &ptr, KG_TOK_CTX_AP_REQ,
545                                        input_token->length, 1))) {
546         mech_used = gss_mech_krb5;
547     } else if ((code == G_WRONG_MECH)
548                &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
549                                                 &(ap_req.length),
550                                                 &ptr, KG_TOK_CTX_AP_REQ,
551                                                 input_token->length, 1))) {
552         mech_used = gss_mech_iakerb;
553     } else if ((code == G_WRONG_MECH)
554                &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
555                                                 &(ap_req.length),
556                                                 &ptr, KG_TOK_CTX_AP_REQ,
557                                                 input_token->length, 1))) {
558         mech_used = gss_mech_krb5_wrong;
559     } else if ((code == G_WRONG_MECH) &&
560                !(code = g_verify_token_header(gss_mech_krb5_old,
561                                               &(ap_req.length),
562                                               &ptr, KG_TOK_CTX_AP_REQ,
563                                               input_token->length, 1))) {
564         /*
565          * Previous versions of this library used the old mech_id
566          * and some broken behavior (wrong IV on checksum
567          * encryption).  We support the old mech_id for
568          * compatibility, and use it to decide when to use the
569          * old behavior.
570          */
571         mech_used = gss_mech_krb5_old;
572     } else if (code == G_WRONG_TOKID) {
573         major_status = GSS_S_CONTINUE_NEEDED;
574         code = KRB5KRB_AP_ERR_MSG_TYPE;
575         mech_used = gss_mech_krb5;
576         goto fail;
577     } else if (code == G_BAD_TOK_HEADER) {
578         /* DCE style not encapsulated */
579         ap_req.length = input_token->length;
580         ap_req.data = input_token->value;
581         mech_used = gss_mech_krb5;
582         no_encap = 1;
583     } else {
584         major_status = GSS_S_DEFECTIVE_TOKEN;
585         goto fail;
586     }
587
588     sptr = (char *) ptr;
589     TREAD_STR(sptr, ap_req.data, ap_req.length);
590     decode_req_message = 1;
591
592     /* construct the sender_addr */
593
594     if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
595         (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
596         /* XXX is this right? */
597         addr.addrtype = ADDRTYPE_INET;
598         addr.length = input_chan_bindings->initiator_address.length;
599         addr.contents = input_chan_bindings->initiator_address.value;
600
601         paddr = &addr;
602     } else {
603         paddr = NULL;
604     }
605
606     /* decode the AP_REQ message */
607
608     /* decode the message */
609
610     if ((code = krb5_auth_con_init(context, &auth_context))) {
611         major_status = GSS_S_FAILURE;
612         save_error_info((OM_uint32)code, context);
613         goto fail;
614     }
615     if (cred->rcache) {
616         cred_rcache = 1;
617         if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
618             major_status = GSS_S_FAILURE;
619             goto fail;
620         }
621     }
622     if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
623         major_status = GSS_S_FAILURE;
624         goto fail;
625     }
626
627     /* Limit the encryption types negotiated (if requested). */
628     if (cred->req_enctypes) {
629         if ((code = krb5_set_default_tgs_enctypes(context,
630                                                   cred->req_enctypes))) {
631             major_status = GSS_S_FAILURE;
632             goto fail;
633         }
634     }
635
636     if (!cred->default_identity) {
637         if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
638             major_status = GSS_S_FAILURE;
639             goto fail;
640         }
641     }
642
643     code = krb5_rd_req(context, &auth_context, &ap_req, accprinc,
644                        cred->keytab, &ap_req_options, &ticket);
645     krb5_free_principal(context, accprinc);
646     if (code) {
647         major_status = GSS_S_FAILURE;
648         goto fail;
649     }
650     krb5_auth_con_setflags(context, auth_context,
651                            KRB5_AUTH_CONTEXT_DO_SEQUENCE);
652
653     krb5_auth_con_getauthenticator(context, auth_context, &authdat);
654
655 #if 0
656     /* make sure the necessary parts of the authdat are present */
657
658     if ((authdat->authenticator->subkey == NULL) ||
659         (authdat->ticket->enc_part2 == NULL)) {
660         code = KG_NO_SUBKEY;
661         major_status = GSS_S_FAILURE;
662         goto fail;
663     }
664 #endif
665
666     if (authdat->checksum == NULL) {
667         /* missing checksum counts as "inappropriate type" */
668         code = KRB5KRB_AP_ERR_INAPP_CKSUM;
669         major_status = GSS_S_FAILURE;
670         goto fail;
671     }
672
673     if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
674         /* Samba does not send 0x8003 GSS-API checksums */
675         krb5_boolean valid;
676         krb5_key subkey;
677         krb5_data zero;
678
679         code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
680         if (code) {
681             major_status = GSS_S_FAILURE;
682             goto fail;
683         }
684
685         zero.length = 0;
686         zero.data = "";
687
688         code = krb5_k_verify_checksum(context,
689                                       subkey,
690                                       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
691                                       &zero,
692                                       authdat->checksum,
693                                       &valid);
694         krb5_k_free_key(context, subkey);
695         if (code || !valid) {
696             major_status = GSS_S_BAD_SIG;
697             goto fail;
698         }
699
700         gss_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
701         bigend = 0;
702         decode_req_message = 0;
703     } else {
704         /* gss krb5 v1 */
705
706         /* stash this now, for later. */
707         code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
708         if (code) {
709             major_status = GSS_S_FAILURE;
710             goto fail;
711         }
712
713         /* verify that the checksum is correct */
714
715         /*
716           The checksum may be either exactly 24 bytes, in which case
717           no options are specified, or greater than 24 bytes, in which case
718           one or more options are specified. Currently, the only valid
719           option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
720         */
721
722         if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
723             (authdat->checksum->length < 24)) {
724             code = 0;
725             major_status = GSS_S_BAD_BINDINGS;
726             goto fail;
727         }
728
729         /*
730           "Be liberal in what you accept, and
731           conservative in what you send"
732           -- rfc1123
733
734           This code will let this acceptor interoperate with an initiator
735           using little-endian or big-endian integer encoding.
736         */
737
738         ptr = (unsigned char *) authdat->checksum->contents;
739         bigend = 0;
740
741         TREAD_INT(ptr, tmp, bigend);
742
743         if (tmp != md5len) {
744             ptr = (unsigned char *) authdat->checksum->contents;
745             bigend = 1;
746
747             TREAD_INT(ptr, tmp, bigend);
748
749             if (tmp != md5len) {
750                 code = KG_BAD_LENGTH;
751                 major_status = GSS_S_FAILURE;
752                 goto fail;
753             }
754         }
755
756         /* at this point, bigend is set according to the initiator's
757            byte order */
758
759
760         /*
761           The following section of code attempts to implement the
762           optional channel binding facility as described in RFC2743.
763
764           Since this facility is optional channel binding may or may
765           not have been provided by either the client or the server.
766
767           If the server has specified input_chan_bindings equal to
768           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
769           the server does provide channel bindings then we compute
770           a checksum and compare against those provided by the
771           client.         */
772
773         if ((code = kg_checksum_channel_bindings(context,
774                                                  input_chan_bindings,
775                                                  &reqcksum, bigend))) {
776             major_status = GSS_S_BAD_BINDINGS;
777             goto fail;
778         }
779
780         /* Always read the clients bindings - eventhough we might ignore them */
781         TREAD_STR(ptr, ptr2, reqcksum.length);
782
783         if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
784             if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
785                 xfree(reqcksum.contents);
786                 reqcksum.contents = 0;
787                 code = 0;
788                 major_status = GSS_S_BAD_BINDINGS;
789                 goto fail;
790             }
791
792         }
793
794         xfree(reqcksum.contents);
795         reqcksum.contents = 0;
796
797         TREAD_INT(ptr, gss_flags, bigend);
798 #if 0
799         gss_flags &= ~GSS_C_DELEG_FLAG; /* mask out the delegation flag; if
800                                            there's a delegation, we'll set
801                                            it below */
802 #endif
803         decode_req_message = 0;
804
805         /* if the checksum length > 24, there are options to process */
806
807         i = authdat->checksum->length - 24;
808         if (i && (gss_flags & GSS_C_DELEG_FLAG)) {
809             if (i >= 4) {
810                 TREAD_INT16(ptr, option_id, bigend);
811                 TREAD_INT16(ptr, option.length, bigend);
812                 i -= 4;
813
814                 if (i < option.length || option.length < 0) {
815                     code = KG_BAD_LENGTH;
816                     major_status = GSS_S_FAILURE;
817                     goto fail;
818                 }
819
820                 /* have to use ptr2, since option.data is wrong type and
821                    macro uses ptr as both lvalue and rvalue */
822
823                 TREAD_STR(ptr, ptr2, option.length);
824                 option.data = (char *) ptr2;
825
826                 i -= option.length;
827
828                 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
829                     major_status = GSS_S_FAILURE;
830                     goto fail;
831                 }
832
833                 /* store the delegated credential */
834
835                 code = rd_and_store_for_creds(context, auth_context, &option,
836                                               (delegated_cred_handle) ?
837                                               &deleg_cred : NULL);
838                 if (code) {
839                     major_status = GSS_S_FAILURE;
840                     goto fail;
841                 }
842
843             } /* if i >= 4 */
844             /* ignore any additional trailing data, for now */
845         }
846         while (i > 0) {
847             /* Process Type-Length-Data options */
848             if (i < 8) {
849                 code = KG_BAD_LENGTH;
850                 major_status = GSS_S_FAILURE;
851                 goto fail;
852             }
853             TREAD_INT(ptr, option_id, 1);
854             TREAD_INT(ptr, option.length, 1);
855             i -= 8;
856             if (i < option.length) {
857                 code = KG_BAD_LENGTH;
858                 major_status = GSS_S_FAILURE;
859                 goto fail;
860             }
861             TREAD_STR(ptr, ptr2, option.length);
862             option.data = (char *)ptr2;
863
864             i -= option.length;
865
866             code = kg_process_extension(context, auth_context,
867                                         option_id, &option, exts);
868             if (code != 0) {
869                 major_status = GSS_S_FAILURE;
870                 goto fail;
871             }
872         }
873     }
874
875     if (exts->iakerb.conv && !exts->iakerb.verified) {
876         major_status = GSS_S_BAD_SIG;
877         goto fail;
878     }
879
880     /* only DCE_STYLE clients are allowed to send raw AP-REQs */
881     if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
882         major_status = GSS_S_DEFECTIVE_TOKEN;
883         goto fail;
884     }
885
886     /* create the ctx struct and start filling it in */
887
888     if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
889         == NULL) {
890         code = ENOMEM;
891         major_status = GSS_S_FAILURE;
892         goto fail;
893     }
894
895     memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
896     ctx->magic = KG_CONTEXT;
897     ctx->mech_used = (gss_OID) mech_used;
898     ctx->auth_context = auth_context;
899     ctx->initiate = 0;
900     ctx->gss_flags = (GSS_C_TRANS_FLAG |
901                       ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
902                                       GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
903                                       GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
904                                       GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
905                                       GSS_C_EXTENDED_ERROR_FLAG)));
906     ctx->seed_init = 0;
907     ctx->big_endian = bigend;
908     ctx->cred_rcache = cred_rcache;
909
910     /* XXX move this into gss_name_t */
911     if (        (code = krb5_merge_authdata(context,
912                                             ticket->enc_part2->authorization_data,
913                                             authdat->authorization_data,
914                                             &ctx->authdata))) {
915         major_status = GSS_S_FAILURE;
916         goto fail;
917     }
918     if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
919                              &ctx->here))) {
920         major_status = GSS_S_FAILURE;
921         goto fail;
922     }
923     if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
924                                                    &ad_context))) {
925         major_status = GSS_S_FAILURE;
926         goto fail;
927     }
928     if ((code = kg_init_name(context, authdat->client, NULL, NULL,
929                              ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
930         major_status = GSS_S_FAILURE;
931         goto fail;
932     }
933     /* Now owned by ctx->there */
934     authdat->client = NULL;
935     krb5_auth_con_set_authdata_context(context, auth_context, NULL);
936
937     if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
938                                               &ctx->subkey))) {
939         major_status = GSS_S_FAILURE;
940         goto fail;
941     }
942
943     /* use the session key if the subkey isn't present */
944
945     if (ctx->subkey == NULL) {
946         if ((code = krb5_auth_con_getkey_k(context, auth_context,
947                                            &ctx->subkey))) {
948             major_status = GSS_S_FAILURE;
949             goto fail;
950         }
951     }
952
953     if (ctx->subkey == NULL) {
954         /* this isn't a very good error, but it's not clear to me this
955            can actually happen */
956         major_status = GSS_S_FAILURE;
957         code = KRB5KDC_ERR_NULL_KEY;
958         goto fail;
959     }
960
961     ctx->enc = NULL;
962     ctx->seq = NULL;
963     ctx->have_acceptor_subkey = 0;
964     /* DCE_STYLE implies acceptor_subkey */
965     if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
966         code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
967         if (code) {
968             major_status = GSS_S_FAILURE;
969             goto fail;
970         }
971     }
972     ctx->krb_times = ticket->enc_part2->times; /* struct copy */
973     ctx->krb_flags = ticket->enc_part2->flags;
974
975     if (delegated_cred_handle != NULL &&
976         deleg_cred == NULL && /* no unconstrained delegation */
977         cred->usage == GSS_C_BOTH &&
978         (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
979         /*
980          * Now, we always fabricate a delegated credentials handle
981          * containing the service ticket to ourselves, which can be
982          * used for S4U2Proxy.
983          */
984         major_status = create_constrained_deleg_creds(minor_status, cred,
985                                                       ticket, &deleg_cred,
986                                                       context);
987         if (GSS_ERROR(major_status))
988             goto fail;
989         ctx->gss_flags |= GSS_C_DELEG_FLAG;
990     }
991
992     krb5_free_ticket(context, ticket); /* Done with ticket */
993
994     {
995         krb5_int32 seq_temp;
996         krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
997         ctx->seq_recv = seq_temp;
998     }
999
1000     if ((code = krb5_timeofday(context, &now))) {
1001         major_status = GSS_S_FAILURE;
1002         goto fail;
1003     }
1004
1005     if (ctx->krb_times.endtime < now) {
1006         code = 0;
1007         major_status = GSS_S_CREDENTIALS_EXPIRED;
1008         goto fail;
1009     }
1010
1011     g_order_init(&(ctx->seqstate), ctx->seq_recv,
1012                  (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
1013                  (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
1014
1015     /* DCE_STYLE implies mutual authentication */
1016     if (ctx->gss_flags & GSS_C_DCE_STYLE)
1017         ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
1018
1019     /* at this point, the entire context structure is filled in,
1020        so it can be released.  */
1021
1022     /* generate an AP_REP if necessary */
1023
1024     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1025         unsigned char * ptr3;
1026         krb5_int32 seq_temp;
1027         int cfx_generate_subkey;
1028
1029         /*
1030          * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
1031          * because pre-CFX tokens do not indicate which key to use. (Note that
1032          * DCE_STYLE implies that we will use a subkey.)
1033          */
1034         if (ctx->proto == 0 &&
1035             (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
1036             (ap_req_options & AP_OPTS_USE_SUBKEY)) {
1037             code = (*kaccess.auth_con_get_subkey_enctype)(context,
1038                                                           auth_context,
1039                                                           &negotiated_etype);
1040             if (code != 0) {
1041                 major_status = GSS_S_FAILURE;
1042                 goto fail;
1043             }
1044
1045             switch (negotiated_etype) {
1046             case ENCTYPE_DES_CBC_MD5:
1047             case ENCTYPE_DES_CBC_MD4:
1048             case ENCTYPE_DES_CBC_CRC:
1049             case ENCTYPE_DES3_CBC_SHA1:
1050             case ENCTYPE_ARCFOUR_HMAC:
1051             case ENCTYPE_ARCFOUR_HMAC_EXP:
1052                 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
1053                  * enctype, even though RFC 4757 treats it as one. */
1054                 ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
1055                 break;
1056             }
1057         }
1058
1059         if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
1060             (ap_req_options & AP_OPTS_USE_SUBKEY))
1061             cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1062         else
1063             cfx_generate_subkey = 0;
1064
1065         if (cfx_generate_subkey) {
1066             krb5_int32 acflags;
1067             code = krb5_auth_con_getflags(context, auth_context, &acflags);
1068             if (code == 0) {
1069                 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1070                 code = krb5_auth_con_setflags(context, auth_context, acflags);
1071             }
1072             if (code) {
1073                 major_status = GSS_S_FAILURE;
1074                 goto fail;
1075             }
1076         }
1077
1078         if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1079             major_status = GSS_S_FAILURE;
1080             goto fail;
1081         }
1082
1083         krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
1084         ctx->seq_send = seq_temp & 0xffffffffL;
1085
1086         if (cfx_generate_subkey) {
1087             /* Get the new acceptor subkey.  With the code above, there
1088                should always be one if we make it to this point.  */
1089             code = krb5_auth_con_getsendsubkey_k(context, auth_context,
1090                                                  &ctx->acceptor_subkey);
1091             if (code != 0) {
1092                 major_status = GSS_S_FAILURE;
1093                 goto fail;
1094             }
1095             ctx->have_acceptor_subkey = 1;
1096
1097             code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
1098                                  &ctx->acceptor_subkey_cksumtype);
1099             if (code) {
1100                 major_status = GSS_S_FAILURE;
1101                 goto fail;
1102             }
1103         }
1104
1105         /* the reply token hasn't been sent yet, but that's ok. */
1106         if (ctx->gss_flags & GSS_C_DCE_STYLE) {
1107             assert(ctx->have_acceptor_subkey);
1108
1109             /* in order to force acceptor subkey to be used, don't set PROT_READY */
1110
1111             /* Raw AP-REP is returned */
1112             output_token->length = ap_rep.length;
1113             output_token->value = ap_rep.data;
1114             ap_rep.data = NULL; /* don't double free */
1115
1116             ctx->established = 0;
1117
1118             *context_handle = (gss_ctx_id_t)ctx;
1119             *minor_status = 0;
1120             major_status = GSS_S_CONTINUE_NEEDED;
1121
1122             /* Only last leg should set return arguments */
1123             goto fail;
1124         } else
1125             ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1126
1127         ctx->established = 1;
1128
1129         token.length = g_token_size(mech_used, ap_rep.length);
1130
1131         if ((token.value = (unsigned char *) xmalloc(token.length))
1132             == NULL) {
1133             major_status = GSS_S_FAILURE;
1134             code = ENOMEM;
1135             goto fail;
1136         }
1137         ptr3 = token.value;
1138         g_make_token_header(mech_used, ap_rep.length,
1139                             &ptr3, KG_TOK_CTX_AP_REP);
1140
1141         TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1142
1143         ctx->established = 1;
1144
1145     } else {
1146         token.length = 0;
1147         token.value = NULL;
1148         ctx->seq_send = ctx->seq_recv;
1149
1150         ctx->established = 1;
1151     }
1152
1153     /* set the return arguments */
1154
1155     if (src_name) {
1156         code = kg_duplicate_name(context, ctx->there, &name);
1157         if (code) {
1158             major_status = GSS_S_FAILURE;
1159             goto fail;
1160         }
1161     }
1162
1163     if (mech_type)
1164         *mech_type = (gss_OID) mech_used;
1165
1166     if (time_rec)
1167         *time_rec = ctx->krb_times.endtime - now;
1168
1169     if (ret_flags)
1170         *ret_flags = ctx->gss_flags;
1171
1172     *context_handle = (gss_ctx_id_t)ctx;
1173     *output_token = token;
1174
1175     if (src_name)
1176         *src_name = (gss_name_t) name;
1177
1178     if (delegated_cred_handle)
1179         *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1180
1181     /* finally! */
1182
1183     *minor_status = 0;
1184     major_status = GSS_S_COMPLETE;
1185
1186 fail:
1187     if (authdat)
1188         krb5_free_authenticator(context, authdat);
1189     /* The ctx structure has the handle of the auth_context */
1190     if (auth_context && !ctx) {
1191         if (cred_rcache)
1192             (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1193
1194         krb5_auth_con_free(context, auth_context);
1195     }
1196     if (reqcksum.contents)
1197         xfree(reqcksum.contents);
1198     if (ap_rep.data)
1199         krb5_free_data_contents(context, &ap_rep);
1200     if (major_status == GSS_S_COMPLETE ||
1201         (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
1202         ctx->k5_context = context;
1203         context = NULL;
1204         goto done;
1205     }
1206
1207     /* from here on is the real "fail" code */
1208
1209     if (ctx)
1210         (void) krb5_gss_delete_sec_context(&tmp_minor_status,
1211                                            (gss_ctx_id_t *) &ctx, NULL);
1212     if (deleg_cred) { /* free memory associated with the deleg credential */
1213         if (deleg_cred->ccache)
1214             (void)krb5_cc_close(context, deleg_cred->ccache);
1215         if (deleg_cred->name)
1216             kg_release_name(context, &deleg_cred->name);
1217         xfree(deleg_cred);
1218     }
1219     if (token.value)
1220         xfree(token.value);
1221     if (name) {
1222         (void) kg_release_name(context, &name);
1223     }
1224
1225     *minor_status = code;
1226
1227     /*
1228      * If decode_req_message is set, then we need to decode the ap_req
1229      * message to determine whether or not to send a response token.
1230      * We need to do this because for some errors we won't be able to
1231      * decode the authenticator to read out the gss_flags field.
1232      */
1233     if (decode_req_message) {
1234         krb5_ap_req      * request;
1235
1236         if (decode_krb5_ap_req(&ap_req, &request))
1237             goto done;
1238
1239         if (request->ap_options & AP_OPTS_MUTUAL_REQUIRED)
1240             gss_flags |= GSS_C_MUTUAL_FLAG;
1241         krb5_free_ap_req(context, request);
1242     }
1243
1244     if (cred
1245         && ((gss_flags & GSS_C_MUTUAL_FLAG)
1246             || (major_status == GSS_S_CONTINUE_NEEDED))) {
1247         unsigned int tmsglen;
1248         int toktype;
1249
1250         /*
1251          * The client is expecting a response, so we can send an
1252          * error token back
1253          */
1254         memset(&krb_error_data, 0, sizeof(krb_error_data));
1255
1256         code -= ERROR_TABLE_BASE_krb5;
1257         if (code < 0 || code > 128)
1258             code = 60 /* KRB_ERR_GENERIC */;
1259
1260         krb_error_data.error = code;
1261         (void) krb5_us_timeofday(context, &krb_error_data.stime,
1262                                  &krb_error_data.susec);
1263
1264         code = krb5_mk_error(context, &krb_error_data, &scratch);
1265         if (code)
1266             goto done;
1267
1268         tmsglen = scratch.length;
1269         toktype = KG_TOK_CTX_ERROR;
1270
1271         token.length = g_token_size(mech_used, tmsglen);
1272         token.value = (unsigned char *) xmalloc(token.length);
1273         if (!token.value)
1274             goto done;
1275
1276         ptr = token.value;
1277         g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1278
1279         TWRITE_STR(ptr, scratch.data, scratch.length);
1280         krb5_free_data_contents(context, &scratch);
1281
1282         *output_token = token;
1283     }
1284
1285 done:
1286     if (!verifier_cred_handle && cred_handle) {
1287         krb5_gss_release_cred(&tmp_minor_status, &cred_handle);
1288     }
1289     if (context) {
1290         if (major_status && *minor_status)
1291             save_error_info(*minor_status, context);
1292         krb5_free_context(context);
1293     }
1294     return (major_status);
1295 }
1296 #endif /* LEAN_CLIENT */
1297
1298 OM_uint32 KRB5_CALLCONV
1299 krb5_gss_accept_sec_context_ext(
1300     OM_uint32 *minor_status,
1301     gss_ctx_id_t *context_handle,
1302     gss_cred_id_t verifier_cred_handle,
1303     gss_buffer_t input_token,
1304     gss_channel_bindings_t input_chan_bindings,
1305     gss_name_t *src_name,
1306     gss_OID *mech_type,
1307     gss_buffer_t output_token,
1308     OM_uint32 *ret_flags,
1309     OM_uint32 *time_rec,
1310     gss_cred_id_t *delegated_cred_handle,
1311     krb5_gss_ctx_ext_t exts)
1312 {
1313     krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
1314
1315     /*
1316      * Context handle must be unspecified.  Actually, it must be
1317      * non-established, but currently, accept_sec_context never returns
1318      * a non-established context handle.
1319      */
1320     /*SUPPRESS 29*/
1321     if (ctx != NULL) {
1322         if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
1323             return kg_accept_dce(minor_status, context_handle,
1324                                  verifier_cred_handle, input_token,
1325                                  input_chan_bindings, src_name, mech_type,
1326                                  output_token, ret_flags, time_rec,
1327                                  delegated_cred_handle);
1328         } else {
1329             *minor_status = EINVAL;
1330             save_error_string(EINVAL, "accept_sec_context called with existing context handle");
1331             return GSS_S_FAILURE;
1332         }
1333     }
1334
1335     return kg_accept_krb5(minor_status, context_handle,
1336                           verifier_cred_handle, input_token,
1337                           input_chan_bindings, src_name, mech_type,
1338                           output_token, ret_flags, time_rec,
1339                           delegated_cred_handle, exts);
1340 }
1341
1342 OM_uint32 KRB5_CALLCONV
1343 krb5_gss_accept_sec_context(minor_status, context_handle,
1344                             verifier_cred_handle, input_token,
1345                             input_chan_bindings, src_name, mech_type,
1346                             output_token, ret_flags, time_rec,
1347                             delegated_cred_handle)
1348     OM_uint32 *minor_status;
1349     gss_ctx_id_t *context_handle;
1350     gss_cred_id_t verifier_cred_handle;
1351     gss_buffer_t input_token;
1352     gss_channel_bindings_t input_chan_bindings;
1353     gss_name_t *src_name;
1354     gss_OID *mech_type;
1355     gss_buffer_t output_token;
1356     OM_uint32 *ret_flags;
1357     OM_uint32 *time_rec;
1358     gss_cred_id_t *delegated_cred_handle;
1359 {
1360     krb5_gss_ctx_ext_rec exts;
1361
1362     memset(&exts, 0, sizeof(exts));
1363
1364     return krb5_gss_accept_sec_context_ext(minor_status,
1365                                            context_handle,
1366                                            verifier_cred_handle,
1367                                            input_token,
1368                                            input_chan_bindings,
1369                                            src_name,
1370                                            mech_type,
1371                                            output_token,
1372                                            ret_flags,
1373                                            time_rec,
1374                                            delegated_cred_handle,
1375                                            &exts);
1376 }