1 /*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
4 */
5 /*
6 * Copyright 2000, 2004 by the Massachusetts Institute of Technology.
7 * All Rights Reserved.
8 *
9 * Export of this software from the United States of America may
10 * require a specific license from the United States Government.
11 * It is the responsibility of any person or organization contemplating
12 * export to obtain such a license before exporting.
13 *
14 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15 * distribute this software and its documentation for any purpose and
16 * without fee is hereby granted, provided that the above copyright
17 * notice appear in all copies and that both that copyright notice and
18 * this permission notice appear in supporting documentation, and that
19 * the name of M.I.T. not be used in advertising or publicity pertaining
20 * to distribution of the software without specific, written prior
21 * permission. Furthermore if you modify this software you must label
22 * your software as modified software and not distribute it in such a
23 * fashion that it might be confused with the original M.I.T. software.
24 * M.I.T. makes no representations about the suitability of
25 * this software for any purpose. It is provided "as is" without express
26 * or implied warranty.
27 *
28 */
29 /*
30 * Copyright 1993 by OpenVision Technologies, Inc.
31 *
32 * Permission to use, copy, modify, distribute, and sell this software
33 * and its documentation for any purpose is hereby granted without fee,
34 * provided that the above copyright notice appears in all copies and
35 * that both that copyright notice and this permission notice appear in
36 * supporting documentation, and that the name of OpenVision not be used
37 * in advertising or publicity pertaining to distribution of the software
38 * without specific, written prior permission. OpenVision makes no
39 * representations about the suitability of this software for any
40 * purpose. It is provided "as is" without express or implied warranty.
41 *
42 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
43 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
44 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
45 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
46 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
47 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
48 * PERFORMANCE OF THIS SOFTWARE.
49 */
50
51 /*
52 * Copyright (C) 1998 by the FundsXpress, INC.
53 *
54 * All rights reserved.
55 *
56 * Export of this software from the United States of America may require
57 * a specific license from the United States Government. It is the
58 * responsibility of any person or organization contemplating export to
59 * obtain such a license before exporting.
60 *
61 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
62 * distribute this software and its documentation for any purpose and
63 * without fee is hereby granted, provided that the above copyright
64 * notice appear in all copies and that both that copyright notice and
65 * this permission notice appear in supporting documentation, and that
66 * the name of FundsXpress. not be used in advertising or publicity pertaining
67 * to distribution of the software without specific, written prior
68 * permission. FundsXpress makes no representations about the suitability of
69 * this software for any purpose. It is provided "as is" without express
70 * or implied warranty.
71 *
72 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
73 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
74 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
75 */
76
77 #include "k5-int.h"
78 #include "gssapiP_krb5.h"
79 #ifdef HAVE_MEMORY_H
80 #include <memory.h>
81 #endif
82 #include <assert.h>
83 #include "auth_con.h"
84 #ifdef CFX_EXERCISE
85 #define CFX_ACCEPTOR_SUBKEY (time(0) & 1)
86 #else
87 #define CFX_ACCEPTOR_SUBKEY 1
88 #endif
89 #include <syslog.h>
90 #include <locale.h> /* Solaris Kerberos */
91
92 /*
93 * Decode, decrypt and store the forwarded creds in the local ccache.
94 * and populate the callers delegated credential handle if it
95 * was provided.
96 */
97 static krb5_error_code
rd_and_store_for_creds(context,auth_context,inbuf,out_cred)98 rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
99 krb5_context context;
100 krb5_auth_context auth_context;
101 krb5_data *inbuf;
102 krb5_gss_cred_id_t *out_cred;
103 {
104 krb5_creds ** creds = NULL;
105 krb5_error_code retval;
106 krb5_ccache ccache = NULL;
107 krb5_gss_cred_id_t cred = NULL;
108 krb5_auth_context new_auth_ctx = NULL;
109 krb5_int32 flags_org;
110
111 /* Solaris Kerberos */
112 KRB5_LOG0(KRB5_INFO, "rd_and_store_for_creds() start");
113
114 if ((retval = krb5_auth_con_getflags(context, auth_context, &flags_org)))
115 return retval;
116 krb5_auth_con_setflags(context, auth_context,
117 0);
118
119 /*
120 * By the time krb5_rd_cred is called here (after krb5_rd_req has been
121 * called in krb5_gss_accept_sec_context), the "keyblock" field of
122 * auth_context contains a pointer to the session key, and the
123 * "recv_subkey" field might contain a session subkey. Either of
124 * these (the "recv_subkey" if it isn't NULL, otherwise the
125 * "keyblock") might have been used to encrypt the encrypted part of
126 * the KRB_CRED message that contains the forwarded credentials. (The
127 * Java Crypto and Security Implementation from the DSTC in Australia
128 * always uses the session key. But apparently it never negotiates a
129 * subkey, so this code works fine against a JCSI client.) Up to the
130 * present, though, GSSAPI clients linked against the MIT code (which
131 * is almost all GSSAPI clients) don't encrypt the KRB_CRED message at
132 * all -- at this level. So if the first call to krb5_rd_cred fails,
133 * we should call it a second time with another auth context freshly
134 * created by krb5_auth_con_init. All of its keyblock fields will be
135 * NULL, so krb5_rd_cred will assume that the KRB_CRED message is
136 * unencrypted. (The MIT code doesn't actually send the KRB_CRED
137 * message in the clear -- the "authenticator" whose "checksum" ends up
138 * containing the KRB_CRED message does get encrypted.)
139 */
140 /* Solaris Kerberos */
141 if ((retval = krb5_rd_cred(context, auth_context, inbuf, &creds, NULL))) {
142 krb5_enctype enctype = ENCTYPE_NULL;
143 /*
144 * If the client is using non-DES enctypes it really ought to
145 * send encrypted KRB-CREDs...
146 */
147 if (auth_context->keyblock != NULL)
148 enctype = auth_context->keyblock->enctype;
149 switch (enctype) {
150 case ENCTYPE_DES_CBC_MD5:
151 case ENCTYPE_DES_CBC_CRC:
152 case ENCTYPE_DES3_CBC_SHA1:
153 break;
154 default:
155 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
156 "krb5_rd_cred() retval = %d\n", retval);
157 goto cleanup;
158 /* NOTREACHED */
159 break;
160 }
161
162 /* Try to krb5_rd_cred() likely unencrypted KRB-CRED */
163 if ((retval = krb5_auth_con_init(context, &new_auth_ctx)))
164 goto cleanup;
165 krb5_auth_con_setflags(context, new_auth_ctx, 0);
166 if ((retval = krb5_rd_cred(context, new_auth_ctx, inbuf,
167 &creds, NULL))) {
168 /* Solaris Kerberos */
169 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
170 "krb5_rd_cred() retval = %d\n", retval);
171 goto cleanup;
172 }
173 }
174
175 if ((retval = krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))) {
176 ccache = NULL;
177 goto cleanup;
178 }
179
180 if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client))) {
181 /* Solaris Kerberos */
182 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
183 "krb5_cc_initialize() retval = %d\n", retval);
184 goto cleanup;
185 }
186
187 if ((retval = krb5_cc_store_cred(context, ccache, creds[0]))) {
188 /* Solaris Kerberos */
189 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
190 "krb5_cc_store_cred() retval = %d\n", retval);
191 goto cleanup;
192 }
193
194 /* generate a delegated credential handle */
195 if (out_cred) {
196 /* allocate memory for a cred_t... */
197 if (!(cred =
198 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec)))) {
199 retval = ENOMEM; /* out of memory? */
200 *out_cred = NULL;
201 goto cleanup;
202 }
203
204 /* zero it out... */
205 /* Solaris Kerberos */
206 (void) memset(cred, 0, sizeof(krb5_gss_cred_id_rec));
207
208 retval = k5_mutex_init(&cred->lock);
209 if (retval) {
210 xfree(cred);
211 cred = NULL;
212 goto cleanup;
213 }
214
215 /* copy the client principle into it... */
216 if ((retval =
217 krb5_copy_principal(context, creds[0]->client, &(cred->princ)))) {
218 /* Solaris Kerberos */
219 KRB5_LOG(KRB5_ERR, "rd_and_store_for_creds() error "
220 "krb5_copy_principal() retval = %d\n", retval);
221 k5_mutex_destroy(&cred->lock);
222 retval = ENOMEM; /* out of memory? */
223 xfree(cred); /* clean up memory on failure */
224 cred = NULL;
225 goto cleanup;
226 }
227
228 cred->usage = GSS_C_INITIATE; /* we can't accept with this */
229 /* cred->princ already set */
230 cred->prerfc_mech = 1; /* this cred will work with all three mechs */
231 cred->rfc_mech = 1;
232 cred->keytab = NULL; /* no keytab associated with this... */
233 cred->tgt_expire = creds[0]->times.endtime; /* store the end time */
234 cred->ccache = ccache; /* the ccache containing the credential */
235 ccache = NULL; /* cred takes ownership so don't destroy */
236 }
237
238 /* If there were errors, there might have been a memory leak
239 if (!cred)
240 if ((retval = krb5_cc_close(context, ccache)))
241 goto cleanup;
242 */
243 cleanup:
244 if (creds)
245 krb5_free_tgt_creds(context, creds);
246
247 if (ccache)
248 (void)krb5_cc_destroy(context, ccache);
249
250 if (out_cred)
251 *out_cred = cred; /* return credential */
252
253 if (new_auth_ctx)
254 krb5_auth_con_free(context, new_auth_ctx);
255
256 krb5_auth_con_setflags(context, auth_context, flags_org);
257
258 /* Solaris Kerberos */
259 KRB5_LOG(KRB5_INFO, "rd_and_store_for_creds() end retval %d", retval);
260 return retval;
261 }
262
263 /*
264 * SUNW15resync
265 * Most of the logic here left "as is" because of lots of fixes MIT
266 * does not have yet
267 */
268 OM_uint32
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)269 krb5_gss_accept_sec_context(minor_status, context_handle,
270 verifier_cred_handle, input_token,
271 input_chan_bindings, src_name, mech_type,
272 output_token, ret_flags, time_rec,
273 delegated_cred_handle)
274 OM_uint32 *minor_status;
275 gss_ctx_id_t *context_handle;
276 gss_cred_id_t verifier_cred_handle;
277 gss_buffer_t input_token;
278 gss_channel_bindings_t input_chan_bindings;
279 gss_name_t *src_name;
280 gss_OID *mech_type;
281 gss_buffer_t output_token;
282 OM_uint32 *ret_flags;
283 OM_uint32 *time_rec;
284 gss_cred_id_t *delegated_cred_handle;
285 {
286 krb5_context context;
287 unsigned char *ptr, *ptr2;
288 krb5_gss_ctx_id_rec *ctx = 0;
289 char *sptr;
290 long tmp;
291 size_t md5len;
292 int bigend;
293 krb5_gss_cred_id_t cred = 0;
294 krb5_data ap_rep, ap_req;
295 krb5_ap_req *request = NULL;
296 int i;
297 krb5_error_code code;
298 krb5_address addr, *paddr;
299 krb5_authenticator *authdat = 0;
300 krb5_checksum reqcksum;
301 krb5_principal client_name = NULL;
302 krb5_principal server_name = NULL;
303 krb5_ui_4 gss_flags = 0;
304 krb5_timestamp now;
305 gss_buffer_desc token;
306 krb5_auth_context auth_context = NULL;
307 krb5_ticket * ticket = NULL;
308 int option_id;
309 krb5_data option;
310 const gss_OID_desc *mech_used = NULL;
311 OM_uint32 major_status = GSS_S_FAILURE;
312 krb5_error krb_error_data;
313 krb5_data scratch;
314 gss_cred_id_t cred_handle = NULL;
315 krb5_gss_cred_id_t deleg_cred = NULL;
316 OM_uint32 saved_ap_options = 0;
317 krb5int_access kaccess;
318 int cred_rcache = 0;
319 int no_encap;
320 OM_uint32 t_minor_status = 0;
321 int acquire_fail = 0;
322
323 KRB5_LOG0(KRB5_INFO,"krb5_gss_accept_sec_context() start");
324
325 /* Solaris Kerberos */
326 memset(&krb_error_data, 0, sizeof(krb_error_data));
327
328 code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
329 if (code) {
330 *minor_status = code;
331 return(GSS_S_FAILURE);
332 }
333
334 code = krb5_gss_init_context(&context);
335 if (code) {
336 *minor_status = code;
337 return GSS_S_FAILURE;
338 }
339
340 /* set up returns to be freeable */
341
342 if (src_name)
343 *src_name = (gss_name_t) NULL;
344 output_token->length = 0;
345 output_token->value = NULL;
346 token.value = 0;
347 reqcksum.contents = 0;
348 ap_req.data = 0;
349 ap_rep.data = 0;
350
351 if (mech_type)
352 *mech_type = GSS_C_NULL_OID;
353 /* initialize the delegated cred handle to NO_CREDENTIAL for now */
354 if (delegated_cred_handle)
355 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
356
357 /*
358 * Context handle must be unspecified. Actually, it must be
359 * non-established, but currently, accept_sec_context never returns
360 * a non-established context handle.
361 */
362 /*SUPPRESS 29*/
363 if (*context_handle != GSS_C_NO_CONTEXT) {
364 *minor_status = 0;
365
366 /* Solaris kerberos: the original Solaris code returned GSS_S_NO_CONTEXT
367 * for this error. This conflicts somewhat with RFC2743 which states
368 * GSS_S_NO_CONTEXT should be returned only for sucessor calls following
369 * GSS_S_CONTINUE_NEEDED status returns. Note the MIT code doesn't
370 * return GSS_S_NO_CONTEXT at all.
371 */
372
373 major_status = GSS_S_NO_CONTEXT;
374 KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
375 "error GSS_S_NO_CONTEXT");
376 goto cleanup;
377 }
378
379 /* verify the token's integrity, and leave the token in ap_req.
380 figure out which mech oid was used, and save it */
381
382 ptr = (unsigned char *) input_token->value;
383
384 if (!(code = g_verify_token_header(gss_mech_krb5,
385 (uint32_t *)&(ap_req.length),
386 &ptr, KG_TOK_CTX_AP_REQ,
387 input_token->length, 1))) {
388 mech_used = gss_mech_krb5;
389 } else if ((code == G_WRONG_MECH) &&
390 !(code = g_verify_token_header(gss_mech_krb5_wrong,
391 (uint32_t *)&(ap_req.length),
392 &ptr, KG_TOK_CTX_AP_REQ,
393 input_token->length, 1))) {
394 mech_used = gss_mech_krb5_wrong;
395 } else if ((code == G_WRONG_MECH) &&
396 !(code = g_verify_token_header(gss_mech_krb5_old,
397 (uint32_t *)&(ap_req.length),
398 &ptr, KG_TOK_CTX_AP_REQ,
399 input_token->length, 1))) {
400 /*
401 * Previous versions of this library used the old mech_id
402 * and some broken behavior (wrong IV on checksum
403 * encryption). We support the old mech_id for
404 * compatibility, and use it to decide when to use the
405 * old behavior.
406 */
407 mech_used = gss_mech_krb5_old;
408 } else if (code == G_WRONG_TOKID) {
409 major_status = GSS_S_CONTINUE_NEEDED;
410 code = KRB5KRB_AP_ERR_MSG_TYPE;
411 mech_used = gss_mech_krb5;
412 goto fail;
413 } else if (code == G_BAD_TOK_HEADER) {
414 /* DCE style not encapsulated */
415 ap_req.length = input_token->length;
416 ap_req.data = input_token->value;
417 mech_used = gss_mech_krb5;
418 no_encap = 1;
419 } else {
420 major_status = GSS_S_DEFECTIVE_TOKEN;
421 goto fail;
422 }
423
424 sptr = (char *) ptr;
425 TREAD_STR(sptr, ap_req.data, ap_req.length);
426
427 /*
428 * Solaris Kerberos:
429 * We need to decode the request now so that we can get the
430 * service principal in order to try and acquire a cred for it.
431 * below in the "handle default cred handle" code block.
432 */
433 if (!krb5_is_ap_req(&ap_req)) {
434 code = KRB5KRB_AP_ERR_MSG_TYPE;
435 goto fail;
436 }
437 /* decode the AP-REQ into request */
438 if ((code = decode_krb5_ap_req(&ap_req, &request))) {
439 if (code == KRB5_BADMSGTYPE)
440 code = KRB5KRB_AP_ERR_BADVERSION;
441 goto fail;
442 }
443
444 /* handle default cred handle */
445 /*
446 * Solaris Kerberos:
447 * If there is no princ associated with the cred then treat it the
448 * the same as GSS_C_NO_CREDENTIAL.
449 */
450 if (verifier_cred_handle == GSS_C_NO_CREDENTIAL ||
451 ((krb5_gss_cred_id_t)verifier_cred_handle)->princ == NULL) {
452 /* Note that we try to acquire a cred for the service principal
453 * named in the AP-REQ. This allows us to implement option (ii)
454 * of the recommended behaviour for GSS_Accept_sec_context() as
455 * described in section 1.1.1.3 of RFC2743.
456
457 * This is far more useful that option (i), for which we would
458 * acquire a cred for GSS_C_NO_NAME.
459 */
460 /* copy the princ from the ap-req or we'll lose it when we free
461 the ap-req */
462 krb5_principal princ;
463 if ((code = krb5_copy_principal(context, request->ticket->server,
464 &princ))) {
465 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
466 "krb5_copy_principal() error code %d", code);
467 major_status = GSS_S_FAILURE;
468 goto fail;
469 }
470 /* intern the acceptor name */
471 if (! kg_save_name((gss_name_t) princ)) {
472 code = G_VALIDATE_FAILED;
473 major_status = GSS_S_FAILURE;
474 goto fail;
475 }
476 major_status = krb5_gss_acquire_cred((OM_uint32*) &code,
477 (gss_name_t) princ,
478 GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
479 GSS_C_ACCEPT, &cred_handle,
480 NULL, NULL);
481
482 if (major_status != GSS_S_COMPLETE){
483 /* Solaris kerberos: RFC2743 indicate this should be returned if we
484 * can't aquire a default cred.
485 */
486 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
487 "krb5_gss_acquire_cred() error"
488 "orig major_status = %d, now = GSS_S_NO_CRED\n",
489 major_status);
490 acquire_fail = 1;
491 major_status = GSS_S_NO_CRED;
492 goto fail;
493 }
494
495 } else {
496 cred_handle = verifier_cred_handle;
497 }
498
499 major_status = krb5_gss_validate_cred((OM_uint32*) &code,
500 cred_handle);
501
502 if (GSS_ERROR(major_status)){
503
504 /* Solaris kerberos: RFC2743 indicate GSS_S_NO_CRED should be returned if
505 * the supplied cred isn't valid.
506 */
507
508 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
509 "krb5_gss_validate_cred() error"
510 "orig major_status = %d, now = GSS_S_NO_CRED\n",
511 major_status);
512
513 major_status = GSS_S_NO_CRED;
514 goto fail;
515 }
516
517 cred = (krb5_gss_cred_id_t) cred_handle;
518
519 /* make sure the supplied credentials are valid for accept */
520
521 if ((cred->usage != GSS_C_ACCEPT) &&
522 (cred->usage != GSS_C_BOTH)) {
523 code = 0;
524 KRB5_LOG0(KRB5_ERR,"krb5_gss_accept_sec_context() "
525 "error GSS_S_NO_CONTEXT");
526 major_status = GSS_S_NO_CRED;
527 goto fail;
528 }
529
530 /* construct the sender_addr */
531
532 if ((input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) &&
533 (input_chan_bindings->initiator_addrtype == GSS_C_AF_INET)) {
534 /* XXX is this right? */
535 addr.addrtype = ADDRTYPE_INET;
536 addr.length = input_chan_bindings->initiator_address.length;
537 addr.contents = input_chan_bindings->initiator_address.value;
538
539 paddr = &addr;
540 } else {
541 paddr = NULL;
542 }
543
544 /* verify the AP_REQ message - setup the auth_context and rcache */
545
546 if ((code = krb5_auth_con_init(context, &auth_context))) {
547 major_status = GSS_S_FAILURE;
548 save_error_info((OM_uint32)code, context);
549 /* Solaris Kerberos */
550 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
551 "krb5_auth_con_init() error code %d", code);
552 goto fail;
553 }
554
555 (void) krb5_auth_con_setflags(context, auth_context,
556 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
557
558 if (cred->rcache) {
559 cred_rcache = 1;
560 if ((code = krb5_auth_con_setrcache(context, auth_context, cred->rcache))) {
561 major_status = GSS_S_FAILURE;
562 /* Solaris Kerberos */
563 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
564 "krb5_auth_con_setrcache() error code %d", code);
565 goto fail;
566 }
567 }
568 if ((code = krb5_auth_con_setaddrs(context, auth_context, NULL, paddr))) {
569 major_status = GSS_S_FAILURE;
570 /* Solaris Kerberos */
571 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
572 "krb5_auth_con_setaddrs() error code %d", code);
573 goto fail;
574 }
575
576 if ((code = krb5_rd_req_decoded(context, &auth_context, request,
577 cred->princ, cred->keytab, NULL, &ticket))) {
578 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
579 "krb5_rd_req() error code %d", code);
580 if (code == KRB5_KT_KVNONOTFOUND) {
581 char *s_name;
582 if (krb5_unparse_name(context, cred->princ, &s_name) == 0) {
583 krb5_set_error_message(context, KRB5KRB_AP_ERR_BADKEYVER,
584 dgettext(TEXT_DOMAIN,
585 "Key version %d is not available for principal %s"),
586 request->ticket->enc_part.kvno,
587 s_name);
588 krb5_free_unparsed_name(context, s_name);
589 }
590 major_status = GSS_S_DEFECTIVE_CREDENTIAL;
591 code = KRB5KRB_AP_ERR_BADKEYVER;
592 } else if (code == KRB5_KT_NOTFOUND) {
593 char *s_name;
594 if (krb5_unparse_name(context, cred->princ, &s_name) == 0) {
595 krb5_set_error_message(context, KRB5KRB_AP_ERR_NOKEY,
596 dgettext(TEXT_DOMAIN,
597 "Service key %s not available"),
598 s_name);
599 krb5_free_unparsed_name(context, s_name);
600 }
601 major_status = GSS_S_DEFECTIVE_CREDENTIAL;
602 code = KRB5KRB_AP_ERR_NOKEY;
603 }
604 else if (code == KRB5KRB_AP_WRONG_PRINC) {
605 major_status = GSS_S_NO_CRED;
606 code = KRB5KRB_AP_ERR_NOT_US;
607 }
608 else if (code == KRB5KRB_AP_ERR_REPEAT)
609 major_status = GSS_S_DUPLICATE_TOKEN;
610 else
611 major_status = GSS_S_FAILURE;
612 goto fail;
613 }
614 krb5_auth_con_setflags(context, auth_context,
615 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
616
617 /* Solaris Kerberos */
618 code = krb5_auth_con_getauthenticator(context, auth_context, &authdat);
619 if (code) {
620 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
621 "krb5_auth_con_getauthenticator() error code %d", code);
622 major_status = GSS_S_FAILURE;
623 goto fail;
624 }
625
626 #if 0
627 /* make sure the necessary parts of the authdat are present */
628
629 if ((authdat->authenticator->subkey == NULL) ||
630 (authdat->ticket->enc_part2 == NULL)) {
631 code = KG_NO_SUBKEY;
632 major_status = GSS_S_FAILURE;
633 goto fail;
634 }
635 #endif
636
637 {
638 /* gss krb5 v1 */
639
640 /* stash this now, for later. */
641 code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
642 if (code) {
643 /* Solaris Kerberos */
644 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
645 "krb5_c_checksum_length() error code %d", code);
646 major_status = GSS_S_FAILURE;
647 goto fail;
648 }
649
650 /* verify that the checksum is correct */
651 if (authdat->checksum == NULL) {
652 /* missing checksum counts as "inappropriate type" */
653 code = KRB5KRB_AP_ERR_INAPP_CKSUM;
654 major_status = GSS_S_FAILURE;
655 goto fail;
656 }
657
658 /*
659 The checksum may be either exactly 24 bytes, in which case
660 no options are specified, or greater than 24 bytes, in which case
661 one or more options are specified. Currently, the only valid
662 option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
663 */
664
665 if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
666 (authdat->checksum->length < 24)) {
667 code = 0;
668 major_status = GSS_S_BAD_BINDINGS;
669 goto fail;
670 }
671
672 /*
673 "Be liberal in what you accept, and
674 conservative in what you send"
675 -- rfc1123
676
677 This code will let this acceptor interoperate with an initiator
678 using little-endian or big-endian integer encoding.
679 */
680
681 ptr = (unsigned char *) authdat->checksum->contents;
682 bigend = 0;
683
684 TREAD_INT(ptr, tmp, bigend);
685
686 if (tmp != md5len) {
687 ptr = (unsigned char *) authdat->checksum->contents;
688 bigend = 1;
689
690 TREAD_INT(ptr, tmp, bigend);
691
692 if (tmp != md5len) {
693 code = KG_BAD_LENGTH;
694 major_status = GSS_S_FAILURE;
695 goto fail;
696 }
697 }
698
699 /* at this point, bigend is set according to the initiator's
700 byte order */
701
702
703 /*
704 The following section of code attempts to implement the
705 optional channel binding facility as described in RFC2743.
706
707 Since this facility is optional channel binding may or may
708 not have been provided by either the client or the server.
709
710 If the server has specified input_chan_bindings equal to
711 GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
712 the server does provide channel bindings then we compute
713 a checksum and compare against those provided by the
714 client. If the check fails we test the clients checksum
715 to see whether the client specified GSS_C_NO_CHANNEL_BINDINGS.
716 If either test succeeds we continue without error.
717 */
718 if ((code = kg_checksum_channel_bindings(context,
719 input_chan_bindings,
720 &reqcksum, bigend))) {
721 /* Solaris Kerberos */
722 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
723 "kg_checksum_channel_bindings() error code %d", code);
724 major_status = GSS_S_BAD_BINDINGS;
725 goto fail;
726 }
727
728 TREAD_STR(ptr, ptr2, reqcksum.length);
729
730 if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
731 if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
732 xfree(reqcksum.contents);
733 reqcksum.contents = 0;
734 if ((code = kg_checksum_channel_bindings(context,
735 GSS_C_NO_CHANNEL_BINDINGS,
736 &reqcksum, bigend))) {
737 major_status = GSS_S_BAD_BINDINGS;
738 goto fail;
739 }
740 if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
741 code = 0;
742 major_status = GSS_S_BAD_BINDINGS;
743 goto fail;
744 }
745 }
746
747 }
748
749 TREAD_INT(ptr, gss_flags, bigend);
750
751 /* if the checksum length > 24, there are options to process */
752
753 if(authdat->checksum->length > 24 && (gss_flags & GSS_C_DELEG_FLAG)) {
754
755 i = authdat->checksum->length - 24;
756
757 if (i >= 4) {
758
759 TREAD_INT16(ptr, option_id, bigend);
760
761 TREAD_INT16(ptr, option.length, bigend);
762
763 i -= 4;
764
765 if (i < option.length || option.length < 0) {
766 code = KG_BAD_LENGTH;
767 major_status = GSS_S_FAILURE;
768 goto fail;
769 }
770
771 /* have to use ptr2, since option.data is wrong type and
772 macro uses ptr as both lvalue and rvalue */
773
774 TREAD_STR(ptr, ptr2, option.length);
775 option.data = (char *) ptr2;
776
777 i -= option.length;
778
779 if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
780 major_status = GSS_S_FAILURE;
781 goto fail;
782 }
783
784 /* store the delegated credential */
785
786 code = rd_and_store_for_creds(context, auth_context, &option,
787 (delegated_cred_handle) ?
788 &deleg_cred : NULL);
789 if (code) {
790 major_status = GSS_S_FAILURE;
791 goto fail;
792 }
793
794 } /* if i >= 4 */
795 /* ignore any additional trailing data, for now */
796 #ifdef CFX_EXERCISE
797 {
798 FILE *f = fopen("/tmp/gsslog", "a");
799 if (f) {
800 fprintf(f,
801 "initial context token with delegation, %d extra bytes\n",
802 i);
803 fclose(f);
804 }
805 }
806 #endif
807 } else {
808 #ifdef CFX_EXERCISE
809 {
810 FILE *f = fopen("/tmp/gsslog", "a");
811 if (f) {
812 if (gss_flags & GSS_C_DELEG_FLAG)
813 fprintf(f,
814 "initial context token, delegation flag but too small\n");
815 else
816 /* no deleg flag, length might still be too big */
817 fprintf(f,
818 "initial context token, %d extra bytes\n",
819 authdat->checksum->length - 24);
820 fclose(f);
821 }
822 }
823 #endif
824 }
825 }
826
827 /* create the ctx struct and start filling it in */
828
829 if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
830 == NULL) {
831 code = ENOMEM;
832 major_status = GSS_S_FAILURE;
833 goto fail;
834 }
835
836 memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
837 ctx->mech_used = (gss_OID) mech_used;
838 ctx->auth_context = auth_context;
839 ctx->initiate = 0;
840 ctx->gss_flags = (GSS_C_TRANS_FLAG |
841 ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
842 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
843 GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
844 ctx->seed_init = 0;
845 ctx->big_endian = bigend;
846 ctx->cred_rcache = cred_rcache;
847
848 /* Intern the ctx pointer so that delete_sec_context works */
849 if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
850 xfree(ctx);
851 ctx = 0;
852
853 /* Solaris Kerberos */
854 KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
855 "kg_save_ctx_id() error");
856 code = G_VALIDATE_FAILED;
857 major_status = GSS_S_FAILURE;
858 goto fail;
859 }
860
861 /* XXX move this into gss_name_t */
862 if ((code = krb5_merge_authdata(context,
863 ticket->enc_part2->authorization_data,
864 authdat->authorization_data,
865 &ctx->authdata))) {
866 major_status = GSS_S_FAILURE;
867 goto fail;
868 }
869
870 if ((code = krb5_copy_principal(context, cred->princ, &ctx->here))) {
871 /* Solaris Kerberos */
872 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
873 "krb5_copy_principal() error code %d", code);
874 major_status = GSS_S_FAILURE;
875 goto fail;
876 }
877
878 if ((code = krb5_copy_principal(context, authdat->client, &ctx->there))) {
879 /* Solaris Kerberos */
880 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
881 "krb5_copy_principal() 2 error code %d", code);
882 major_status = GSS_S_FAILURE;
883 goto fail;
884 }
885
886 if ((code = krb5_auth_con_getrecvsubkey(context, auth_context,
887 &ctx->subkey))) {
888 /* Solaris Kerberos */
889 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
890 "krb5_auth_con_getremotesubkey() error code %d", code);
891 major_status = GSS_S_FAILURE;
892 goto fail;
893 }
894
895 /* use the session key if the subkey isn't present */
896
897 if (ctx->subkey == NULL) {
898 if ((code = krb5_auth_con_getkey(context, auth_context,
899 &ctx->subkey))) {
900 /* Solaris Kerberos */
901 KRB5_LOG(KRB5_ERR, "krb5_gss_accept_sec_context() "
902 "krb5_auth_con_getkey() error code %d", code);
903 *minor_status = (OM_uint32) KRB5KDC_ERR_NULL_KEY;
904 major_status = GSS_S_FAILURE;
905 goto fail;
906 }
907 }
908
909 if (ctx->subkey == NULL) {
910 /* this isn't a very good error, but it's not clear to me this
911 can actually happen */
912 major_status = GSS_S_FAILURE;
913 code = KRB5KDC_ERR_NULL_KEY;
914 goto fail;
915 }
916
917 /* Solaris Kerberos */
918 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() "
919 "ctx->subkey->enctype=%d", ctx->subkey->enctype);
920
921 ctx->proto = 0;
922 switch(ctx->subkey->enctype) {
923 case ENCTYPE_DES_CBC_MD5:
924 case ENCTYPE_DES_CBC_CRC:
925 ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
926 ctx->signalg = SGN_ALG_DES_MAC_MD5;
927 ctx->cksum_size = 8;
928 ctx->sealalg = SEAL_ALG_DES;
929
930 /* fill in the encryption descriptors */
931
932 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
933 major_status = GSS_S_FAILURE;
934 goto fail;
935 }
936
937 for (i=0; i<ctx->enc->length; i++)
938 /*SUPPRESS 113*/
939 ctx->enc->contents[i] ^= 0xf0;
940
941 goto copy_subkey_to_seq;
942 break;
943
944 case ENCTYPE_DES3_CBC_SHA1:
945 ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
946 ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
947 ctx->cksum_size = 20;
948 ctx->sealalg = SEAL_ALG_DES3KD;
949
950 /* fill in the encryption descriptors */
951 copy_subkey:
952 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc))) {
953 major_status = GSS_S_FAILURE;
954 goto fail;
955 }
956 copy_subkey_to_seq:
957 if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq))) {
958 major_status = GSS_S_FAILURE;
959 goto fail;
960 }
961 break;
962
963 case ENCTYPE_ARCFOUR_HMAC:
964 ctx->signalg = SGN_ALG_HMAC_MD5 ;
965 ctx->cksum_size = 8;
966 ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
967 goto copy_subkey;
968
969 default:
970 ctx->signalg = -1;
971 ctx->sealalg = -1;
972 ctx->proto = 1;
973 code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
974 &ctx->cksumtype);
975 if (code)
976 goto fail;
977 code = krb5_c_checksum_length(context, ctx->cksumtype,
978 (size_t *)&ctx->cksum_size);
979 if (code)
980 goto fail;
981 ctx->have_acceptor_subkey = 0;
982 goto copy_subkey;
983 }
984
985 /* Solaris Kerberos */
986 KRB5_LOG1(KRB5_ERR, "accept_sec_context: subkey enctype = %d proto = %d",
987 ctx->subkey->enctype, ctx->proto);
988
989 ctx->endtime = ticket->enc_part2->times.endtime;
990 ctx->krb_flags = ticket->enc_part2->flags;
991
992 krb5_free_ticket(context, ticket); /* Done with ticket */
993
994 {
995 krb5_ui_4 seq_temp;
996 krb5_auth_con_getremoteseqnumber(context, auth_context,
997 (krb5_int32 *)&seq_temp);
998 ctx->seq_recv = seq_temp;
999 }
1000
1001 if ((code = krb5_timeofday(context, &now))) {
1002 major_status = GSS_S_FAILURE;
1003 goto fail;
1004 }
1005
1006 if (ctx->endtime < now) {
1007 code = 0;
1008 major_status = GSS_S_CREDENTIALS_EXPIRED;
1009 goto fail;
1010 }
1011
1012 g_order_init(&(ctx->seqstate), ctx->seq_recv,
1013 (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
1014 (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
1015
1016 /* at this point, the entire context structure is filled in,
1017 so it can be released. */
1018
1019 /* generate an AP_REP if necessary */
1020
1021 if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
1022 unsigned char * ptr3;
1023 krb5_ui_4 seq_temp;
1024 int cfx_generate_subkey;
1025
1026 if (ctx->proto == 1)
1027 cfx_generate_subkey = CFX_ACCEPTOR_SUBKEY;
1028 else
1029 cfx_generate_subkey = 0;
1030
1031 if (cfx_generate_subkey) {
1032 krb5_int32 acflags;
1033 code = krb5_auth_con_getflags(context, auth_context, &acflags);
1034 if (code == 0) {
1035 acflags |= KRB5_AUTH_CONTEXT_USE_SUBKEY;
1036 code = krb5_auth_con_setflags(context, auth_context, acflags);
1037 }
1038 if (code) {
1039 major_status = GSS_S_FAILURE;
1040 goto fail;
1041 }
1042 }
1043
1044 if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) {
1045 major_status = GSS_S_FAILURE;
1046 goto fail;
1047 }
1048
1049 krb5_auth_con_getlocalseqnumber(context, auth_context,
1050 (krb5_int32 *)&seq_temp);
1051 ctx->seq_send = seq_temp & 0xffffffffL;
1052
1053 if (cfx_generate_subkey) {
1054 /* Get the new acceptor subkey. With the code above, there
1055 should always be one if we make it to this point. */
1056 code = krb5_auth_con_getsendsubkey(context, auth_context,
1057 &ctx->acceptor_subkey);
1058 if (code != 0) {
1059 major_status = GSS_S_FAILURE;
1060 goto fail;
1061 }
1062 code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
1063 ctx->acceptor_subkey->enctype,
1064 &ctx->acceptor_subkey_cksumtype);
1065 if (code) {
1066 major_status = GSS_S_FAILURE;
1067 goto fail;
1068 }
1069 ctx->have_acceptor_subkey = 1;
1070 }
1071
1072 /* the reply token hasn't been sent yet, but that's ok. */
1073 ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
1074 ctx->established = 1;
1075
1076 token.length = g_token_size(mech_used, ap_rep.length);
1077
1078 if ((token.value = (unsigned char *) xmalloc(token.length))
1079 == NULL) {
1080 major_status = GSS_S_FAILURE;
1081 code = ENOMEM;
1082 goto fail;
1083 }
1084 ptr3 = token.value;
1085 g_make_token_header(mech_used, ap_rep.length,
1086 &ptr3, KG_TOK_CTX_AP_REP);
1087
1088 TWRITE_STR(ptr3, ap_rep.data, ap_rep.length);
1089
1090 ctx->established = 1;
1091
1092 } else {
1093 token.length = 0;
1094 token.value = NULL;
1095 ctx->seq_send = ctx->seq_recv;
1096
1097 ctx->established = 1;
1098 }
1099
1100 /* set the return arguments */
1101
1102 /*
1103 * Solaris Kerberos
1104 * Regardless of src_name, get name for error msg if neeeded.
1105 */
1106 if ((code = krb5_copy_principal(context, ctx->there, &client_name))) {
1107 major_status = GSS_S_FAILURE;
1108 goto fail;
1109 }
1110 if ((code = krb5_copy_principal(context, ctx->here, &server_name))) {
1111 major_status = GSS_S_FAILURE;
1112 goto fail;
1113 }
1114 /* intern the src_name */
1115 if (! kg_save_name((gss_name_t) client_name)) {
1116 code = G_VALIDATE_FAILED;
1117 major_status = GSS_S_FAILURE;
1118 goto fail;
1119 }
1120
1121 if (time_rec)
1122 *time_rec = ctx->endtime - now;
1123
1124 if (ret_flags)
1125 *ret_flags = ctx->gss_flags;
1126
1127 *context_handle = (gss_ctx_id_t)ctx;
1128 *output_token = token;
1129
1130 if (src_name)
1131 *src_name = (gss_name_t) client_name;
1132
1133 if (delegated_cred_handle && deleg_cred) {
1134 if (!kg_save_cred_id((gss_cred_id_t) deleg_cred)) {
1135 /* Solaris Kerberos */
1136 KRB5_LOG0(KRB5_ERR, "krb5_gss_accept_sec_context() "
1137 "kg_save_cred_id() error");
1138 major_status = GSS_S_FAILURE;
1139 code = (OM_uint32) G_VALIDATE_FAILED;
1140 goto fail;
1141 }
1142
1143 *delegated_cred_handle = (gss_cred_id_t) deleg_cred;
1144 }
1145
1146 if (server_name)
1147 krb5_free_principal(context, server_name);
1148
1149 /* finally! */
1150
1151 *minor_status = 0;
1152 major_status = GSS_S_COMPLETE;
1153
1154 fail:
1155 if (mech_type) {
1156 /*
1157 * This needs to be set/returned even on fail so
1158 * gss_accept_sec_context() can map_error_oid() the correct
1159 * error/oid for later use by gss_display_status().
1160 * (needed in CIFS/SPNEGO case)
1161 */
1162 *mech_type = (gss_OID) mech_used;
1163 }
1164
1165 if (authdat)
1166 krb5_free_authenticator(context, authdat);
1167 /* The ctx structure has the handle of the auth_context */
1168 if (auth_context && !ctx) {
1169 if (cred_rcache)
1170 (void)krb5_auth_con_setrcache(context, auth_context, NULL);
1171
1172 krb5_auth_con_free(context, auth_context);
1173 }
1174 if (reqcksum.contents)
1175 xfree(reqcksum.contents);
1176 if (ap_rep.data)
1177 xfree(ap_rep.data);
1178
1179 if (request != NULL) {
1180 saved_ap_options = request->ap_options;
1181 krb5_free_ap_req(context, request);
1182 request = NULL;
1183 }
1184
1185 if (!GSS_ERROR(major_status) && major_status != GSS_S_CONTINUE_NEEDED) {
1186 if (!verifier_cred_handle && cred_handle) {
1187 krb5_gss_release_cred(minor_status, &cred_handle);
1188 }
1189
1190 if (ctx)
1191 ctx->k5_context = context;
1192
1193 return(major_status);
1194 }
1195
1196 /* from here on is the real "fail" code */
1197
1198 if (ctx)
1199 (void) krb5_gss_delete_sec_context(minor_status,
1200 (gss_ctx_id_t *) &ctx, NULL);
1201 if (deleg_cred) { /* free memory associated with the deleg credential */
1202 if (deleg_cred->ccache)
1203 (void)krb5_cc_close(context, deleg_cred->ccache);
1204 if (deleg_cred->princ)
1205 krb5_free_principal(context, deleg_cred->princ);
1206 xfree(deleg_cred);
1207 }
1208 if (token.value)
1209 xfree(token.value);
1210
1211 *minor_status = code;
1212
1213 if (saved_ap_options & AP_OPTS_MUTUAL_REQUIRED)
1214 gss_flags |= GSS_C_MUTUAL_FLAG;
1215
1216 if (cred
1217 && ((gss_flags & GSS_C_MUTUAL_FLAG)
1218 || (major_status == GSS_S_CONTINUE_NEEDED))) {
1219 unsigned int tmsglen;
1220 int toktype;
1221
1222 /*
1223 * The client is expecting a response, so we can send an
1224 * error token back
1225 */
1226
1227 /*
1228 * Solaris Kerberos: We need to remap error conditions for buggy
1229 * Windows clients if the MS_INTEROP env var has been set.
1230 */
1231 if ((code == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
1232 code == KRB5KRB_AP_ERR_NOKEY || code == KRB5KRB_AP_ERR_BADKEYVER)
1233 && krb5_getenv("MS_INTEROP")) {
1234 code = KRB5KRB_AP_ERR_MODIFIED;
1235 major_status = GSS_S_CONTINUE_NEEDED;
1236 }
1237
1238 /*
1239 * SUNW17PACresync / Solaris Kerberos
1240 * Set e-data to Windows constant.
1241 * (verified by MSFT)
1242 *
1243 * This facilitates the Windows CIFS client clock skew
1244 * recovery feature.
1245 */
1246 if (code == KRB5KRB_AP_ERR_SKEW && krb5_getenv("MS_INTEROP")) {
1247 char *ms_e_data = "\x30\x05\xa1\x03\x02\x01\x02";
1248 int len = strlen(ms_e_data);
1249
1250 krb_error_data.e_data.data = malloc(len);
1251 if (krb_error_data.e_data.data) {
1252 (void) memcpy(krb_error_data.e_data.data, ms_e_data, len);
1253 krb_error_data.e_data.length = len;
1254 }
1255 major_status = GSS_S_CONTINUE_NEEDED;
1256 }
1257
1258 code -= ERROR_TABLE_BASE_krb5;
1259 if (code < 0 || code > 128)
1260 code = 60 /* KRB_ERR_GENERIC */;
1261
1262 krb_error_data.error = code;
1263 (void) krb5_us_timeofday(context, &krb_error_data.stime,
1264 &krb_error_data.susec);
1265 krb_error_data.server = cred->princ;
1266
1267 code = krb5_mk_error(context, &krb_error_data, &scratch);
1268 if (code)
1269 goto cleanup;
1270
1271 tmsglen = scratch.length;
1272 toktype = KG_TOK_CTX_ERROR;
1273
1274 token.length = g_token_size(mech_used, tmsglen);
1275 token.value = (unsigned char *) xmalloc(token.length);
1276 if (!token.value)
1277 goto cleanup;
1278
1279 ptr = token.value;
1280 g_make_token_header(mech_used, tmsglen, &ptr, toktype);
1281
1282 TWRITE_STR(ptr, scratch.data, scratch.length);
1283 xfree(scratch.data);
1284
1285 *output_token = token;
1286 }
1287
1288 cleanup:
1289 /* Solaris Kerberos */
1290 if (krb_error_data.e_data.data != NULL)
1291 free(krb_error_data.e_data.data);
1292
1293 if (!verifier_cred_handle && cred_handle) {
1294 krb5_gss_release_cred(&t_minor_status, &cred_handle);
1295 }
1296
1297 /*
1298 * Solaris Kerberos
1299 * Enhance the error message.
1300 */
1301 if (GSS_ERROR(major_status)) {
1302 if (client_name && server_name &&
1303 (*minor_status == (OM_uint32)KRB5KRB_AP_ERR_BAD_INTEGRITY)) {
1304 char *c_name = NULL;
1305 char *s_name = NULL;
1306 krb5_error_code cret, sret;
1307 cret = krb5_unparse_name(context, (krb5_principal) client_name,
1308 &c_name);
1309 sret = krb5_unparse_name(context, (krb5_principal) server_name,
1310 &s_name);
1311 krb5_set_error_message(context, *minor_status,
1312 dgettext(TEXT_DOMAIN,
1313 "Decrypt integrity check failed for client '%s' and server '%s'"),
1314 cret == 0 ? c_name : "unknown",
1315 sret == 0 ? s_name : "unknown");
1316 if (s_name)
1317 krb5_free_unparsed_name(context, s_name);
1318 if (c_name)
1319 krb5_free_unparsed_name(context, c_name);
1320 }
1321 /*
1322 * Solaris Kerberos
1323 * krb5_gss_acquire_cred() does not take a context arg
1324 * (and does a save_error_info() itself) so re-calling
1325 * save_error_info() here is trouble.
1326 */
1327 if (!acquire_fail)
1328 save_error_info(*minor_status, context);
1329 }
1330 if (client_name) {
1331 (void) kg_delete_name((gss_name_t) client_name);
1332 }
1333 if (server_name)
1334 krb5_free_principal(context, server_name);
1335 krb5_free_context(context);
1336
1337 /* Solaris Kerberos */
1338 KRB5_LOG(KRB5_ERR,"krb5_gss_accept_sec_context() end, "
1339 "major_status = %d", major_status);
1340 return (major_status);
1341 }
1342