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