1/* 2 * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "gsskrb5_locl.h" 35 36/* 37 * copy the addresses from `input_chan_bindings' (if any) to 38 * the auth context `ac' 39 */ 40 41static OM_uint32 42set_addresses (krb5_context context, 43 krb5_auth_context ac, 44 const gss_channel_bindings_t input_chan_bindings) 45{ 46 /* Port numbers are expected to be in application_data.value, 47 * initator's port first */ 48 49 krb5_address initiator_addr, acceptor_addr; 50 krb5_error_code kret; 51 52 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS 53 || input_chan_bindings->application_data.length != 54 2 * sizeof(ac->local_port)) 55 return 0; 56 57 memset(&initiator_addr, 0, sizeof(initiator_addr)); 58 memset(&acceptor_addr, 0, sizeof(acceptor_addr)); 59 60 ac->local_port = 61 *(int16_t *) input_chan_bindings->application_data.value; 62 63 ac->remote_port = 64 *((int16_t *) input_chan_bindings->application_data.value + 1); 65 66 kret = _gsskrb5i_address_to_krb5addr(context, 67 input_chan_bindings->acceptor_addrtype, 68 &input_chan_bindings->acceptor_address, 69 ac->remote_port, 70 &acceptor_addr); 71 if (kret) 72 return kret; 73 74 kret = _gsskrb5i_address_to_krb5addr(context, 75 input_chan_bindings->initiator_addrtype, 76 &input_chan_bindings->initiator_address, 77 ac->local_port, 78 &initiator_addr); 79 if (kret) { 80 krb5_free_address (context, &acceptor_addr); 81 return kret; 82 } 83 84 kret = krb5_auth_con_setaddrs(context, 85 ac, 86 &initiator_addr, /* local address */ 87 &acceptor_addr); /* remote address */ 88 89 krb5_free_address (context, &initiator_addr); 90 krb5_free_address (context, &acceptor_addr); 91 92#if 0 93 free(input_chan_bindings->application_data.value); 94 input_chan_bindings->application_data.value = NULL; 95 input_chan_bindings->application_data.length = 0; 96#endif 97 98 return kret; 99} 100 101OM_uint32 102_gsskrb5_create_ctx( 103 OM_uint32 * minor_status, 104 gss_ctx_id_t * context_handle, 105 krb5_context context, 106 const gss_channel_bindings_t input_chan_bindings, 107 enum gss_ctx_id_t_state state) 108{ 109 krb5_error_code kret; 110 gsskrb5_ctx ctx; 111 112 *context_handle = NULL; 113 114 ctx = malloc(sizeof(*ctx)); 115 if (ctx == NULL) { 116 *minor_status = ENOMEM; 117 return GSS_S_FAILURE; 118 } 119 ctx->auth_context = NULL; 120 ctx->source = NULL; 121 ctx->target = NULL; 122 ctx->kcred = NULL; 123 ctx->ccache = NULL; 124 ctx->state = state; 125 ctx->flags = 0; 126 ctx->more_flags = 0; 127 ctx->service_keyblock = NULL; 128 ctx->ticket = NULL; 129 krb5_data_zero(&ctx->fwd_data); 130 ctx->lifetime = GSS_C_INDEFINITE; 131 ctx->order = NULL; 132 ctx->crypto = NULL; 133 HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); 134 135 kret = krb5_auth_con_init (context, &ctx->auth_context); 136 if (kret) { 137 *minor_status = kret; 138 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 139 return GSS_S_FAILURE; 140 } 141 142 kret = set_addresses(context, ctx->auth_context, input_chan_bindings); 143 if (kret) { 144 *minor_status = kret; 145 146 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 147 148 krb5_auth_con_free(context, ctx->auth_context); 149 150 return GSS_S_BAD_BINDINGS; 151 } 152 153 /* 154 * We need a sequence number 155 */ 156 157 krb5_auth_con_addflags(context, 158 ctx->auth_context, 159 KRB5_AUTH_CONTEXT_DO_SEQUENCE | 160 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, 161 NULL); 162 163 *context_handle = (gss_ctx_id_t)ctx; 164 165 return GSS_S_COMPLETE; 166} 167 168 169static OM_uint32 170gsskrb5_get_creds( 171 OM_uint32 * minor_status, 172 krb5_context context, 173 krb5_ccache ccache, 174 gsskrb5_ctx ctx, 175 const gss_name_t target_name, 176 int use_dns, 177 OM_uint32 time_req, 178 OM_uint32 * time_rec, 179 krb5_creds ** cred) 180{ 181 OM_uint32 ret; 182 krb5_error_code kret; 183 krb5_creds this_cred; 184 OM_uint32 lifetime_rec; 185 186 *cred = NULL; 187 188 if (ctx->target) { 189 krb5_free_principal(context, ctx->target); 190 ctx->target = NULL; 191 } 192 193 ret = _gsskrb5_canon_name(minor_status, context, use_dns, 194 ctx->source, target_name, &ctx->target); 195 if (ret) 196 return ret; 197 198 memset(&this_cred, 0, sizeof(this_cred)); 199 this_cred.client = ctx->source; 200 this_cred.server = ctx->target; 201 202 if (time_req && time_req != GSS_C_INDEFINITE) { 203 krb5_timestamp ts; 204 205 krb5_timeofday (context, &ts); 206 this_cred.times.endtime = ts + time_req; 207 } else { 208 this_cred.times.endtime = 0; 209 } 210 211 this_cred.session.keytype = KEYTYPE_NULL; 212 213 kret = krb5_get_credentials(context, 214 0, 215 ccache, 216 &this_cred, 217 cred); 218 if (kret) { 219 *minor_status = kret; 220 return GSS_S_FAILURE; 221 } 222 223 ctx->lifetime = (*cred)->times.endtime; 224 225 ret = _gsskrb5_lifetime_left(minor_status, context, 226 ctx->lifetime, &lifetime_rec); 227 if (ret) return ret; 228 229 if (lifetime_rec == 0) { 230 *minor_status = 0; 231 return GSS_S_CONTEXT_EXPIRED; 232 } 233 234 if (time_rec) *time_rec = lifetime_rec; 235 236 return GSS_S_COMPLETE; 237} 238 239static OM_uint32 240gsskrb5_initiator_ready( 241 OM_uint32 * minor_status, 242 gsskrb5_ctx ctx, 243 krb5_context context) 244{ 245 OM_uint32 ret; 246 int32_t seq_number; 247 int is_cfx = 0; 248 OM_uint32 flags = ctx->flags; 249 250 krb5_free_creds(context, ctx->kcred); 251 ctx->kcred = NULL; 252 253 if (ctx->more_flags & CLOSE_CCACHE) 254 krb5_cc_close(context, ctx->ccache); 255 ctx->ccache = NULL; 256 257 krb5_auth_getremoteseqnumber (context, ctx->auth_context, &seq_number); 258 259 _gsskrb5i_is_cfx(context, ctx, 0); 260 is_cfx = (ctx->more_flags & IS_CFX); 261 262 ret = _gssapi_msg_order_create(minor_status, 263 &ctx->order, 264 _gssapi_msg_order_f(flags), 265 seq_number, 0, is_cfx); 266 if (ret) return ret; 267 268 ctx->state = INITIATOR_READY; 269 ctx->more_flags |= OPEN; 270 271 return GSS_S_COMPLETE; 272} 273 274/* 275 * handle delegated creds in init-sec-context 276 */ 277 278static void 279do_delegation (krb5_context context, 280 krb5_auth_context ac, 281 krb5_ccache ccache, 282 krb5_creds *cred, 283 krb5_const_principal name, 284 krb5_data *fwd_data, 285 uint32_t flagmask, 286 uint32_t *flags) 287{ 288 krb5_creds creds; 289 KDCOptions fwd_flags; 290 krb5_error_code kret; 291 292 memset (&creds, 0, sizeof(creds)); 293 krb5_data_zero (fwd_data); 294 295 kret = krb5_cc_get_principal(context, ccache, &creds.client); 296 if (kret) 297 goto out; 298 299 kret = krb5_build_principal(context, 300 &creds.server, 301 strlen(creds.client->realm), 302 creds.client->realm, 303 KRB5_TGS_NAME, 304 creds.client->realm, 305 NULL); 306 if (kret) 307 goto out; 308 309 creds.times.endtime = 0; 310 311 memset(&fwd_flags, 0, sizeof(fwd_flags)); 312 fwd_flags.forwarded = 1; 313 fwd_flags.forwardable = 1; 314 315 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/ 316 name->name.name_string.len < 2) 317 goto out; 318 319 kret = krb5_get_forwarded_creds(context, 320 ac, 321 ccache, 322 KDCOptions2int(fwd_flags), 323 name->name.name_string.val[1], 324 &creds, 325 fwd_data); 326 327 out: 328 if (kret) 329 *flags &= ~flagmask; 330 else 331 *flags |= flagmask; 332 333 if (creds.client) 334 krb5_free_principal(context, creds.client); 335 if (creds.server) 336 krb5_free_principal(context, creds.server); 337} 338 339/* 340 * first stage of init-sec-context 341 */ 342 343static OM_uint32 344init_auth 345(OM_uint32 * minor_status, 346 gsskrb5_cred cred, 347 gsskrb5_ctx ctx, 348 krb5_context context, 349 gss_name_t name, 350 const gss_OID mech_type, 351 OM_uint32 req_flags, 352 OM_uint32 time_req, 353 const gss_buffer_t input_token, 354 gss_OID * actual_mech_type, 355 gss_buffer_t output_token, 356 OM_uint32 * ret_flags, 357 OM_uint32 * time_rec 358 ) 359{ 360 OM_uint32 ret = GSS_S_FAILURE; 361 krb5_error_code kret; 362 krb5_data outbuf; 363 krb5_data fwd_data; 364 OM_uint32 lifetime_rec; 365 int allow_dns = 1; 366 367 krb5_data_zero(&outbuf); 368 krb5_data_zero(&fwd_data); 369 370 *minor_status = 0; 371 372 if (actual_mech_type) 373 *actual_mech_type = GSS_KRB5_MECHANISM; 374 375 if (cred == NULL) { 376 kret = krb5_cc_default (context, &ctx->ccache); 377 if (kret) { 378 *minor_status = kret; 379 ret = GSS_S_FAILURE; 380 goto failure; 381 } 382 ctx->more_flags |= CLOSE_CCACHE; 383 } else 384 ctx->ccache = cred->ccache; 385 386 kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source); 387 if (kret) { 388 *minor_status = kret; 389 ret = GSS_S_FAILURE; 390 goto failure; 391 } 392 393 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 394 if (ret) 395 goto failure; 396 397 398 /* 399 * This is hideous glue for (NFS) clients that wants to limit the 400 * available enctypes to what it can support (encryption in 401 * kernel). If there is no enctypes selected for this credential, 402 * reset it to the default set of enctypes. 403 */ 404 { 405 krb5_enctype *enctypes = NULL; 406 407 if (cred && cred->enctypes) 408 enctypes = cred->enctypes; 409 krb5_set_default_in_tkt_etypes(context, enctypes); 410 } 411 412 /* canon name if needed for client + target realm */ 413 kret = krb5_cc_get_config(context, ctx->ccache, NULL, 414 "realm-config", &outbuf); 415 if (kret == 0) { 416 /* XXX 2 is no server canon */ 417 if (outbuf.length < 1 || ((((unsigned char *)outbuf.data)[0]) & 2)) 418 allow_dns = 0; 419 krb5_data_free(&outbuf); 420 } 421 422 /* 423 * First we try w/o dns, hope that the KDC have register alias 424 * (and referrals if cross realm) for this principal. If that 425 * fails and if we are allowed to using this realm try again with 426 * DNS canonicalizion. 427 */ 428 ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, 429 ctx, name, 0, time_req, 430 time_rec, &ctx->kcred); 431 if (ret && allow_dns) 432 ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, 433 ctx, name, 1, time_req, 434 time_rec, &ctx->kcred); 435 if (ret) 436 goto failure; 437 438 ctx->lifetime = ctx->kcred->times.endtime; 439 440 ret = _gsskrb5_lifetime_left(minor_status, 441 context, 442 ctx->lifetime, 443 &lifetime_rec); 444 if (ret) 445 goto failure; 446 447 if (lifetime_rec == 0) { 448 *minor_status = 0; 449 ret = GSS_S_CONTEXT_EXPIRED; 450 goto failure; 451 } 452 453 krb5_auth_con_setkey(context, 454 ctx->auth_context, 455 &ctx->kcred->session); 456 457 kret = krb5_auth_con_generatelocalsubkey(context, 458 ctx->auth_context, 459 &ctx->kcred->session); 460 if(kret) { 461 *minor_status = kret; 462 ret = GSS_S_FAILURE; 463 goto failure; 464 } 465 466 return GSS_S_COMPLETE; 467 468failure: 469 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) 470 krb5_cc_close(context, ctx->ccache); 471 ctx->ccache = NULL; 472 473 return ret; 474 475} 476 477static OM_uint32 478init_auth_restart 479(OM_uint32 * minor_status, 480 gsskrb5_cred cred, 481 gsskrb5_ctx ctx, 482 krb5_context context, 483 OM_uint32 req_flags, 484 const gss_channel_bindings_t input_chan_bindings, 485 const gss_buffer_t input_token, 486 gss_OID * actual_mech_type, 487 gss_buffer_t output_token, 488 OM_uint32 * ret_flags, 489 OM_uint32 * time_rec 490 ) 491{ 492 OM_uint32 ret = GSS_S_FAILURE; 493 krb5_error_code kret; 494 krb5_flags ap_options; 495 krb5_data outbuf; 496 uint32_t flags; 497 krb5_data authenticator; 498 Checksum cksum; 499 krb5_enctype enctype; 500 krb5_data fwd_data, timedata; 501 int32_t offset = 0, oldoffset; 502 uint32_t flagmask; 503 504 krb5_data_zero(&outbuf); 505 krb5_data_zero(&fwd_data); 506 507 *minor_status = 0; 508 509 /* 510 * If the credential doesn't have ok-as-delegate, check if there 511 * is a realm setting and use that. 512 */ 513 if (!ctx->kcred->flags.b.ok_as_delegate) { 514 krb5_data data; 515 516 ret = krb5_cc_get_config(context, ctx->ccache, NULL, 517 "realm-config", &data); 518 if (ret == 0) { 519 /* XXX 1 is use ok-as-delegate */ 520 if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0) 521 req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); 522 krb5_data_free(&data); 523 } 524 } 525 526 flagmask = 0; 527 528 /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */ 529 if ((req_flags & GSS_C_DELEG_POLICY_FLAG) 530 && ctx->kcred->flags.b.ok_as_delegate) 531 flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG; 532 /* if there still is a GSS_C_DELEG_FLAG, use that */ 533 if (req_flags & GSS_C_DELEG_FLAG) 534 flagmask |= GSS_C_DELEG_FLAG; 535 536 537 flags = 0; 538 ap_options = 0; 539 if (flagmask & GSS_C_DELEG_FLAG) { 540 do_delegation (context, 541 ctx->auth_context, 542 ctx->ccache, ctx->kcred, ctx->target, 543 &fwd_data, flagmask, &flags); 544 } 545 546 if (req_flags & GSS_C_MUTUAL_FLAG) { 547 flags |= GSS_C_MUTUAL_FLAG; 548 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 549 } 550 551 if (req_flags & GSS_C_REPLAY_FLAG) 552 flags |= GSS_C_REPLAY_FLAG; 553 if (req_flags & GSS_C_SEQUENCE_FLAG) 554 flags |= GSS_C_SEQUENCE_FLAG; 555#if 0 556 if (req_flags & GSS_C_ANON_FLAG) 557 ; /* XXX */ 558#endif 559 if (req_flags & GSS_C_DCE_STYLE) { 560 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ 561 flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; 562 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 563 } 564 if (req_flags & GSS_C_IDENTIFY_FLAG) 565 flags |= GSS_C_IDENTIFY_FLAG; 566 if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) 567 flags |= GSS_C_EXTENDED_ERROR_FLAG; 568 569 if (req_flags & GSS_C_CONF_FLAG) { 570 flags |= GSS_C_CONF_FLAG; 571 } 572 if (req_flags & GSS_C_INTEG_FLAG) { 573 flags |= GSS_C_INTEG_FLAG; 574 } 575 if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) { 576 flags |= GSS_C_CONF_FLAG; 577 flags |= GSS_C_INTEG_FLAG; 578 } 579 flags |= GSS_C_TRANS_FLAG; 580 581 if (ret_flags) 582 *ret_flags = flags; 583 ctx->flags = flags; 584 ctx->more_flags |= LOCAL; 585 586 ret = _gsskrb5_create_8003_checksum (minor_status, 587 input_chan_bindings, 588 flags, 589 &fwd_data, 590 &cksum); 591 krb5_data_free (&fwd_data); 592 if (ret) 593 goto failure; 594 595 enctype = ctx->auth_context->keyblock->keytype; 596 597 ret = krb5_cc_get_config(context, ctx->ccache, ctx->target, 598 "time-offset", &timedata); 599 if (ret == 0) { 600 if (timedata.length == 4) { 601 const u_char *p = timedata.data; 602 offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); 603 } 604 krb5_data_free(&timedata); 605 } 606 607 if (offset) { 608 krb5_get_kdc_sec_offset (context, &oldoffset, NULL); 609 krb5_set_kdc_sec_offset (context, offset, -1); 610 } 611 612 kret = krb5_build_authenticator (context, 613 ctx->auth_context, 614 enctype, 615 ctx->kcred, 616 &cksum, 617 NULL, 618 &authenticator, 619 KRB5_KU_AP_REQ_AUTH); 620 621 if (kret) { 622 if (offset) 623 krb5_set_kdc_sec_offset (context, oldoffset, -1); 624 *minor_status = kret; 625 ret = GSS_S_FAILURE; 626 goto failure; 627 } 628 629 kret = krb5_build_ap_req (context, 630 enctype, 631 ctx->kcred, 632 ap_options, 633 authenticator, 634 &outbuf); 635 if (offset) 636 krb5_set_kdc_sec_offset (context, oldoffset, -1); 637 if (kret) { 638 *minor_status = kret; 639 ret = GSS_S_FAILURE; 640 goto failure; 641 } 642 643 if (flags & GSS_C_DCE_STYLE) { 644 output_token->value = outbuf.data; 645 output_token->length = outbuf.length; 646 } else { 647 ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, 648 (u_char *)"\x01\x00", GSS_KRB5_MECHANISM); 649 krb5_data_free (&outbuf); 650 if (ret) 651 goto failure; 652 } 653 654 free_Checksum(&cksum); 655 656 if (flags & GSS_C_MUTUAL_FLAG) { 657 ctx->state = INITIATOR_WAIT_FOR_MUTAL; 658 return GSS_S_CONTINUE_NEEDED; 659 } 660 661 return gsskrb5_initiator_ready(minor_status, ctx, context); 662failure: 663 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) 664 krb5_cc_close(context, ctx->ccache); 665 ctx->ccache = NULL; 666 667 return ret; 668} 669 670 671static OM_uint32 672repl_mutual 673(OM_uint32 * minor_status, 674 gsskrb5_ctx ctx, 675 krb5_context context, 676 const gss_OID mech_type, 677 OM_uint32 req_flags, 678 OM_uint32 time_req, 679 const gss_channel_bindings_t input_chan_bindings, 680 const gss_buffer_t input_token, 681 gss_OID * actual_mech_type, 682 gss_buffer_t output_token, 683 OM_uint32 * ret_flags, 684 OM_uint32 * time_rec 685 ) 686{ 687 OM_uint32 ret; 688 krb5_error_code kret; 689 krb5_data indata; 690 krb5_ap_rep_enc_part *repl; 691 692 output_token->length = 0; 693 output_token->value = NULL; 694 695 if (actual_mech_type) 696 *actual_mech_type = GSS_KRB5_MECHANISM; 697 698 if (IS_DCE_STYLE(ctx)) { 699 /* There is no OID wrapping. */ 700 indata.length = input_token->length; 701 indata.data = input_token->value; 702 } else { 703 ret = _gsskrb5_decapsulate (minor_status, 704 input_token, 705 &indata, 706 "\x02\x00", 707 GSS_KRB5_MECHANISM); 708 if (ret == GSS_S_DEFECTIVE_TOKEN) { 709 /* check if there is an error token sent instead */ 710 ret = _gsskrb5_decapsulate (minor_status, 711 input_token, 712 &indata, 713 "\x03\x00", 714 GSS_KRB5_MECHANISM); 715 if (ret == GSS_S_COMPLETE) { 716 KRB_ERROR error; 717 718 kret = krb5_rd_error(context, &indata, &error); 719 if (kret == 0) { 720 kret = krb5_error_from_rd_error(context, &error, NULL); 721 722 /* save the time skrew for this host */ 723 if (kret == KRB5KRB_AP_ERR_SKEW) { 724 krb5_data timedata; 725 unsigned char p[4]; 726 int32_t t = error.stime - time(NULL); 727 728 p[0] = (t >> 24) & 0xFF; 729 p[1] = (t >> 16) & 0xFF; 730 p[2] = (t >> 8) & 0xFF; 731 p[3] = (t >> 0) & 0xFF; 732 733 timedata.data = p; 734 timedata.length = sizeof(p); 735 736 krb5_cc_set_config(context, ctx->ccache, ctx->target, 737 "time-offset", &timedata); 738 739 if ((ctx->more_flags & RETRIED) == 0) 740 ctx->state = INITIATOR_RESTART; 741 ctx->more_flags |= RETRIED; 742 } 743 free_KRB_ERROR (&error); 744 } 745 *minor_status = kret; 746 return GSS_S_FAILURE; 747 } 748 return ret; 749 } 750 } 751 752 kret = krb5_rd_rep (context, 753 ctx->auth_context, 754 &indata, 755 &repl); 756 if (kret) { 757 *minor_status = kret; 758 return GSS_S_FAILURE; 759 } 760 krb5_free_ap_rep_enc_part (context, 761 repl); 762 763 *minor_status = 0; 764 if (time_rec) { 765 ret = _gsskrb5_lifetime_left(minor_status, 766 context, 767 ctx->lifetime, 768 time_rec); 769 } else { 770 ret = GSS_S_COMPLETE; 771 } 772 if (ret_flags) 773 *ret_flags = ctx->flags; 774 775 if (req_flags & GSS_C_DCE_STYLE) { 776 int32_t local_seq, remote_seq; 777 krb5_data outbuf; 778 779 /* 780 * So DCE_STYLE is strange. The client echos the seq number 781 * that the server used in the server's mk_rep in its own 782 * mk_rep(). After when done, it resets to it's own seq number 783 * for the gss_wrap calls. 784 */ 785 786 krb5_auth_getremoteseqnumber(context, ctx->auth_context, &remote_seq); 787 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq); 788 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq); 789 790 kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); 791 if (kret) { 792 *minor_status = kret; 793 return GSS_S_FAILURE; 794 } 795 796 /* reset local seq number */ 797 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq); 798 799 output_token->length = outbuf.length; 800 output_token->value = outbuf.data; 801 } 802 803 return gsskrb5_initiator_ready(minor_status, ctx, context); 804} 805 806/* 807 * gss_init_sec_context 808 */ 809 810OM_uint32 _gsskrb5_init_sec_context 811(OM_uint32 * minor_status, 812 const gss_cred_id_t cred_handle, 813 gss_ctx_id_t * context_handle, 814 const gss_name_t target_name, 815 const gss_OID mech_type, 816 OM_uint32 req_flags, 817 OM_uint32 time_req, 818 const gss_channel_bindings_t input_chan_bindings, 819 const gss_buffer_t input_token, 820 gss_OID * actual_mech_type, 821 gss_buffer_t output_token, 822 OM_uint32 * ret_flags, 823 OM_uint32 * time_rec 824 ) 825{ 826 krb5_context context; 827 gsskrb5_cred cred = (gsskrb5_cred)cred_handle; 828 gsskrb5_ctx ctx; 829 OM_uint32 ret; 830 831 GSSAPI_KRB5_INIT (&context); 832 833 output_token->length = 0; 834 output_token->value = NULL; 835 836 if (context_handle == NULL) { 837 *minor_status = 0; 838 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 839 } 840 841 if (ret_flags) 842 *ret_flags = 0; 843 if (time_rec) 844 *time_rec = 0; 845 846 if (target_name == GSS_C_NO_NAME) { 847 if (actual_mech_type) 848 *actual_mech_type = GSS_C_NO_OID; 849 *minor_status = 0; 850 return GSS_S_BAD_NAME; 851 } 852 853 if (mech_type != GSS_C_NO_OID && 854 !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) 855 return GSS_S_BAD_MECH; 856 857 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { 858 OM_uint32 ret; 859 860 if (*context_handle != GSS_C_NO_CONTEXT) { 861 *minor_status = 0; 862 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 863 } 864 865 ret = _gsskrb5_create_ctx(minor_status, 866 context_handle, 867 context, 868 input_chan_bindings, 869 INITIATOR_START); 870 if (ret) 871 return ret; 872 } 873 874 if (*context_handle == GSS_C_NO_CONTEXT) { 875 *minor_status = 0; 876 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 877 } 878 879 ctx = (gsskrb5_ctx) *context_handle; 880 881 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 882 883 again: 884 switch (ctx->state) { 885 case INITIATOR_START: 886 ret = init_auth(minor_status, 887 cred, 888 ctx, 889 context, 890 target_name, 891 mech_type, 892 req_flags, 893 time_req, 894 input_token, 895 actual_mech_type, 896 output_token, 897 ret_flags, 898 time_rec); 899 if (ret != GSS_S_COMPLETE) 900 break; 901 /* FALL THOUGH */ 902 case INITIATOR_RESTART: 903 ret = init_auth_restart(minor_status, 904 cred, 905 ctx, 906 context, 907 req_flags, 908 input_chan_bindings, 909 input_token, 910 actual_mech_type, 911 output_token, 912 ret_flags, 913 time_rec); 914 break; 915 case INITIATOR_WAIT_FOR_MUTAL: 916 ret = repl_mutual(minor_status, 917 ctx, 918 context, 919 mech_type, 920 req_flags, 921 time_req, 922 input_chan_bindings, 923 input_token, 924 actual_mech_type, 925 output_token, 926 ret_flags, 927 time_rec); 928 if (ctx->state == INITIATOR_RESTART) 929 goto again; 930 break; 931 case INITIATOR_READY: 932 /* 933 * If we get there, the caller have called 934 * gss_init_sec_context() one time too many. 935 */ 936 _gsskrb5_set_status(EINVAL, "init_sec_context " 937 "called one time too many"); 938 *minor_status = EINVAL; 939 ret = GSS_S_BAD_STATUS; 940 break; 941 default: 942 _gsskrb5_set_status(EINVAL, "init_sec_context " 943 "invalid state %d for client", 944 (int)ctx->state); 945 *minor_status = EINVAL; 946 ret = GSS_S_BAD_STATUS; 947 break; 948 } 949 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 950 951 /* destroy context in case of error */ 952 if (GSS_ERROR(ret)) { 953 OM_uint32 min2; 954 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 955 } 956 957 return ret; 958 959} 960