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