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