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