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