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