xref: /freebsd/crypto/krb5/src/lib/gssapi/krb5/accept_sec_context.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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 "k5-input.h"
102 #include "gssapiP_krb5.h"
103 #ifdef HAVE_MEMORY_H
104 #include <memory.h>
105 #endif
106 #include <assert.h>
107 
108 #ifdef CFX_EXERCISE
109 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
110 #else
111 #define CFX_ACCEPTOR_SUBKEY 1
112 #endif
113 
114 #ifndef LEAN_CLIENT
115 
116 static OM_uint32
create_constrained_deleg_creds(OM_uint32 * minor_status,krb5_gss_cred_id_t verifier_cred_handle,krb5_ticket * ticket,krb5_gss_cred_id_t * out_cred,krb5_context context)117 create_constrained_deleg_creds(OM_uint32 *minor_status,
118                                krb5_gss_cred_id_t verifier_cred_handle,
119                                krb5_ticket *ticket,
120                                krb5_gss_cred_id_t *out_cred,
121                                krb5_context context)
122 {
123     OM_uint32 major_status;
124     krb5_creds krb_creds;
125     krb5_data *data;
126     krb5_error_code code;
127 
128     assert(out_cred != NULL);
129     assert(verifier_cred_handle->usage == GSS_C_BOTH);
130 
131     memset(&krb_creds, 0, sizeof(krb_creds));
132     krb_creds.client = ticket->enc_part2->client;
133     krb_creds.server = ticket->server;
134     krb_creds.keyblock = *(ticket->enc_part2->session);
135     krb_creds.ticket_flags = ticket->enc_part2->flags;
136     krb_creds.times = ticket->enc_part2->times;
137     krb_creds.magic = KV5M_CREDS;
138     krb_creds.authdata = NULL;
139 
140     code = encode_krb5_ticket(ticket, &data);
141     if (code) {
142         *minor_status = code;
143         return GSS_S_FAILURE;
144     }
145 
146     krb_creds.ticket = *data;
147 
148     major_status = kg_compose_deleg_cred(minor_status,
149                                          verifier_cred_handle,
150                                          &krb_creds,
151                                          GSS_C_INDEFINITE,
152                                          out_cred,
153                                          NULL,
154                                          context);
155 
156     krb5_free_data(context, data);
157 
158     return major_status;
159 }
160 
161 /* Decode, decrypt and store the forwarded creds in the local ccache. */
162 static krb5_error_code
rd_and_store_for_creds(context,auth_context,inbuf,out_cred)163 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
164     krb5_context context;
165     krb5_auth_context auth_context;
166     krb5_data *inbuf;
167     krb5_gss_cred_id_t *out_cred;
168 {
169     krb5_creds ** creds = NULL;
170     krb5_error_code retval;
171     krb5_ccache ccache = NULL;
172     krb5_gss_cred_id_t cred = NULL;
173     krb5_auth_context new_auth_ctx = NULL;
174     krb5_int32 flags_org;
175 
176     if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
177         return retval;
178     krb5_auth_con_setflags(context, auth_context,
179                            0);
180 
181     /*
182      * By the time krb5_rd_cred is called here (after krb5_rd_req has been
183      * called in krb5_gss_accept_sec_context), the "keyblock" field of
184      * auth_context contains a pointer to the session key, and the
185      * "recv_subkey" field might contain a session subkey.  Either of
186      * these (the "recv_subkey" if it isn't NULL, otherwise the
187      * "keyblock") might have been used to encrypt the encrypted part of
188      * the KRB_CRED message that contains the forwarded credentials.  (The
189      * Java Crypto and Security Implementation from the DSTC in Australia
190      * always uses the session key.  But apparently it never negotiates a
191      * subkey, so this code works fine against a JCSI client.)  Up to the
192      * present, though, GSSAPI clients linked against the MIT code (which
193      * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
194      * all -- at this level.  So if the first call to krb5_rd_cred fails,
195      * we should call it a second time with another auth context freshly
196      * created by krb5_auth_con_init.  All of its keyblock fields will be
197      * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
198      * unencrypted.  (The MIT code doesn't actually send the KRB_CRED
199      * message in the clear -- the "authenticator" whose "checksum" ends up
200      * containing the KRB_CRED message does get encrypted.)
201      */
202     if (krb5_rd_cred(context, auth_context, inbuf, &creds, NULL)) {
203         if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
204             goto cleanup;
205         krb5_auth_con_setflags(context, new_auth_ctx, 0);
206         if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
207                                    &creds, NULL)))
208             goto cleanup;
209     }
210 
211     if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
212         ccache = NULL;
213         goto cleanup;
214     }
215 
216     if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
217         goto cleanup;
218 
219     if ((retval = k5_cc_store_primary_cred(context, ccache, creds[0])))
220         goto cleanup;
221 
222     /* generate a delegated credential handle */
223     if (out_cred) {
224         /* allocate memory for a cred_t... */
225         if (!(cred =
226               (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
227             retval = ENOMEM; /* out of memory? */
228             goto cleanup;
229         }
230 
231         /* zero it out... */
232         memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
233 
234         retval = k5_mutex_init(&cred->lock);
235         if (retval) {
236             xfree(cred);
237             cred = NULL;
238             goto cleanup;
239         }
240 
241         /* copy the client principle into it... */
242         if ((retval =
243              kg_init_name(context, creds[0]->client, NULL, NULL, NULL, 0,
244                           &cred->name))) {
245             k5_mutex_destroy(&cred->lock);
246             retval = ENOMEM; /* out of memory? */
247             xfree(cred); /* clean up memory on failure */
248             cred = NULL;
249             goto cleanup;
250         }
251 
252         cred->usage = GSS_C_INITIATE; /* we can't accept with this */
253         /* cred->name already set */
254         cred->keytab = NULL; /* no keytab associated with this... */
255         cred->expire = creds[0]->times.endtime; /* store the end time */
256         cred->ccache = ccache; /* the ccache containing the credential */
257         cred->destroy_ccache = 1;
258         ccache = NULL; /* cred takes ownership so don't destroy */
259     }
260 
261     /* If there were errors, there might have been a memory leak
262        if (!cred)
263        if ((retval = krb5_cc_close(context, ccache)))
264        goto cleanup;
265     */
266 cleanup:
267     if (creds)
268         krb5_free_tgt_creds(context, creds);
269 
270     if (ccache)
271         (void)krb5_cc_destroy(context, ccache);
272 
273     if (out_cred)
274         *out_cred = cred; /* return credential */
275 
276     if (new_auth_ctx)
277         krb5_auth_con_free(context, new_auth_ctx);
278 
279     krb5_auth_con_setflags(context, auth_context, flags_org);
280 
281     return retval;
282 }
283 
284 
285 /*
286  * Performs third leg of DCE authentication
287  */
288 static OM_uint32
kg_accept_dce(minor_status,context_handle,verifier_cred_handle,input_token,input_chan_bindings,src_name,mech_type,output_token,ret_flags,time_rec,delegated_cred_handle)289 kg_accept_dce(minor_status, context_handle, verifier_cred_handle,
290               input_token, input_chan_bindings, src_name, mech_type,
291               output_token, ret_flags, time_rec, delegated_cred_handle)
292     OM_uint32 *minor_status;
293     gss_ctx_id_t *context_handle;
294     gss_cred_id_t verifier_cred_handle;
295     gss_buffer_t input_token;
296     gss_channel_bindings_t input_chan_bindings;
297     gss_name_t *src_name;
298     gss_OID *mech_type;
299     gss_buffer_t output_token;
300     OM_uint32 *ret_flags;
301     OM_uint32 *time_rec;
302     gss_cred_id_t *delegated_cred_handle;
303 {
304     krb5_error_code code;
305     krb5_gss_ctx_id_rec *ctx = 0;
306     krb5_timestamp now;
307     krb5_gss_name_t name = NULL;
308     krb5_ui_4 nonce = 0;
309     krb5_data ap_rep;
310     OM_uint32 major_status = GSS_S_FAILURE;
311 
312     output_token->length = 0;
313     output_token->value = NULL;
314 
315     if (mech_type)
316         *mech_type = GSS_C_NULL_OID;
317     /* return a bogus cred handle */
318     if (delegated_cred_handle)
319         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
320 
321     ctx = (krb5_gss_ctx_id_rec *)*context_handle;
322 
323     code = krb5_timeofday(ctx->k5_context, &now);
324     if (code != 0) {
325         major_status = GSS_S_FAILURE;
326         goto fail;
327     }
328 
329     ap_rep.data = input_token->value;
330     ap_rep.length = input_token->length;
331 
332     code = krb5_rd_rep_dce(ctx->k5_context,
333                            ctx->auth_context,
334                            &ap_rep,
335                            &nonce);
336     if (code != 0) {
337         major_status = GSS_S_FAILURE;
338         goto fail;
339     }
340 
341     ctx->established = 1;
342 
343     if (src_name) {
344         code = kg_duplicate_name(ctx->k5_context, ctx->there, &name);
345         if (code) {
346             major_status = GSS_S_FAILURE;
347             goto fail;
348         }
349         *src_name = (gss_name_t) name;
350     }
351 
352     if (mech_type)
353         *mech_type = ctx->mech_used;
354 
355     if (time_rec) {
356         *time_rec = ts_interval(ts_incr(now, -ctx->k5_context->clockskew),
357                                 ctx->krb_times.endtime);
358     }
359 
360     /* Never return GSS_C_DELEG_FLAG since we don't support DCE credential
361      * delegation yet. */
362     if (ret_flags)
363         *ret_flags = (ctx->gss_flags & ~GSS_C_DELEG_FLAG);
364 
365     *minor_status = 0;
366 
367     return GSS_S_COMPLETE;
368 
369 fail:
370     /* real failure code follows */
371 
372     (void) krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx,
373                                        NULL);
374     *context_handle = GSS_C_NO_CONTEXT;
375     *minor_status = code;
376 
377     return major_status;
378 }
379 
380 static krb5_error_code
kg_process_extension(krb5_context context,krb5_auth_context auth_context,int ext_type,krb5_data * ext_data,krb5_gss_ctx_ext_t exts)381 kg_process_extension(krb5_context context,
382                      krb5_auth_context auth_context,
383                      int ext_type,
384                      krb5_data *ext_data,
385                      krb5_gss_ctx_ext_t exts)
386 {
387     krb5_error_code code = 0;
388 
389     assert(exts != NULL);
390 
391     switch (ext_type) {
392     case KRB5_GSS_EXTS_IAKERB_FINISHED:
393         if (exts->iakerb.conv == NULL) {
394             code = KRB5KRB_AP_ERR_MSG_TYPE; /* XXX */
395         } else {
396             krb5_key key;
397 
398             code = krb5_auth_con_getrecvsubkey_k(context, auth_context, &key);
399             if (code != 0)
400                 break;
401 
402             code = iakerb_verify_finished(context, key, exts->iakerb.conv,
403                                           ext_data);
404             if (code == 0)
405                 exts->iakerb.verified = 1;
406 
407             krb5_k_free_key(context, key);
408         }
409         break;
410     default:
411         break;
412     }
413 
414     return code;
415 }
416 
417 /* The length of the MD5 channel bindings in an 0x8003 checksum */
418 #define CB_MD5_LEN 16
419 
420 /* The minimum length of an 0x8003 checksum value (4-byte channel bindings
421  * length, 16-byte channel bindings, 4-byte flags) */
422 #define MIN_8003_LEN (4 + CB_MD5_LEN + 4)
423 
424 /* The flags we accept from the initiator's authenticator checksum. */
425 #define INITIATOR_FLAGS (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |           \
426                          GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |        \
427                          GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE |        \
428                          GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
429 
430 /* A zero-value channel binding, for comparison */
431 static const uint8_t null_cb[CB_MD5_LEN];
432 
433 /* Look for AP_OPTIONS in authdata.  If present and the options include
434  * KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
435 static krb5_error_code
check_cbt(krb5_context context,krb5_authdata * const * authdata,krb5_boolean * cbt_out)436 check_cbt(krb5_context context, krb5_authdata *const *authdata,
437           krb5_boolean *cbt_out)
438 {
439     krb5_error_code code;
440     krb5_authdata **ad;
441     uint32_t ad_ap_options;
442     const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
443 
444     *cbt_out = FALSE;
445 
446     code = krb5_find_authdata(context, NULL, authdata,
447                               KRB5_AUTHDATA_AP_OPTIONS, &ad);
448     if (code || ad == NULL)
449         return code;
450     if (ad[1] != NULL || ad[0]->length != 4) {
451         code = KRB5KRB_AP_ERR_MSG_TYPE;
452     } else {
453         ad_ap_options = load_32_le(ad[0]->contents);
454         if (ad_ap_options & KERB_AP_OPTIONS_CBT)
455             *cbt_out = TRUE;
456     }
457 
458     krb5_free_authdata(context, ad);
459     return code;
460 }
461 
462 /*
463  * The krb5 GSS mech appropriates the authenticator checksum field from RFC
464  * 4120 to store structured data instead of a checksum, indicated with checksum
465  * type 0x8003 (see RFC 4121 section 4.1.1).  Some implementations instead send
466  * no checksum, or a regular checksum over empty data.
467  *
468  * Interpret the checksum.  Read delegated creds into *deleg_out if it is not
469  * NULL.  Set *flags_out to the allowed subset of token flags, plus
470  * GSS_C_DELEG_FLAG if a delegated credential was present and
471  * GSS_C_CHANNEL_BOUND_FLAG if matching channel bindings are present.  Process
472  * any extensions found using exts.  On error, set *code_out to a krb5_error
473  * code for use as a minor status value.
474  */
475 static OM_uint32
process_checksum(OM_uint32 * minor_status,krb5_context context,gss_channel_bindings_t acceptor_cb,krb5_auth_context auth_context,krb5_flags ap_req_options,krb5_authenticator * authenticator,krb5_gss_ctx_ext_t exts,krb5_gss_cred_id_t * deleg_out,krb5_ui_4 * flags_out,krb5_error_code * code_out)476 process_checksum(OM_uint32 *minor_status, krb5_context context,
477                  gss_channel_bindings_t acceptor_cb,
478                  krb5_auth_context auth_context, krb5_flags ap_req_options,
479                  krb5_authenticator *authenticator, krb5_gss_ctx_ext_t exts,
480                  krb5_gss_cred_id_t *deleg_out, krb5_ui_4 *flags_out,
481                  krb5_error_code *code_out)
482 {
483     krb5_error_code code = 0;
484     OM_uint32 status, option_id, token_flags;
485     size_t cb_len, option_len;
486     krb5_boolean valid, client_cbt, token_cb_present = FALSE, cb_match = FALSE;
487     krb5_key subkey;
488     krb5_data option, empty = empty_data();
489     krb5_checksum cb_cksum;
490     const uint8_t *token_cb, *option_bytes;
491     struct k5input in;
492     const krb5_checksum *cksum = authenticator->checksum;
493 
494     cb_cksum.contents = NULL;
495 
496     if (cksum == NULL) {
497         /*
498          * Some SMB client implementations use handcrafted GSSAPI code that
499          * does not provide a checksum.  MS-KILE documents that the Microsoft
500          * implementation considers a missing checksum acceptable; the server
501          * assumes all flags are unset in this case, and does not check channel
502          * bindings.
503          */
504         *flags_out = 0;
505     } else if (cksum->checksum_type != CKSUMTYPE_KG_CB) {
506         /* Samba sends a regular checksum. */
507         code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
508         if (code) {
509             status = GSS_S_FAILURE;
510             goto fail;
511         }
512 
513         /* Verifying the checksum ensures that this authenticator wasn't
514          * replayed from one with a checksum over actual data. */
515         code = krb5_k_verify_checksum(context, subkey,
516                                       KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, &empty,
517                                       cksum, &valid);
518         krb5_k_free_key(context, subkey);
519         if (code || !valid) {
520             status = GSS_S_BAD_SIG;
521             goto fail;
522         }
523 
524         /* Use ap_options from the request to guess the mutual flag. */
525         *flags_out = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
526         if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
527             *flags_out |= GSS_C_MUTUAL_FLAG;
528     } else {
529         /* The checksum must contain at least a fixed 24-byte part. */
530         if (cksum->length < MIN_8003_LEN) {
531             status = GSS_S_BAD_BINDINGS;
532             goto fail;
533         }
534 
535         k5_input_init(&in, cksum->contents, cksum->length);
536         cb_len = k5_input_get_uint32_le(&in);
537         if (cb_len != CB_MD5_LEN) {
538             code = KG_BAD_LENGTH;
539             status = GSS_S_FAILURE;
540             goto fail;
541         }
542 
543         token_cb = k5_input_get_bytes(&in, cb_len);
544         if (acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS) {
545             code = kg_checksum_channel_bindings(context, acceptor_cb,
546                                                 &cb_cksum);
547             if (code) {
548                 status = GSS_S_BAD_BINDINGS;
549                 goto fail;
550             }
551             assert(cb_cksum.length == cb_len);
552             token_cb_present = (k5_bcmp(token_cb, null_cb, cb_len) != 0);
553             cb_match = (k5_bcmp(token_cb, cb_cksum.contents, cb_len) == 0);
554             if (token_cb_present && !cb_match) {
555                 status = GSS_S_BAD_BINDINGS;
556                 goto fail;
557             }
558         }
559 
560         /* Read the token flags and accept some of them as context flags. */
561         token_flags = k5_input_get_uint32_le(&in);
562         *flags_out = token_flags & INITIATOR_FLAGS;
563         if (cb_match)
564             *flags_out |= GSS_C_CHANNEL_BOUND_FLAG;
565 
566         /* Read the delegated credential if present. */
567         if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {
568             option_id = k5_input_get_uint16_le(&in);
569             option_len = k5_input_get_uint16_le(&in);
570             option_bytes = k5_input_get_bytes(&in, option_len);
571             option = make_data((uint8_t *)option_bytes, option_len);
572             if (in.status) {
573                 code = KG_BAD_LENGTH;
574                 status = GSS_S_FAILURE;
575                 goto fail;
576             }
577             if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
578                 status = GSS_S_FAILURE;
579                 goto fail;
580             }
581 
582             /* Store the delegated credential. */
583             code = rd_and_store_for_creds(context, auth_context, &option,
584                                           deleg_out);
585             if (code) {
586                 status = GSS_S_FAILURE;
587                 goto fail;
588             }
589             *flags_out |= GSS_C_DELEG_FLAG;
590         }
591 
592         /* Process any extensions at the end of the checksum.  Extensions use
593          * 4-byte big-endian tag and length instead of 2-byte little-endian. */
594         while (in.len > 0) {
595             option_id = k5_input_get_uint32_be(&in);
596             option_len = k5_input_get_uint32_be(&in);
597             option_bytes = k5_input_get_bytes(&in, option_len);
598             option = make_data((uint8_t *)option_bytes, option_len);
599             if (in.status) {
600                 code = KG_BAD_LENGTH;
601                 status = GSS_S_FAILURE;
602                 goto fail;
603             }
604 
605             code = kg_process_extension(context, auth_context, option_id,
606                                         &option, exts);
607             if (code) {
608                 status = GSS_S_FAILURE;
609                 goto fail;
610             }
611         }
612     }
613 
614     /*
615      * If the client asserts the KERB_AP_OPTIONS_CBT flag (from MS-KILE) in the
616      * authenticator authdata, and the acceptor passed channel bindings,
617      * require matching channel bindings from the client.  The intent is to
618      * prevent an authenticator generated for use outside of a TLS channel from
619      * being used inside of one.
620      */
621     code = check_cbt(context, authenticator->authorization_data, &client_cbt);
622     if (code) {
623         status = GSS_S_FAILURE;
624         goto fail;
625     }
626     if (client_cbt && acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS && !cb_match) {
627         status = GSS_S_BAD_BINDINGS;
628         goto fail;
629     }
630 
631     status = GSS_S_COMPLETE;
632 
633 fail:
634     free(cb_cksum.contents);
635     *code_out = code;
636     return status;
637 }
638 
639 static OM_uint32
kg_accept_krb5(minor_status,context_handle,verifier_cred_handle,input_token,input_chan_bindings,src_name,mech_type,output_token,ret_flags,time_rec,delegated_cred_handle,exts)640 kg_accept_krb5(minor_status, context_handle,
641                verifier_cred_handle, input_token,
642                input_chan_bindings, src_name, mech_type,
643                output_token, ret_flags, time_rec,
644                delegated_cred_handle, exts)
645     OM_uint32 *minor_status;
646     gss_ctx_id_t *context_handle;
647     gss_cred_id_t verifier_cred_handle;
648     gss_buffer_t input_token;
649     gss_channel_bindings_t input_chan_bindings;
650     gss_name_t *src_name;
651     gss_OID *mech_type;
652     gss_buffer_t output_token;
653     OM_uint32 *ret_flags;
654     OM_uint32 *time_rec;
655     gss_cred_id_t *delegated_cred_handle;
656     krb5_gss_ctx_ext_t exts;
657 {
658     krb5_context context;
659     unsigned char *ptr;
660     krb5_gss_cred_id_t cred = 0;
661     krb5_data ap_rep, ap_req;
662     krb5_error_code code;
663     krb5_address addr, *paddr;
664     krb5_authenticator *authdat = 0;
665     krb5_gss_name_t name = NULL;
666     krb5_ui_4 gss_flags = 0;
667     krb5_gss_ctx_id_rec *ctx = NULL;
668     krb5_timestamp now;
669     gss_buffer_desc token;
670     krb5_auth_context auth_context = NULL;
671     krb5_ticket * ticket = NULL;
672     const gss_OID_desc *mech_used = NULL;
673     OM_uint32 major_status;
674     OM_uint32 tmp_minor_status;
675     krb5_error krb_error_data;
676     krb5_data scratch;
677     gss_cred_id_t defcred = GSS_C_NO_CREDENTIAL;
678     krb5_gss_cred_id_t deleg_cred = NULL;
679     krb5int_access kaccess;
680     int cred_rcache = 0;
681     int no_encap = 0;
682     krb5_flags ap_req_options = 0;
683     krb5_enctype negotiated_etype;
684     krb5_authdata_context ad_context = NULL;
685     krb5_ap_req *request = NULL;
686     struct k5buf buf;
687 
688     code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
689     if (code) {
690         *minor_status = code;
691         return(GSS_S_FAILURE);
692     }
693 
694     code = krb5_gss_init_context(&context);
695     if (code) {
696         *minor_status = code;
697         return GSS_S_FAILURE;
698     }
699 
700     /* set up returns to be freeable */
701 
702     if (src_name)
703         *src_name = (gss_name_t) NULL;
704     output_token->length = 0;
705     output_token->value = NULL;
706     token.value = 0;
707     ap_req.data = 0;
708     ap_rep.data = 0;
709 
710     if (mech_type)
711         *mech_type = GSS_C_NULL_OID;
712     /* return a bogus cred handle */
713     if (delegated_cred_handle)
714         *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
715 
716     /* handle default cred handle */
717     if (verifier_cred_handle == GSS_C_NO_CREDENTIAL) {
718         major_status = krb5_gss_acquire_cred(minor_status, GSS_C_NO_NAME,
719                                              GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
720                                              GSS_C_ACCEPT, &defcred,
721                                              NULL, NULL);
722         if (major_status != GSS_S_COMPLETE) {
723             code = *minor_status;
724             goto fail;
725         }
726         verifier_cred_handle = defcred;
727     }
728 
729     /* Resolve any initiator state in the verifier cred and lock it. */
730     major_status = kg_cred_resolve(minor_status, context, verifier_cred_handle,
731                                    GSS_C_NO_NAME);
732     if (GSS_ERROR(major_status)) {
733         code = *minor_status;
734         goto fail;
735     }
736     cred = (krb5_gss_cred_id_t)verifier_cred_handle;
737 
738     /* make sure the supplied credentials are valid for accept */
739 
740     if ((cred->usage != GSS_C_ACCEPT) &&
741         (cred->usage != GSS_C_BOTH)) {
742         code = 0;
743         major_status = GSS_S_NO_CRED;
744         goto fail;
745     }
746 
747     /* verify the token's integrity, and leave the token in ap_req.
748        figure out which mech oid was used, and save it */
749 
750     ptr = (unsigned char *) input_token->value;
751 
752     if (!(code = g_verify_token_header(gss_mech_krb5,
753                                        &(ap_req.length),
754                                        &ptr, KG_TOK_CTX_AP_REQ,
755                                        input_token->length, 1))) {
756         mech_used = gss_mech_krb5;
757     } else if ((code == G_WRONG_MECH)
758                &&!(code = g_verify_token_header((gss_OID) gss_mech_iakerb,
759                                                 &(ap_req.length),
760                                                 &ptr, KG_TOK_CTX_AP_REQ,
761                                                 input_token->length, 1))) {
762         mech_used = gss_mech_iakerb;
763     } else if ((code == G_WRONG_MECH)
764                &&!(code = g_verify_token_header((gss_OID) gss_mech_krb5_wrong,
765                                                 &(ap_req.length),
766                                                 &ptr, KG_TOK_CTX_AP_REQ,
767                                                 input_token->length, 1))) {
768         mech_used = gss_mech_krb5_wrong;
769     } else if ((code == G_WRONG_MECH) &&
770                !(code = g_verify_token_header(gss_mech_krb5_old,
771                                               &(ap_req.length),
772                                               &ptr, KG_TOK_CTX_AP_REQ,
773                                               input_token->length, 1))) {
774         /*
775          * Previous versions of this library used the old mech_id
776          * and some broken behavior (wrong IV on checksum
777          * encryption).  We support the old mech_id for
778          * compatibility, and use it to decide when to use the
779          * old behavior.
780          */
781         mech_used = gss_mech_krb5_old;
782     } else if (code == G_WRONG_TOKID) {
783         major_status = GSS_S_CONTINUE_NEEDED;
784         code = KRB5KRB_AP_ERR_MSG_TYPE;
785         mech_used = gss_mech_krb5;
786         goto fail;
787     } else if (code == G_BAD_TOK_HEADER) {
788         /* DCE style not encapsulated */
789         ap_req.length = input_token->length;
790         mech_used = gss_mech_krb5;
791         no_encap = 1;
792     } else {
793         major_status = GSS_S_DEFECTIVE_TOKEN;
794         goto fail;
795     }
796     ap_req.data = (char *)ptr;
797 
798     /* construct the sender_addr */
799 
800     if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
801         (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
802         /* XXX is this right? */
803         addr.addrtype = ADDRTYPE_INET;
804         addr.length = input_chan_bindings->initiator_address.length;
805         addr.contents = input_chan_bindings->initiator_address.value;
806 
807         paddr = &addr;
808     } else {
809         paddr = NULL;
810     }
811 
812     /* decode the AP_REQ message */
813     code = decode_krb5_ap_req(&ap_req, &request);
814     if (code) {
815         major_status = GSS_S_FAILURE;
816         goto done;
817     }
818     ticket = request->ticket;
819 
820     /* decode the message */
821 
822     if ((code = krb5_auth_con_init(context, &auth_context))) {
823         major_status = GSS_S_FAILURE;
824         save_error_info((OM_uint32)code, context);
825         goto fail;
826     }
827     if (cred->rcache) {
828         cred_rcache = 1;
829         if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
830             major_status = GSS_S_FAILURE;
831             goto fail;
832         }
833     }
834     if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
835         major_status = GSS_S_FAILURE;
836         goto fail;
837     }
838 
839     /* Limit the encryption types negotiated (if requested). */
840     if (cred->req_enctypes) {
841         if ((code = krb5_auth_con_setpermetypes(context, auth_context,
842                                                 cred->req_enctypes))) {
843             major_status = GSS_S_FAILURE;
844             goto fail;
845         }
846     }
847 
848     code = krb5_rd_req_decoded(context, &auth_context, request,
849                                cred->acceptor_mprinc, cred->keytab,
850                                &ap_req_options, NULL);
851     if (code) {
852         major_status = GSS_S_FAILURE;
853         goto fail;
854     }
855     krb5_auth_con_setflags(context, auth_context,
856                            KRB5_AUTH_CONTEXT_DO_SEQUENCE);
857 
858     krb5_auth_con_getauthenticator(context, auth_context, &authdat);
859 
860     major_status = process_checksum(minor_status, context, input_chan_bindings,
861                                     auth_context, ap_req_options,
862                                     authdat, exts,
863                                     delegated_cred_handle ? &deleg_cred : NULL,
864                                     &gss_flags, &code);
865 
866     if (major_status != GSS_S_COMPLETE)
867         goto fail;
868 
869     if (exts->iakerb.conv && !exts->iakerb.verified) {
870         major_status = GSS_S_BAD_SIG;
871         goto fail;
872     }
873 
874     /* only DCE_STYLE clients are allowed to send raw AP-REQs */
875     if (no_encap != ((gss_flags & GSS_C_DCE_STYLE) != 0)) {
876         major_status = GSS_S_DEFECTIVE_TOKEN;
877         goto fail;
878     }
879 
880     /* create the ctx struct and start filling it in */
881 
882     if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
883         == NULL) {
884         code = ENOMEM;
885         major_status = GSS_S_FAILURE;
886         goto fail;
887     }
888 
889     memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
890     ctx->magic = KG_CONTEXT;
891     ctx->mech_used = (gss_OID) mech_used;
892     ctx->auth_context = auth_context;
893     ctx->initiate = 0;
894     ctx->gss_flags = gss_flags | GSS_C_TRANS_FLAG;
895     ctx->seed_init = 0;
896     ctx->cred_rcache = cred_rcache;
897 
898     /* XXX move this into gss_name_t */
899     if (        (code = krb5_merge_authdata(context,
900                                             ticket->enc_part2->authorization_data,
901                                             authdat->authorization_data,
902                                             &ctx->authdata))) {
903         major_status = GSS_S_FAILURE;
904         goto fail;
905     }
906     if ((code = kg_init_name(context, ticket->server, NULL, NULL, NULL, 0,
907                              &ctx->here))) {
908         major_status = GSS_S_FAILURE;
909         goto fail;
910     }
911     if ((code = krb5_auth_con_get_authdata_context(context, auth_context,
912                                                    &ad_context))) {
913         major_status = GSS_S_FAILURE;
914         goto fail;
915     }
916     if ((code = kg_init_name(context, authdat->client, NULL, NULL,
917                              ad_context, KG_INIT_NAME_NO_COPY, &ctx->there))) {
918         major_status = GSS_S_FAILURE;
919         goto fail;
920     }
921     /* Now owned by ctx->there */
922     authdat->client = NULL;
923     krb5_auth_con_set_authdata_context(context, auth_context, NULL);
924 
925     if ((code = krb5_auth_con_getrecvsubkey_k(context, auth_context,
926                                               &ctx->subkey))) {
927         major_status = GSS_S_FAILURE;
928         goto fail;
929     }
930 
931     /* use the session key if the subkey isn't present */
932 
933     if (ctx->subkey == NULL) {
934         if ((code = krb5_auth_con_getkey_k(context, auth_context,
935                                            &ctx->subkey))) {
936             major_status = GSS_S_FAILURE;
937             goto fail;
938         }
939     }
940 
941     if (ctx->subkey == NULL) {
942         /* this isn't a very good error, but it's not clear to me this
943            can actually happen */
944         major_status = GSS_S_FAILURE;
945         code = KRB5KDC_ERR_NULL_KEY;
946         goto fail;
947     }
948 
949     ctx->enc = NULL;
950     ctx->seq = NULL;
951     ctx->have_acceptor_subkey = 0;
952     /* DCE_STYLE implies acceptor_subkey */
953     if ((ctx->gss_flags & GSS_C_DCE_STYLE) == 0) {
954         code = kg_setup_keys(context, ctx, ctx->subkey, &ctx->cksumtype);
955         if (code) {
956             major_status = GSS_S_FAILURE;
957             goto fail;
958         }
959     }
960     ctx->krb_times = ticket->enc_part2->times; /* struct copy */
961     ctx->krb_flags = ticket->enc_part2->flags;
962 
963     if (delegated_cred_handle != NULL &&
964         deleg_cred == NULL && /* no unconstrained delegation */
965         cred->usage == GSS_C_BOTH) {
966         /*
967          * Now, we always fabricate a delegated credentials handle
968          * containing the service ticket to ourselves, which can be
969          * used for S4U2Proxy.
970          */
971         major_status = create_constrained_deleg_creds(minor_status, cred,
972                                                       ticket, &deleg_cred,
973                                                       context);
974         if (GSS_ERROR(major_status))
975             goto fail;
976         ctx->gss_flags |= GSS_C_DELEG_FLAG;
977     }
978 
979     {
980         krb5_int32 seq_temp;
981         krb5_auth_con_getremoteseqnumber(context, auth_context, &seq_temp);
982         ctx->seq_recv = (uint32_t)seq_temp;
983     }
984 
985     if ((code = krb5_timeofday(context, &now))) {
986         major_status = GSS_S_FAILURE;
987         goto fail;
988     }
989 
990     code = g_seqstate_init(&ctx->seqstate, ctx->seq_recv,
991                            (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
992                            (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0,
993                            ctx->proto);
994     if (code) {
995         major_status = GSS_S_FAILURE;
996         goto fail;
997     }
998 
999     /* DCE_STYLE implies mutual authentication */
1000     if (ctx->gss_flags & GSS_C_DCE_STYLE)
1001         ctx->gss_flags |= GSS_C_MUTUAL_FLAG;
1002 
1003     /* at this point, the entire context structure is filled in,
1004        so it can be released.  */
1005 
1006     /* generate an AP_REP if necessary */
1007 
1008     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1009         krb5_int32 seq_temp;
1010         int cfx_generate_subkey;
1011 
1012         /*
1013          * Do not generate a subkey per RFC 4537 unless we are upgrading to CFX,
1014          * because pre-CFX tokens do not indicate which key to use. (Note that
1015          * DCE_STYLE implies that we will use a subkey.)
1016          */
1017         if (ctx->proto == 0 &&
1018             (ctx->gss_flags & GSS_C_DCE_STYLE) == 0 &&
1019             (ap_req_options & AP_OPTS_USE_SUBKEY)) {
1020             code = (*kaccess.auth_con_get_subkey_enctype)(context,
1021                                                           auth_context,
1022                                                           &negotiated_etype);
1023             if (code != 0) {
1024                 major_status = GSS_S_FAILURE;
1025                 goto fail;
1026             }
1027 
1028             switch (negotiated_etype) {
1029             case ENCTYPE_DES3_CBC_SHA1:
1030             case ENCTYPE_ARCFOUR_HMAC:
1031             case ENCTYPE_ARCFOUR_HMAC_EXP:
1032                 /* RFC 4121 accidentally omits RC4-HMAC-EXP as a "not-newer"
1033                  * enctype, even though RFC 4757 treats it as one. */
1034                 ap_req_options &= ~(AP_OPTS_USE_SUBKEY);
1035                 break;
1036             }
1037         }
1038 
1039         if (ctx->proto == 1 || (ctx->gss_flags & GSS_C_DCE_STYLE) ||
1040             (ap_req_options & AP_OPTS_USE_SUBKEY))
1041             cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1042         else
1043             cfx_generate_subkey = 0;
1044 
1045         if (cfx_generate_subkey) {
1046             krb5_int32 acflags;
1047             code = krb5_auth_con_getflags(context, auth_context, &acflags);
1048             if (code == 0) {
1049                 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1050                 code = krb5_auth_con_setflags(context, auth_context, acflags);
1051             }
1052             if (code) {
1053                 major_status = GSS_S_FAILURE;
1054                 goto fail;
1055             }
1056         }
1057 
1058         if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1059             major_status = GSS_S_FAILURE;
1060             goto fail;
1061         }
1062 
1063         krb5_auth_con_getlocalseqnumber(context, auth_context, &seq_temp);
1064         ctx->seq_send = (uint32_t)seq_temp;
1065 
1066         if (cfx_generate_subkey) {
1067             /* Get the new acceptor subkey.  With the code above, there
1068                should always be one if we make it to this point.  */
1069             code = krb5_auth_con_getsendsubkey_k(context, auth_context,
1070                                                  &ctx->acceptor_subkey);
1071             if (code != 0) {
1072                 major_status = GSS_S_FAILURE;
1073                 goto fail;
1074             }
1075             ctx->have_acceptor_subkey = 1;
1076 
1077             code = kg_setup_keys(context, ctx, ctx->acceptor_subkey,
1078                                  &ctx->acceptor_subkey_cksumtype);
1079             if (code) {
1080                 major_status = GSS_S_FAILURE;
1081                 goto fail;
1082             }
1083         }
1084 
1085         /* the reply token hasn't been sent yet, but that's ok. */
1086         if (ctx->gss_flags & GSS_C_DCE_STYLE) {
1087             assert(ctx->have_acceptor_subkey);
1088 
1089             /* in order to force acceptor subkey to be used, don't set PROT_READY */
1090 
1091             /* Raw AP-REP is returned */
1092             code = data_to_gss(&ap_rep, output_token);
1093             if (code)
1094             {
1095                 major_status = GSS_S_FAILURE;
1096                 goto fail;
1097             }
1098 
1099             ctx->established = 0;
1100 
1101             *context_handle = (gss_ctx_id_t)ctx;
1102             *minor_status = 0;
1103             major_status = GSS_S_CONTINUE_NEEDED;
1104 
1105             /* Only last leg should set return arguments */
1106             goto fail;
1107         } else
1108             ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1109 
1110         ctx->established = 1;
1111 
1112         token.length = g_token_size(mech_used, ap_rep.length);
1113         token.value = gssalloc_malloc(token.length);
1114         if (token.value == NULL) {
1115             major_status = GSS_S_FAILURE;
1116             code = ENOMEM;
1117             goto fail;
1118         }
1119         k5_buf_init_fixed(&buf, token.value, token.length);
1120         g_make_token_header(&buf, mech_used, ap_rep.length, KG_TOK_CTX_AP_REP);
1121         k5_buf_add_len(&buf, ap_rep.data, ap_rep.length);
1122         assert(buf.len == token.length);
1123 
1124         ctx->established = 1;
1125 
1126     } else {
1127         token.length = 0;
1128         token.value = NULL;
1129         ctx->seq_send = ctx->seq_recv;
1130 
1131         ctx->established = 1;
1132     }
1133 
1134     /* set the return arguments */
1135 
1136     if (src_name) {
1137         code = kg_duplicate_name(context, ctx->there, &name);
1138         if (code) {
1139             major_status = GSS_S_FAILURE;
1140             goto fail;
1141         }
1142     }
1143 
1144     if (mech_type)
1145         *mech_type = (gss_OID) mech_used;
1146 
1147     /* Add the maximum allowable clock skew as a grace period for context
1148      * expiration, just as we do for the ticket. */
1149     if (time_rec) {
1150         *time_rec = ts_interval(ts_incr(now, -context->clockskew),
1151                                 ctx->krb_times.endtime);
1152     }
1153 
1154     if (ret_flags)
1155         *ret_flags = ctx->gss_flags;
1156 
1157     *context_handle = (gss_ctx_id_t)ctx;
1158     *output_token = token;
1159 
1160     if (src_name)
1161         *src_name = (gss_name_t) name;
1162 
1163     if (delegated_cred_handle)
1164         *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1165 
1166     /* finally! */
1167 
1168     *minor_status = 0;
1169     major_status = GSS_S_COMPLETE;
1170 
1171 fail:
1172     if (authdat)
1173         krb5_free_authenticator(context, authdat);
1174     /* The ctx structure has the handle of the auth_context */
1175     if (auth_context && !ctx) {
1176         if (cred_rcache)
1177             (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1178 
1179         krb5_auth_con_free(context, auth_context);
1180     }
1181     if (ap_rep.data)
1182         krb5_free_data_contents(context, &ap_rep);
1183     if (major_status == GSS_S_COMPLETE ||
1184         (major_status == GSS_S_CONTINUE_NEEDED && code != KRB5KRB_AP_ERR_MSG_TYPE)) {
1185         ctx->k5_context = context;
1186         context = NULL;
1187         goto done;
1188     }
1189 
1190     /* from here on is the real "fail" code */
1191 
1192     if (ctx)
1193         (void) krb5_gss_delete_sec_context(&tmp_minor_status,
1194                                            (gss_ctx_id_t *) &ctx, NULL);
1195     if (deleg_cred) { /* free memory associated with the deleg credential */
1196         if (deleg_cred->ccache)
1197             (void)krb5_cc_close(context, deleg_cred->ccache);
1198         if (deleg_cred->name)
1199             kg_release_name(context, &deleg_cred->name);
1200         xfree(deleg_cred);
1201     }
1202     if (token.value)
1203         xfree(token.value);
1204     if (name) {
1205         (void) kg_release_name(context, &name);
1206     }
1207 
1208     *minor_status = code;
1209 
1210     /* We may have failed before being able to read the GSS flags from the
1211      * authenticator, so also check the request AP options. */
1212     if (cred != NULL && request != NULL &&
1213         ((gss_flags & GSS_C_MUTUAL_FLAG) ||
1214          (request->ap_options & AP_OPTS_MUTUAL_REQUIRED) ||
1215          major_status == GSS_S_CONTINUE_NEEDED)) {
1216         unsigned int tmsglen;
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 
1239         token.length = g_token_size(mech_used, tmsglen);
1240         token.value = gssalloc_malloc(token.length);
1241         if (!token.value)
1242             goto done;
1243         k5_buf_init_fixed(&buf, token.value, token.length);
1244         g_make_token_header(&buf, mech_used, tmsglen, KG_TOK_CTX_ERROR);
1245         k5_buf_add_len(&buf, scratch.data, scratch.length);
1246         assert(buf.len == token.length);
1247 
1248         krb5_free_data_contents(context, &scratch);
1249 
1250         *output_token = token;
1251     }
1252 
1253 done:
1254     krb5_free_ap_req(context, request);
1255     if (cred)
1256         k5_mutex_unlock(&cred->lock);
1257     if (defcred)
1258         krb5_gss_release_cred(&tmp_minor_status, &defcred);
1259     if (context) {
1260         if (major_status && *minor_status)
1261             save_error_info(*minor_status, context);
1262         krb5_free_context(context);
1263     }
1264     return (major_status);
1265 }
1266 #endif /* LEAN_CLIENT */
1267 
1268 OM_uint32 KRB5_CALLCONV
krb5_gss_accept_sec_context_ext(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_cred_id_t verifier_cred_handle,gss_buffer_t input_token,gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle,krb5_gss_ctx_ext_t exts)1269 krb5_gss_accept_sec_context_ext(
1270     OM_uint32 *minor_status,
1271     gss_ctx_id_t *context_handle,
1272     gss_cred_id_t verifier_cred_handle,
1273     gss_buffer_t input_token,
1274     gss_channel_bindings_t input_chan_bindings,
1275     gss_name_t *src_name,
1276     gss_OID *mech_type,
1277     gss_buffer_t output_token,
1278     OM_uint32 *ret_flags,
1279     OM_uint32 *time_rec,
1280     gss_cred_id_t *delegated_cred_handle,
1281     krb5_gss_ctx_ext_t exts)
1282 {
1283     krb5_gss_ctx_id_rec *ctx = (krb5_gss_ctx_id_rec *)*context_handle;
1284 
1285     /*
1286      * Context handle must be unspecified.  Actually, it must be
1287      * non-established, but currently, accept_sec_context never returns
1288      * a non-established context handle.
1289      */
1290     /*SUPPRESS 29*/
1291     if (ctx != NULL) {
1292         if (ctx->established == 0 && (ctx->gss_flags & GSS_C_DCE_STYLE)) {
1293             return kg_accept_dce(minor_status, context_handle,
1294                                  verifier_cred_handle, input_token,
1295                                  input_chan_bindings, src_name, mech_type,
1296                                  output_token, ret_flags, time_rec,
1297                                  delegated_cred_handle);
1298         } else {
1299             *minor_status = EINVAL;
1300             save_error_string(EINVAL, "accept_sec_context called with existing context handle");
1301             return GSS_S_FAILURE;
1302         }
1303     }
1304 
1305     return kg_accept_krb5(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, exts);
1310 }
1311 
1312 OM_uint32 KRB5_CALLCONV
krb5_gss_accept_sec_context(minor_status,context_handle,verifier_cred_handle,input_token,input_chan_bindings,src_name,mech_type,output_token,ret_flags,time_rec,delegated_cred_handle)1313 krb5_gss_accept_sec_context(minor_status, context_handle,
1314                             verifier_cred_handle, input_token,
1315                             input_chan_bindings, src_name, mech_type,
1316                             output_token, ret_flags, time_rec,
1317                             delegated_cred_handle)
1318     OM_uint32 *minor_status;
1319     gss_ctx_id_t *context_handle;
1320     gss_cred_id_t verifier_cred_handle;
1321     gss_buffer_t input_token;
1322     gss_channel_bindings_t input_chan_bindings;
1323     gss_name_t *src_name;
1324     gss_OID *mech_type;
1325     gss_buffer_t output_token;
1326     OM_uint32 *ret_flags;
1327     OM_uint32 *time_rec;
1328     gss_cred_id_t *delegated_cred_handle;
1329 {
1330     krb5_gss_ctx_ext_rec exts;
1331 
1332     memset(&exts, 0, sizeof(exts));
1333 
1334     return krb5_gss_accept_sec_context_ext(minor_status,
1335                                            context_handle,
1336                                            verifier_cred_handle,
1337                                            input_token,
1338                                            input_chan_bindings,
1339                                            src_name,
1340                                            mech_type,
1341                                            output_token,
1342                                            ret_flags,
1343                                            time_rec,
1344                                            delegated_cred_handle,
1345                                            &exts);
1346 }
1347