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