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