Imported Upstream version 1.15.1
[platform/upstream/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->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     ap_rep.data = input_token->value;
329     ap_rep.length = input_token->length;
330
331     code = krb5_rd_rep_dce(ctx->k5_context,
332                            ctx->auth_context,
333                            &ap_rep,
334                            &nonce);
335     if (code != 0) {
336         major_status = GSS_S_FAILURE;
337         goto fail;
338     }
339
340     ctx->established = 1;
341
342     if (src_name) {
343         code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
344         if (code) {
345             major_status = GSS_S_FAILURE;
346             goto fail;
347         }
348         *src_name = (gss_name_t) name;
349     }
350
351     if (mech_type)
352         *mech_type = ctx->mech_used;
353
354     if (time_rec)
355         *time_rec = ctx->krb_times.endtime + ctx->k5_context->clockskew - now;
356
357     /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
358      * delegation yet. */
359     if (ret_flags)
360         *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
361
362     *minor_status = 0;
363
364     return GSS_S_COMPLETE;
365
366 fail:
367     /* real failure code follows */
368
369     (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
370                                        NULL);
371     *context_handle = GSS_C_NO_CONTEXT;
372     *minor_status = code;
373
374     return major_status;
375 }
376
377 static krb5_error_code
378 kg_process_extension(krb5_context context,
379                      krb5_auth_context auth_context,
380                      int ext_type,
381                      krb5_data *ext_data,
382                      krb5_gss_ctx_ext_t exts)
383 {
384     krb5_error_code code = 0;
385
386     assert(exts != NULL);
387
388     switch (ext_type) {
389     case KRB5_GSS_EXTS_IAKERB_FINISHED:
390         if (exts->iakerb.conv == NULL) {
391             code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
392         } else {
393             krb5_key key;
394
395             code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
396             if (code != 0)
397                 break;
398
399             code = iakerb_verify_finished(context, key, exts->iakerb.conv,
400                                           ext_data);
401             if (code == 0)
402                 exts->iakerb.verified = 1;
403
404             krb5_k_free_key(context, key);
405         }
406         break;
407     default:
408         break;
409     }
410
411     return code;
412 }
413
414 static OM_uint32
415 kg_accept_krb5(minor_status, context_handle,
416                verifier_cred_handle, input_token,
417                input_chan_bindings, src_name, mech_type,
418                output_token, ret_flags, time_rec,
419                delegated_cred_handle, exts)
420     OM_uint32 *minor_status;
421     gss_ctx_id_t *context_handle;
422     gss_cred_id_t verifier_cred_handle;
423     gss_buffer_t input_token;
424     gss_channel_bindings_t input_chan_bindings;
425     gss_name_t *src_name;
426     gss_OID *mech_type;
427     gss_buffer_t output_token;
428     OM_uint32 *ret_flags;
429     OM_uint32 *time_rec;
430     gss_cred_id_t *delegated_cred_handle;
431     krb5_gss_ctx_ext_t exts;
432 {
433     krb5_context context;
434     unsigned char *ptr, *ptr2;
435     char *sptr;
436     OM_uint32 tmp;
437     size_t md5len;
438     krb5_gss_cred_id_t cred = 0;
439     krb5_data ap_rep, ap_req;
440     unsigned int i;
441     krb5_error_code code;
442     krb5_address addr, *paddr;
443     krb5_authenticator *authdat = 0;
444     krb5_checksum reqcksum;
445     krb5_gss_name_t name = NULL;
446     krb5_ui_4 gss_flags = 0;
447     krb5_gss_ctx_id_rec *ctx = NULL;
448     krb5_timestamp now;
449     gss_buffer_desc token;
450     krb5_auth_context auth_context = NULL;
451     krb5_ticket * ticket = NULL;
452     int option_id;
453     krb5_data option;
454     const gss_OID_desc *mech_used = NULL;
455     OM_uint32 major_status = GSS_S_FAILURE;
456     OM_uint32 tmp_minor_status;
457     krb5_error krb_error_data;
458     krb5_data scratch;
459     gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
460     krb5_gss_cred_id_t deleg_cred = NULL;
461     krb5int_access kaccess;
462     int cred_rcache = 0;
463     int no_encap = 0;
464     int token_deleg_flag = 0;
465     krb5_flags ap_req_options = 0;
466     krb5_enctype negotiated_etype;
467     krb5_authdata_context ad_context = NULL;
468     krb5_principal accprinc = NULL;
469     krb5_ap_req *request = NULL;
470
471     code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
472     if (code) {
473         *minor_status = code;
474         return(GSS_S_FAILURE);
475     }
476
477     code = krb5_gss_init_context(&context);
478     if (code) {
479         *minor_status = code;
480         return GSS_S_FAILURE;
481     }
482
483     /* set up returns to be freeable */
484
485     if (src_name)
486         *src_name = (gss_name_t) NULL;
487     output_token->length = 0;
488     output_token->value = NULL;
489     token.value = 0;
490     reqcksum.contents = 0;
491     ap_req.data = 0;
492     ap_rep.data = 0;
493
494     if (mech_type)
495         *mech_type = GSS_C_NULL_OID;
496     /* return a bogus cred handle */
497     if (delegated_cred_handle)
498         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
499
500     /* handle default cred handle */
501     if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
502         major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
503                                              GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
504                                              GSS_C_ACCEPT, &defcred,
505                                              NULL, NULL);
506         if (major_status != GSS_S_COMPLETE) {
507             code = *minor_status;
508             goto fail;
509         }
510         verifier_cred_handle = defcred;
511     }
512
513     /* Resolve any initiator state in the verifier cred and lock it. */
514     major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
515                                    GSS_C_NO_NAME);
516     if (GSS_ERROR(major_status)) {
517         code = *minor_status;
518         goto fail;
519     }
520     cred = (krb5_gss_cred_id_t)verifier_cred_handle;
521
522     /* make sure the supplied credentials are valid for accept */
523
524     if ((cred->usage != GSS_C_ACCEPT) &&
525         (cred->usage != GSS_C_BOTH)) {
526         code = 0;
527         major_status = GSS_S_NO_CRED;
528         goto fail;
529     }
530
531     /* verify the token's integrity, and leave the token in ap_req.
532        figure out which mech oid was used, and save it */
533
534     ptr = (unsigned char *) input_token->value;
535
536     if (!(code = g_verify_token_header(gss_mech_krb5,
537                                        &(ap_req.length),
538                                        &ptr, KG_TOK_CTX_AP_REQ,
539                                        input_token->length, 1))) {
540         mech_used = gss_mech_krb5;
541     } else if ((code == G_WRONG_MECH)
542                &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
543                                                 &(ap_req.length),
544                                                 &ptr, KG_TOK_CTX_AP_REQ,
545                                                 input_token->length, 1))) {
546         mech_used = gss_mech_iakerb;
547     } else if ((code == G_WRONG_MECH)
548                &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
549                                                 &(ap_req.length),
550                                                 &ptr, KG_TOK_CTX_AP_REQ,
551                                                 input_token->length, 1))) {
552         mech_used = gss_mech_krb5_wrong;
553     } else if ((code == G_WRONG_MECH) &&
554                !(code = g_verify_token_header(gss_mech_krb5_old,
555                                               &(ap_req.length),
556                                               &ptr, KG_TOK_CTX_AP_REQ,
557                                               input_token->length, 1))) {
558         /*
559          * Previous versions of this library used the old mech_id
560          * and some broken behavior (wrong IV on checksum
561          * encryption).  We support the old mech_id for
562          * compatibility, and use it to decide when to use the
563          * old behavior.
564          */
565         mech_used = gss_mech_krb5_old;
566     } else if (code == G_WRONG_TOKID) {
567         major_status = GSS_S_CONTINUE_NEEDED;
568         code = KRB5KRB_AP_ERR_MSG_TYPE;
569         mech_used = gss_mech_krb5;
570         goto fail;
571     } else if (code == G_BAD_TOK_HEADER) {
572         /* DCE style not encapsulated */
573         ap_req.length = input_token->length;
574         ap_req.data = input_token->value;
575         mech_used = gss_mech_krb5;
576         no_encap = 1;
577     } else {
578         major_status = GSS_S_DEFECTIVE_TOKEN;
579         goto fail;
580     }
581
582     sptr = (char *) ptr;
583     TREAD_STR(sptr, ap_req.data, ap_req.length);
584
585     /* construct the sender_addr */
586
587     if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
588         (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
589         /* XXX is this right? */
590         addr.addrtype = ADDRTYPE_INET;
591         addr.length = input_chan_bindings->initiator_address.length;
592         addr.contents = input_chan_bindings->initiator_address.value;
593
594         paddr = &addr;
595     } else {
596         paddr = NULL;
597     }
598
599     /* decode the AP_REQ message */
600     code = decode_krb5_ap_req(&ap_req, &request);
601     if (code) {
602         major_status = GSS_S_FAILURE;
603         goto done;
604     }
605     ticket = request->ticket;
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     /* Limit the encryption types negotiated (if requested). */
627     if (cred->req_enctypes) {
628         if ((code = krb5_auth_con_setpermetypes(context, auth_context,
629                                                 cred->req_enctypes))) {
630             major_status = GSS_S_FAILURE;
631             goto fail;
632         }
633     }
634
635     if (!cred->default_identity) {
636         if ((code = kg_acceptor_princ(context, cred->name, &accprinc))) {
637             major_status = GSS_S_FAILURE;
638             goto fail;
639         }
640     }
641
642     code = krb5_rd_req_decoded(context, &auth_context, request, accprinc,
643                                cred->keytab, &ap_req_options, NULL);
644
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         /*
668          * Some SMB client implementations use handcrafted GSSAPI code that
669          * does not provide a checksum.  MS-KILE documents that the Microsoft
670          * implementation considers a missing checksum acceptable; the server
671          * assumes all flags are unset in this case, and does not check channel
672          * bindings.
673          */
674         gss_flags = 0;
675     } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
676         /* Samba does not send 0x8003 GSS-API checksums */
677         krb5_boolean valid;
678         krb5_key subkey;
679         krb5_data zero;
680
681         code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
682         if (code) {
683             major_status = GSS_S_FAILURE;
684             goto fail;
685         }
686
687         zero.length = 0;
688         zero.data = "";
689
690         code = krb5_k_verify_checksum(context,
691                                       subkey,
692                                       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
693                                       &zero,
694                                       authdat->checksum,
695                                       &valid);
696         krb5_k_free_key(context, subkey);
697         if (code || !valid) {
698             major_status = GSS_S_BAD_SIG;
699             goto fail;
700         }
701
702         /* Use ap_options from the request to guess the mutual flag. */
703         gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
704         if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
705             gss_flags |= GSS_C_MUTUAL_FLAG;
706     } else {
707         /* gss krb5 v1 */
708
709         /* stash this now, for later. */
710         code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
711         if (code) {
712             major_status = GSS_S_FAILURE;
713             goto fail;
714         }
715
716         /* verify that the checksum is correct */
717
718         /*
719           The checksum may be either exactly 24 bytes, in which case
720           no options are specified, or greater than 24 bytes, in which case
721           one or more options are specified. Currently, the only valid
722           option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
723         */
724
725         if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
726             (authdat->checksum->length < 24)) {
727             code = 0;
728             major_status = GSS_S_BAD_BINDINGS;
729             goto fail;
730         }
731
732         ptr = (unsigned char *) authdat->checksum->contents;
733
734         TREAD_INT(ptr, tmp, 0);
735
736         if (tmp != md5len) {
737             code = KG_BAD_LENGTH;
738             major_status = GSS_S_FAILURE;
739             goto fail;
740         }
741
742         /*
743           The following section of code attempts to implement the
744           optional channel binding facility as described in RFC2743.
745
746           Since this facility is optional channel binding may or may
747           not have been provided by either the client or the server.
748
749           If the server has specified input_chan_bindings equal to
750           GSS_C_NO_CHANNEL_BINDINGS then we skip the check.  If
751           the server does provide channel bindings then we compute
752           a checksum and compare against those provided by the
753           client.         */
754
755         if ((code = kg_checksum_channel_bindings(context,
756                                                  input_chan_bindings,
757                                                  &reqcksum))) {
758             major_status = GSS_S_BAD_BINDINGS;
759             goto fail;
760         }
761
762         /* Always read the clients bindings - eventhough we might ignore them */
763         TREAD_STR(ptr, ptr2, reqcksum.length);
764
765         if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
766             if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
767                 xfree(reqcksum.contents);
768                 reqcksum.contents = 0;
769                 code = 0;
770                 major_status = GSS_S_BAD_BINDINGS;
771                 goto fail;
772             }
773
774         }
775
776         xfree(reqcksum.contents);
777         reqcksum.contents = 0;
778
779         /* Read the token flags.  Remember if GSS_C_DELEG_FLAG was set, but
780          * mask it out until we actually read a delegated credential. */
781         TREAD_INT(ptr, gss_flags, 0);
782         token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
783         gss_flags &= ~GSS_C_DELEG_FLAG;
784
785         /* if the checksum length > 24, there are options to process */
786
787         i = authdat->checksum->length - 24;
788         if (i && token_deleg_flag) {
789             if (i >= 4) {
790                 TREAD_INT16(ptr, option_id, 0);
791                 TREAD_INT16(ptr, option.length, 0);
792                 i -= 4;
793
794                 if (i < option.length) {
795                     code = KG_BAD_LENGTH;
796                     major_status = GSS_S_FAILURE;
797                     goto fail;
798                 }
799
800                 /* have to use ptr2, since option.data is wrong type and
801                    macro uses ptr as both lvalue and rvalue */
802
803                 TREAD_STR(ptr, ptr2, option.length);
804                 option.data = (char *) ptr2;
805
806                 i -= option.length;
807
808                 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
809                     major_status = GSS_S_FAILURE;
810                     goto fail;
811                 }
812
813                 /* store the delegated credential */
814
815                 code = rd_and_store_for_creds(context, auth_context, &option,
816                                               (delegated_cred_handle) ?
817                                               &deleg_cred : NULL);
818                 if (code) {
819                     major_status = GSS_S_FAILURE;
820                     goto fail;
821                 }
822
823                 gss_flags |= GSS_C_DELEG_FLAG;
824             } /* if i >= 4 */
825             /* ignore any additional trailing data, for now */
826         }
827         while (i > 0) {
828             /* Process Type-Length-Data options */
829             if (i < 8) {
830                 code = KG_BAD_LENGTH;
831                 major_status = GSS_S_FAILURE;
832                 goto fail;
833             }
834             TREAD_INT(ptr, option_id, 1);
835             TREAD_INT(ptr, option.length, 1);
836             i -= 8;
837             if (i < option.length) {
838                 code = KG_BAD_LENGTH;
839                 major_status = GSS_S_FAILURE;
840                 goto fail;
841             }
842             TREAD_STR(ptr, ptr2, option.length);
843             option.data = (char *)ptr2;
844
845             i -= option.length;
846
847             code = kg_process_extension(context, auth_context,
848                                         option_id, &option, exts);
849             if (code != 0) {
850                 major_status = GSS_S_FAILURE;
851                 goto fail;
852             }
853         }
854     }
855
856     if (exts->iakerb.conv && !exts->iakerb.verified) {
857         major_status = GSS_S_BAD_SIG;
858         goto fail;
859     }
860
861     /* only DCE_STYLE clients are allowed to send raw AP-REQs */
862     if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
863         major_status = GSS_S_DEFECTIVE_TOKEN;
864         goto fail;
865     }
866
867     /* create the ctx struct and start filling it in */
868
869     if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
870         == NULL) {
871         code = ENOMEM;
872         major_status = GSS_S_FAILURE;
873         goto fail;
874     }
875
876     memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
877     ctx->magic = KG_CONTEXT;
878     ctx->mech_used = (gss_OID) mech_used;
879     ctx->auth_context = auth_context;
880     ctx->initiate = 0;
881     ctx->gss_flags = (GSS_C_TRANS_FLAG |
882                       ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
883                                       GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
884                                       GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
885                                       GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
886                                       GSS_C_EXTENDED_ERROR_FLAG)));
887     ctx->seed_init = 0;
888     ctx->cred_rcache = cred_rcache;
889
890     /* XXX move this into gss_name_t */
891     if (        (code = krb5_merge_authdata(context,
892                                             ticket->enc_part2->authorization_data,
893                                             authdat->authorization_data,
894                                             &ctx->authdata))) {
895         major_status = GSS_S_FAILURE;
896         goto fail;
897     }
898     if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
899                              &ctx->here))) {
900         major_status = GSS_S_FAILURE;
901         goto fail;
902     }
903     if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
904                                                    &ad_context))) {
905         major_status = GSS_S_FAILURE;
906         goto fail;
907     }
908     if ((code = kg_init_name(context, authdat->client, NULL, NULL,
909                              ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
910         major_status = GSS_S_FAILURE;
911         goto fail;
912     }
913     /* Now owned by ctx->there */
914     authdat->client = NULL;
915     krb5_auth_con_set_authdata_context(context, auth_context, NULL);
916
917     if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
918                                               &ctx->subkey))) {
919         major_status = GSS_S_FAILURE;
920         goto fail;
921     }
922
923     /* use the session key if the subkey isn't present */
924
925     if (ctx->subkey == NULL) {
926         if ((code = krb5_auth_con_getkey_k(context, auth_context,
927                                            &ctx->subkey))) {
928             major_status = GSS_S_FAILURE;
929             goto fail;
930         }
931     }
932
933     if (ctx->subkey == NULL) {
934         /* this isn't a very good error, but it's not clear to me this
935            can actually happen */
936         major_status = GSS_S_FAILURE;
937         code = KRB5KDC_ERR_NULL_KEY;
938         goto fail;
939     }
940
941     ctx->enc = NULL;
942     ctx->seq = NULL;
943     ctx->have_acceptor_subkey = 0;
944     /* DCE_STYLE implies acceptor_subkey */
945     if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
946         code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
947         if (code) {
948             major_status = GSS_S_FAILURE;
949             goto fail;
950         }
951     }
952     ctx->krb_times = ticket->enc_part2->times; /* struct copy */
953     ctx->krb_flags = ticket->enc_part2->flags;
954
955     if (delegated_cred_handle != NULL &&
956         deleg_cred == NULL && /* no unconstrained delegation */
957         cred->usage == GSS_C_BOTH &&
958         (ticket->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
959         /*
960          * Now, we always fabricate a delegated credentials handle
961          * containing the service ticket to ourselves, which can be
962          * used for S4U2Proxy.
963          */
964         major_status = create_constrained_deleg_creds(minor_status, cred,
965                                                       ticket, &deleg_cred,
966                                                       context);
967         if (GSS_ERROR(major_status))
968             goto fail;
969         ctx->gss_flags |= GSS_C_DELEG_FLAG;
970     }
971
972     {
973         krb5_int32 seq_temp;
974         krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
975         ctx->seq_recv = seq_temp;
976     }
977
978     if ((code = krb5_timeofday(context, &now))) {
979         major_status = GSS_S_FAILURE;
980         goto fail;
981     }
982
983     code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
984                            (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
985                            (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
986                            ctx->proto);
987     if (code) {
988         major_status = GSS_S_FAILURE;
989         goto fail;
990     }
991
992     /* DCE_STYLE implies mutual authentication */
993     if (ctx->gss_flags & GSS_C_DCE_STYLE)
994         ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
995
996     /* at this point, the entire context structure is filled in,
997        so it can be released.  */
998
999     /* generate an AP_REP if necessary */
1000
1001     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1002         unsigned char * ptr3;
1003         krb5_int32 seq_temp;
1004         int cfx_generate_subkey;
1005
1006         /*
1007          * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
1008          * because pre-CFX tokens do not indicate which key to use. (Note that
1009          * DCE_STYLE implies that we will use a subkey.)
1010          */
1011         if (ctx->proto == 0 &&
1012             (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
1013             (ap_req_options & AP_OPTS_USE_SUBKEY)) {
1014             code = (*kaccess.auth_con_get_subkey_enctype)(context,
1015                                                           auth_context,
1016                                                           &negotiated_etype);
1017             if (code != 0) {
1018                 major_status = GSS_S_FAILURE;
1019                 goto fail;
1020             }
1021
1022             switch (negotiated_etype) {
1023             case ENCTYPE_DES_CBC_MD5:
1024             case ENCTYPE_DES_CBC_MD4:
1025             case ENCTYPE_DES_CBC_CRC:
1026             case ENCTYPE_DES3_CBC_SHA1:
1027             case ENCTYPE_ARCFOUR_HMAC:
1028             case ENCTYPE_ARCFOUR_HMAC_EXP:
1029                 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
1030                  * enctype, even though RFC 4757 treats it as one. */
1031                 ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
1032                 break;
1033             }
1034         }
1035
1036         if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
1037             (ap_req_options & AP_OPTS_USE_SUBKEY))
1038             cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1039         else
1040             cfx_generate_subkey = 0;
1041
1042         if (cfx_generate_subkey) {
1043             krb5_int32 acflags;
1044             code = krb5_auth_con_getflags(context, auth_context, &acflags);
1045             if (code == 0) {
1046                 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1047                 code = krb5_auth_con_setflags(context, auth_context, acflags);
1048             }
1049             if (code) {
1050                 major_status = GSS_S_FAILURE;
1051                 goto fail;
1052             }
1053         }
1054
1055         if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1056             major_status = GSS_S_FAILURE;
1057             goto fail;
1058         }
1059
1060         krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
1061         ctx->seq_send = seq_temp & 0xffffffffL;
1062
1063         if (cfx_generate_subkey) {
1064             /* Get the new acceptor subkey.  With the code above, there
1065                should always be one if we make it to this point.  */
1066             code = krb5_auth_con_getsendsubkey_k(context, auth_context,
1067                                                  &ctx->acceptor_subkey);
1068             if (code != 0) {
1069                 major_status = GSS_S_FAILURE;
1070                 goto fail;
1071             }
1072             ctx->have_acceptor_subkey = 1;
1073
1074             code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
1075                                  &ctx->acceptor_subkey_cksumtype);
1076             if (code) {
1077                 major_status = GSS_S_FAILURE;
1078                 goto fail;
1079             }
1080         }
1081
1082         /* the reply token hasn't been sent yet, but that's ok. */
1083         if (ctx->gss_flags & GSS_C_DCE_STYLE) {
1084             assert(ctx->have_acceptor_subkey);
1085
1086             /* in order to force acceptor subkey to be used, don't set PROT_READY */
1087
1088             /* Raw AP-REP is returned */
1089             code = data_to_gss(&ap_rep, output_token);
1090             if (code)
1091             {
1092                 major_status = GSS_S_FAILURE;
1093                 goto fail;
1094             }
1095
1096             ctx->established = 0;
1097
1098             *context_handle = (gss_ctx_id_t)ctx;
1099             *minor_status = 0;
1100             major_status = GSS_S_CONTINUE_NEEDED;
1101
1102             /* Only last leg should set return arguments */
1103             goto fail;
1104         } else
1105             ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1106
1107         ctx->established = 1;
1108
1109         token.length = g_token_size(mech_used, ap_rep.length);
1110
1111         if ((token.value = (unsigned char *) gssalloc_malloc(token.length))
1112             == NULL) {
1113             major_status = GSS_S_FAILURE;
1114             code = ENOMEM;
1115             goto fail;
1116         }
1117         ptr3 = token.value;
1118         g_make_token_header(mech_used, ap_rep.length,
1119                             &ptr3, KG_TOK_CTX_AP_REP);
1120
1121         TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1122
1123         ctx->established = 1;
1124
1125     } else {
1126         token.length = 0;
1127         token.value = NULL;
1128         ctx->seq_send = ctx->seq_recv;
1129
1130         ctx->established = 1;
1131     }
1132
1133     /* set the return arguments */
1134
1135     if (src_name) {
1136         code = kg_duplicate_name(context, ctx->there, &name);
1137         if (code) {
1138             major_status = GSS_S_FAILURE;
1139             goto fail;
1140         }
1141     }
1142
1143     if (mech_type)
1144         *mech_type = (gss_OID) mech_used;
1145
1146     /* Add the maximum allowable clock skew as a grace period for context
1147      * expiration, just as we do for the ticket. */
1148     if (time_rec)
1149         *time_rec = ctx->krb_times.endtime + context->clockskew - now;
1150
1151     if (ret_flags)
1152         *ret_flags = ctx->gss_flags;
1153
1154     *context_handle = (gss_ctx_id_t)ctx;
1155     *output_token = token;
1156
1157     if (src_name)
1158         *src_name = (gss_name_t) name;
1159
1160     if (delegated_cred_handle)
1161         *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1162
1163     /* finally! */
1164
1165     *minor_status = 0;
1166     major_status = GSS_S_COMPLETE;
1167
1168 fail:
1169     if (authdat)
1170         krb5_free_authenticator(context, authdat);
1171     /* The ctx structure has the handle of the auth_context */
1172     if (auth_context && !ctx) {
1173         if (cred_rcache)
1174             (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1175
1176         krb5_auth_con_free(context, auth_context);
1177     }
1178     if (reqcksum.contents)
1179         xfree(reqcksum.contents);
1180     if (ap_rep.data)
1181         krb5_free_data_contents(context, &ap_rep);
1182     if (major_status == GSS_S_COMPLETE ||
1183         (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
1184         ctx->k5_context = context;
1185         context = NULL;
1186         goto done;
1187     }
1188
1189     /* from here on is the real "fail" code */
1190
1191     if (ctx)
1192         (void) krb5_gss_delete_sec_context(&tmp_minor_status,
1193                                            (gss_ctx_id_t *) &ctx, NULL);
1194     if (deleg_cred) { /* free memory associated with the deleg credential */
1195         if (deleg_cred->ccache)
1196             (void)krb5_cc_close(context, deleg_cred->ccache);
1197         if (deleg_cred->name)
1198             kg_release_name(context, &deleg_cred->name);
1199         xfree(deleg_cred);
1200     }
1201     if (token.value)
1202         xfree(token.value);
1203     if (name) {
1204         (void) kg_release_name(context, &name);
1205     }
1206
1207     *minor_status = code;
1208
1209     /* We may have failed before being able to read the GSS flags from the
1210      * authenticator, so also check the request AP options. */
1211     if (cred != NULL && request != NULL &&
1212         ((gss_flags & GSS_C_MUTUAL_FLAG) ||
1213          (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
1214          major_status == GSS_S_CONTINUE_NEEDED)) {
1215         unsigned int tmsglen;
1216         int toktype;
1217
1218         /*
1219          * The client is expecting a response, so we can send an
1220          * error token back
1221          */
1222         memset(&krb_error_data, 0, sizeof(krb_error_data));
1223
1224         code -= ERROR_TABLE_BASE_krb5;
1225         if (code < 0 || code > KRB_ERR_MAX)
1226             code = 60 /* KRB_ERR_GENERIC */;
1227
1228         krb_error_data.error = code;
1229         (void) krb5_us_timeofday(context, &krb_error_data.stime,
1230                                  &krb_error_data.susec);
1231
1232         krb_error_data.server = ticket->server;
1233         code = krb5_mk_error(context, &krb_error_data, &scratch);
1234         if (code)
1235             goto done;
1236
1237         tmsglen = scratch.length;
1238         toktype = KG_TOK_CTX_ERROR;
1239
1240         token.length = g_token_size(mech_used, tmsglen);
1241         token.value = gssalloc_malloc(token.length);
1242         if (!token.value)
1243             goto done;
1244
1245         ptr = token.value;
1246         g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1247
1248         TWRITE_STR(ptr, scratch.data, scratch.length);
1249         krb5_free_data_contents(context, &scratch);
1250
1251         *output_token = token;
1252     }
1253
1254 done:
1255     krb5_free_ap_req(context, request);
1256     if (cred)
1257         k5_mutex_unlock(&cred->lock);
1258     if (defcred)
1259         krb5_gss_release_cred(&tmp_minor_status, &defcred);
1260     if (context) {
1261         if (major_status && *minor_status)
1262             save_error_info(*minor_status, context);
1263         krb5_free_context(context);
1264     }
1265     return (major_status);
1266 }
1267 #endif /* LEAN_CLIENT */
1268
1269 OM_uint32 KRB5_CALLCONV
1270 krb5_gss_accept_sec_context_ext(
1271     OM_uint32 *minor_status,
1272     gss_ctx_id_t *context_handle,
1273     gss_cred_id_t verifier_cred_handle,
1274     gss_buffer_t input_token,
1275     gss_channel_bindings_t input_chan_bindings,
1276     gss_name_t *src_name,
1277     gss_OID *mech_type,
1278     gss_buffer_t output_token,
1279     OM_uint32 *ret_flags,
1280     OM_uint32 *time_rec,
1281     gss_cred_id_t *delegated_cred_handle,
1282     krb5_gss_ctx_ext_t exts)
1283 {
1284     krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
1285
1286     /*
1287      * Context handle must be unspecified.  Actually, it must be
1288      * non-established, but currently, accept_sec_context never returns
1289      * a non-established context handle.
1290      */
1291     /*SUPPRESS 29*/
1292     if (ctx != NULL) {
1293         if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
1294             return kg_accept_dce(minor_status, context_handle,
1295                                  verifier_cred_handle, input_token,
1296                                  input_chan_bindings, src_name, mech_type,
1297                                  output_token, ret_flags, time_rec,
1298                                  delegated_cred_handle);
1299         } else {
1300             *minor_status = EINVAL;
1301             save_error_string(EINVAL, "accept_sec_context called with existing context handle");
1302             return GSS_S_FAILURE;
1303         }
1304     }
1305
1306     return kg_accept_krb5(minor_status, context_handle,
1307                           verifier_cred_handle, input_token,
1308                           input_chan_bindings, src_name, mech_type,
1309                           output_token, ret_flags, time_rec,
1310                           delegated_cred_handle, exts);
1311 }
1312
1313 OM_uint32 KRB5_CALLCONV
1314 krb5_gss_accept_sec_context(minor_status, context_handle,
1315                             verifier_cred_handle, input_token,
1316                             input_chan_bindings, src_name, mech_type,
1317                             output_token, ret_flags, time_rec,
1318                             delegated_cred_handle)
1319     OM_uint32 *minor_status;
1320     gss_ctx_id_t *context_handle;
1321     gss_cred_id_t verifier_cred_handle;
1322     gss_buffer_t input_token;
1323     gss_channel_bindings_t input_chan_bindings;
1324     gss_name_t *src_name;
1325     gss_OID *mech_type;
1326     gss_buffer_t output_token;
1327     OM_uint32 *ret_flags;
1328     OM_uint32 *time_rec;
1329     gss_cred_id_t *delegated_cred_handle;
1330 {
1331     krb5_gss_ctx_ext_rec exts;
1332
1333     memset(&exts, 0, sizeof(exts));
1334
1335     return krb5_gss_accept_sec_context_ext(minor_status,
1336                                            context_handle,
1337                                            verifier_cred_handle,
1338                                            input_token,
1339                                            input_chan_bindings,
1340                                            src_name,
1341                                            mech_type,
1342                                            output_token,
1343                                            ret_flags,
1344                                            time_rec,
1345                                            delegated_cred_handle,
1346                                            &exts);
1347 }