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