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