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