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