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