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