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