1 /* 2 * Copyright (c) 1997 - 2007 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 "krb5/gsskrb5_locl.h" 35 36 RCSID("$Id: init_sec_context.c 22071 2007-11-14 20:04:50Z lha $"); 37 38 /* 39 * copy the addresses from `input_chan_bindings' (if any) to 40 * the auth context `ac' 41 */ 42 43 static OM_uint32 44 set_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 103 OM_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->source = NULL; 123 ctx->target = 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 HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); 133 134 kret = krb5_auth_con_init (context, &ctx->auth_context); 135 if (kret) { 136 *minor_status = kret; 137 138 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 139 140 return GSS_S_FAILURE; 141 } 142 143 kret = set_addresses(context, ctx->auth_context, input_chan_bindings); 144 if (kret) { 145 *minor_status = kret; 146 147 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 148 149 krb5_auth_con_free(context, ctx->auth_context); 150 151 return GSS_S_BAD_BINDINGS; 152 } 153 154 /* 155 * We need a sequence number 156 */ 157 158 krb5_auth_con_addflags(context, 159 ctx->auth_context, 160 KRB5_AUTH_CONTEXT_DO_SEQUENCE | 161 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, 162 NULL); 163 164 *context_handle = (gss_ctx_id_t)ctx; 165 166 return GSS_S_COMPLETE; 167 } 168 169 170 static OM_uint32 171 gsskrb5_get_creds( 172 OM_uint32 * minor_status, 173 krb5_context context, 174 krb5_ccache ccache, 175 gsskrb5_ctx ctx, 176 krb5_const_principal target_name, 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 memset(&this_cred, 0, sizeof(this_cred)); 189 this_cred.client = ctx->source; 190 this_cred.server = ctx->target; 191 192 if (time_req && time_req != GSS_C_INDEFINITE) { 193 krb5_timestamp ts; 194 195 krb5_timeofday (context, &ts); 196 this_cred.times.endtime = ts + time_req; 197 } else { 198 this_cred.times.endtime = 0; 199 } 200 201 this_cred.session.keytype = KEYTYPE_NULL; 202 203 kret = krb5_get_credentials(context, 204 0, 205 ccache, 206 &this_cred, 207 cred); 208 if (kret) { 209 *minor_status = kret; 210 return GSS_S_FAILURE; 211 } 212 213 ctx->lifetime = (*cred)->times.endtime; 214 215 ret = _gsskrb5_lifetime_left(minor_status, context, 216 ctx->lifetime, &lifetime_rec); 217 if (ret) return ret; 218 219 if (lifetime_rec == 0) { 220 *minor_status = 0; 221 return GSS_S_CONTEXT_EXPIRED; 222 } 223 224 if (time_rec) *time_rec = lifetime_rec; 225 226 return GSS_S_COMPLETE; 227 } 228 229 static OM_uint32 230 gsskrb5_initiator_ready( 231 OM_uint32 * minor_status, 232 gsskrb5_ctx ctx, 233 krb5_context context) 234 { 235 OM_uint32 ret; 236 int32_t seq_number; 237 int is_cfx = 0; 238 OM_uint32 flags = ctx->flags; 239 240 krb5_auth_getremoteseqnumber (context, 241 ctx->auth_context, 242 &seq_number); 243 244 _gsskrb5i_is_cfx(ctx, &is_cfx); 245 246 ret = _gssapi_msg_order_create(minor_status, 247 &ctx->order, 248 _gssapi_msg_order_f(flags), 249 seq_number, 0, is_cfx); 250 if (ret) return ret; 251 252 ctx->state = INITIATOR_READY; 253 ctx->more_flags |= OPEN; 254 255 return GSS_S_COMPLETE; 256 } 257 258 /* 259 * handle delegated creds in init-sec-context 260 */ 261 262 static void 263 do_delegation (krb5_context context, 264 krb5_auth_context ac, 265 krb5_ccache ccache, 266 krb5_creds *cred, 267 krb5_const_principal name, 268 krb5_data *fwd_data, 269 uint32_t *flags) 270 { 271 krb5_creds creds; 272 KDCOptions fwd_flags; 273 krb5_error_code kret; 274 275 memset (&creds, 0, sizeof(creds)); 276 krb5_data_zero (fwd_data); 277 278 kret = krb5_cc_get_principal(context, ccache, &creds.client); 279 if (kret) 280 goto out; 281 282 kret = krb5_build_principal(context, 283 &creds.server, 284 strlen(creds.client->realm), 285 creds.client->realm, 286 KRB5_TGS_NAME, 287 creds.client->realm, 288 NULL); 289 if (kret) 290 goto out; 291 292 creds.times.endtime = 0; 293 294 memset(&fwd_flags, 0, sizeof(fwd_flags)); 295 fwd_flags.forwarded = 1; 296 fwd_flags.forwardable = 1; 297 298 if ( /*target_name->name.name_type != KRB5_NT_SRV_HST ||*/ 299 name->name.name_string.len < 2) 300 goto out; 301 302 kret = krb5_get_forwarded_creds(context, 303 ac, 304 ccache, 305 KDCOptions2int(fwd_flags), 306 name->name.name_string.val[1], 307 &creds, 308 fwd_data); 309 310 out: 311 if (kret) 312 *flags &= ~GSS_C_DELEG_FLAG; 313 else 314 *flags |= GSS_C_DELEG_FLAG; 315 316 if (creds.client) 317 krb5_free_principal(context, creds.client); 318 if (creds.server) 319 krb5_free_principal(context, creds.server); 320 } 321 322 /* 323 * first stage of init-sec-context 324 */ 325 326 static OM_uint32 327 init_auth 328 (OM_uint32 * minor_status, 329 gsskrb5_cred initiator_cred_handle, 330 gsskrb5_ctx ctx, 331 krb5_context context, 332 krb5_const_principal name, 333 const gss_OID mech_type, 334 OM_uint32 req_flags, 335 OM_uint32 time_req, 336 const gss_channel_bindings_t input_chan_bindings, 337 const gss_buffer_t input_token, 338 gss_OID * actual_mech_type, 339 gss_buffer_t output_token, 340 OM_uint32 * ret_flags, 341 OM_uint32 * time_rec 342 ) 343 { 344 OM_uint32 ret = GSS_S_FAILURE; 345 krb5_error_code kret; 346 krb5_flags ap_options; 347 krb5_creds *cred = NULL; 348 krb5_data outbuf; 349 krb5_ccache ccache = NULL; 350 uint32_t flags; 351 krb5_data authenticator; 352 Checksum cksum; 353 krb5_enctype enctype; 354 krb5_data fwd_data; 355 OM_uint32 lifetime_rec; 356 357 krb5_data_zero(&outbuf); 358 krb5_data_zero(&fwd_data); 359 360 *minor_status = 0; 361 362 if (actual_mech_type) 363 *actual_mech_type = GSS_KRB5_MECHANISM; 364 365 if (initiator_cred_handle == NULL) { 366 kret = krb5_cc_default (context, &ccache); 367 if (kret) { 368 *minor_status = kret; 369 ret = GSS_S_FAILURE; 370 goto failure; 371 } 372 } else 373 ccache = initiator_cred_handle->ccache; 374 375 kret = krb5_cc_get_principal (context, ccache, &ctx->source); 376 if (kret) { 377 *minor_status = kret; 378 ret = GSS_S_FAILURE; 379 goto failure; 380 } 381 382 kret = krb5_copy_principal (context, name, &ctx->target); 383 if (kret) { 384 *minor_status = kret; 385 ret = GSS_S_FAILURE; 386 goto failure; 387 } 388 389 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 390 if (ret) 391 goto failure; 392 393 394 /* 395 * This is hideous glue for (NFS) clients that wants to limit the 396 * available enctypes to what it can support (encryption in 397 * kernel). If there is no enctypes selected for this credential, 398 * reset it to the default set of enctypes. 399 */ 400 { 401 krb5_enctype *enctypes = NULL; 402 403 if (initiator_cred_handle && initiator_cred_handle->enctypes) 404 enctypes = initiator_cred_handle->enctypes; 405 krb5_set_default_in_tkt_etypes(context, enctypes); 406 } 407 408 ret = gsskrb5_get_creds(minor_status, 409 context, 410 ccache, 411 ctx, 412 ctx->target, 413 time_req, 414 time_rec, 415 &cred); 416 if (ret) 417 goto failure; 418 419 ctx->lifetime = cred->times.endtime; 420 421 ret = _gsskrb5_lifetime_left(minor_status, 422 context, 423 ctx->lifetime, 424 &lifetime_rec); 425 if (ret) { 426 goto failure; 427 } 428 429 if (lifetime_rec == 0) { 430 *minor_status = 0; 431 ret = GSS_S_CONTEXT_EXPIRED; 432 goto failure; 433 } 434 435 krb5_auth_con_setkey(context, 436 ctx->auth_context, 437 &cred->session); 438 439 kret = krb5_auth_con_generatelocalsubkey(context, 440 ctx->auth_context, 441 &cred->session); 442 if(kret) { 443 *minor_status = kret; 444 ret = GSS_S_FAILURE; 445 goto failure; 446 } 447 448 /* 449 * If the credential doesn't have ok-as-delegate, check what local 450 * policy say about ok-as-delegate, default is FALSE that makes 451 * code ignore the KDC setting and follow what the application 452 * requested. If it is TRUE, strip of the GSS_C_DELEG_FLAG if the 453 * KDC doesn't set ok-as-delegate. 454 */ 455 if (!cred->flags.b.ok_as_delegate) { 456 krb5_boolean delegate; 457 458 krb5_appdefault_boolean(context, 459 "gssapi", name->realm, 460 "ok-as-delegate", FALSE, &delegate); 461 if (delegate) 462 req_flags &= ~GSS_C_DELEG_FLAG; 463 } 464 465 flags = 0; 466 ap_options = 0; 467 if (req_flags & GSS_C_DELEG_FLAG) 468 do_delegation (context, 469 ctx->auth_context, 470 ccache, cred, name, &fwd_data, &flags); 471 472 if (req_flags & GSS_C_MUTUAL_FLAG) { 473 flags |= GSS_C_MUTUAL_FLAG; 474 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 475 } 476 477 if (req_flags & GSS_C_REPLAY_FLAG) 478 flags |= GSS_C_REPLAY_FLAG; 479 if (req_flags & GSS_C_SEQUENCE_FLAG) 480 flags |= GSS_C_SEQUENCE_FLAG; 481 if (req_flags & GSS_C_ANON_FLAG) 482 ; /* XXX */ 483 if (req_flags & GSS_C_DCE_STYLE) { 484 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ 485 flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; 486 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 487 } 488 if (req_flags & GSS_C_IDENTIFY_FLAG) 489 flags |= GSS_C_IDENTIFY_FLAG; 490 if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) 491 flags |= GSS_C_EXTENDED_ERROR_FLAG; 492 493 flags |= GSS_C_CONF_FLAG; 494 flags |= GSS_C_INTEG_FLAG; 495 flags |= GSS_C_TRANS_FLAG; 496 497 if (ret_flags) 498 *ret_flags = flags; 499 ctx->flags = flags; 500 ctx->more_flags |= LOCAL; 501 502 ret = _gsskrb5_create_8003_checksum (minor_status, 503 input_chan_bindings, 504 flags, 505 &fwd_data, 506 &cksum); 507 krb5_data_free (&fwd_data); 508 if (ret) 509 goto failure; 510 511 enctype = ctx->auth_context->keyblock->keytype; 512 513 kret = krb5_build_authenticator (context, 514 ctx->auth_context, 515 enctype, 516 cred, 517 &cksum, 518 NULL, 519 &authenticator, 520 KRB5_KU_AP_REQ_AUTH); 521 522 if (kret) { 523 *minor_status = kret; 524 ret = GSS_S_FAILURE; 525 goto failure; 526 } 527 528 kret = krb5_build_ap_req (context, 529 enctype, 530 cred, 531 ap_options, 532 authenticator, 533 &outbuf); 534 535 if (kret) { 536 *minor_status = kret; 537 ret = GSS_S_FAILURE; 538 goto failure; 539 } 540 541 ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, 542 (u_char *)"\x01\x00", GSS_KRB5_MECHANISM); 543 if (ret) 544 goto failure; 545 546 krb5_data_free (&outbuf); 547 krb5_free_creds(context, cred); 548 free_Checksum(&cksum); 549 if (initiator_cred_handle == NULL) 550 krb5_cc_close(context, ccache); 551 552 if (flags & GSS_C_MUTUAL_FLAG) { 553 ctx->state = INITIATOR_WAIT_FOR_MUTAL; 554 return GSS_S_CONTINUE_NEEDED; 555 } 556 557 return gsskrb5_initiator_ready(minor_status, ctx, context); 558 failure: 559 if(cred) 560 krb5_free_creds(context, cred); 561 if (ccache && initiator_cred_handle == NULL) 562 krb5_cc_close(context, ccache); 563 564 return ret; 565 566 } 567 568 static OM_uint32 569 repl_mutual 570 (OM_uint32 * minor_status, 571 gsskrb5_ctx ctx, 572 krb5_context context, 573 const gss_OID mech_type, 574 OM_uint32 req_flags, 575 OM_uint32 time_req, 576 const gss_channel_bindings_t input_chan_bindings, 577 const gss_buffer_t input_token, 578 gss_OID * actual_mech_type, 579 gss_buffer_t output_token, 580 OM_uint32 * ret_flags, 581 OM_uint32 * time_rec 582 ) 583 { 584 OM_uint32 ret; 585 krb5_error_code kret; 586 krb5_data indata; 587 krb5_ap_rep_enc_part *repl; 588 int is_cfx = 0; 589 590 output_token->length = 0; 591 output_token->value = NULL; 592 593 if (actual_mech_type) 594 *actual_mech_type = GSS_KRB5_MECHANISM; 595 596 if (ctx->flags & GSS_C_DCE_STYLE) { 597 /* There is no OID wrapping. */ 598 indata.length = input_token->length; 599 indata.data = input_token->value; 600 } else { 601 ret = _gsskrb5_decapsulate (minor_status, 602 input_token, 603 &indata, 604 "\x02\x00", 605 GSS_KRB5_MECHANISM); 606 if (ret) { 607 /* XXX - Handle AP_ERROR */ 608 return ret; 609 } 610 } 611 612 kret = krb5_rd_rep (context, 613 ctx->auth_context, 614 &indata, 615 &repl); 616 if (kret) { 617 *minor_status = kret; 618 return GSS_S_FAILURE; 619 } 620 krb5_free_ap_rep_enc_part (context, 621 repl); 622 623 _gsskrb5i_is_cfx(ctx, &is_cfx); 624 if (is_cfx) { 625 krb5_keyblock *key = NULL; 626 627 kret = krb5_auth_con_getremotesubkey(context, 628 ctx->auth_context, 629 &key); 630 if (kret == 0 && key != NULL) { 631 ctx->more_flags |= ACCEPTOR_SUBKEY; 632 krb5_free_keyblock (context, key); 633 } 634 } 635 636 637 *minor_status = 0; 638 if (time_rec) { 639 ret = _gsskrb5_lifetime_left(minor_status, 640 context, 641 ctx->lifetime, 642 time_rec); 643 } else { 644 ret = GSS_S_COMPLETE; 645 } 646 if (ret_flags) 647 *ret_flags = ctx->flags; 648 649 if (req_flags & GSS_C_DCE_STYLE) { 650 int32_t con_flags; 651 krb5_data outbuf; 652 653 /* Do don't do sequence number for the mk-rep */ 654 krb5_auth_con_removeflags(context, 655 ctx->auth_context, 656 KRB5_AUTH_CONTEXT_DO_SEQUENCE, 657 &con_flags); 658 659 kret = krb5_mk_rep(context, 660 ctx->auth_context, 661 &outbuf); 662 if (kret) { 663 *minor_status = kret; 664 return GSS_S_FAILURE; 665 } 666 667 output_token->length = outbuf.length; 668 output_token->value = outbuf.data; 669 670 krb5_auth_con_removeflags(context, 671 ctx->auth_context, 672 KRB5_AUTH_CONTEXT_DO_SEQUENCE, 673 NULL); 674 } 675 676 return gsskrb5_initiator_ready(minor_status, ctx, context); 677 } 678 679 /* 680 * gss_init_sec_context 681 */ 682 683 OM_uint32 _gsskrb5_init_sec_context 684 (OM_uint32 * minor_status, 685 const gss_cred_id_t initiator_cred_handle, 686 gss_ctx_id_t * context_handle, 687 const gss_name_t target_name, 688 const gss_OID mech_type, 689 OM_uint32 req_flags, 690 OM_uint32 time_req, 691 const gss_channel_bindings_t input_chan_bindings, 692 const gss_buffer_t input_token, 693 gss_OID * actual_mech_type, 694 gss_buffer_t output_token, 695 OM_uint32 * ret_flags, 696 OM_uint32 * time_rec 697 ) 698 { 699 krb5_context context; 700 gsskrb5_cred cred = (gsskrb5_cred)initiator_cred_handle; 701 krb5_const_principal name = (krb5_const_principal)target_name; 702 gsskrb5_ctx ctx; 703 OM_uint32 ret; 704 705 GSSAPI_KRB5_INIT (&context); 706 707 output_token->length = 0; 708 output_token->value = NULL; 709 710 if (context_handle == NULL) { 711 *minor_status = 0; 712 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 713 } 714 715 if (ret_flags) 716 *ret_flags = 0; 717 if (time_rec) 718 *time_rec = 0; 719 720 if (target_name == GSS_C_NO_NAME) { 721 if (actual_mech_type) 722 *actual_mech_type = GSS_C_NO_OID; 723 *minor_status = 0; 724 return GSS_S_BAD_NAME; 725 } 726 727 if (mech_type != GSS_C_NO_OID && 728 !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) 729 return GSS_S_BAD_MECH; 730 731 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { 732 OM_uint32 ret; 733 734 if (*context_handle != GSS_C_NO_CONTEXT) { 735 *minor_status = 0; 736 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 737 } 738 739 ret = _gsskrb5_create_ctx(minor_status, 740 context_handle, 741 context, 742 input_chan_bindings, 743 INITIATOR_START); 744 if (ret) 745 return ret; 746 } 747 748 if (*context_handle == GSS_C_NO_CONTEXT) { 749 *minor_status = 0; 750 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 751 } 752 753 ctx = (gsskrb5_ctx) *context_handle; 754 755 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 756 757 switch (ctx->state) { 758 case INITIATOR_START: 759 ret = init_auth(minor_status, 760 cred, 761 ctx, 762 context, 763 name, 764 mech_type, 765 req_flags, 766 time_req, 767 input_chan_bindings, 768 input_token, 769 actual_mech_type, 770 output_token, 771 ret_flags, 772 time_rec); 773 break; 774 case INITIATOR_WAIT_FOR_MUTAL: 775 ret = repl_mutual(minor_status, 776 ctx, 777 context, 778 mech_type, 779 req_flags, 780 time_req, 781 input_chan_bindings, 782 input_token, 783 actual_mech_type, 784 output_token, 785 ret_flags, 786 time_rec); 787 break; 788 case INITIATOR_READY: 789 /* 790 * If we get there, the caller have called 791 * gss_init_sec_context() one time too many. 792 */ 793 *minor_status = 0; 794 ret = GSS_S_BAD_STATUS; 795 break; 796 default: 797 *minor_status = 0; 798 ret = GSS_S_BAD_STATUS; 799 break; 800 } 801 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 802 803 /* destroy context in case of error */ 804 if (GSS_ERROR(ret)) { 805 OM_uint32 min2; 806 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 807 } 808 809 return ret; 810 811 } 812