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