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