1 /* 2 * Copyright (c) 1997 - 2006 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: accept_sec_context.c 20199 2007-02-07 22:36:39Z lha $"); 37 38 HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; 39 krb5_keytab _gsskrb5_keytab; 40 41 OM_uint32 42 _gsskrb5_register_acceptor_identity (const char *identity) 43 { 44 krb5_context context; 45 krb5_error_code ret; 46 47 ret = _gsskrb5_init(&context); 48 if(ret) 49 return GSS_S_FAILURE; 50 51 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); 52 53 if(_gsskrb5_keytab != NULL) { 54 krb5_kt_close(context, _gsskrb5_keytab); 55 _gsskrb5_keytab = NULL; 56 } 57 if (identity == NULL) { 58 ret = krb5_kt_default(context, &_gsskrb5_keytab); 59 } else { 60 char *p; 61 62 asprintf(&p, "FILE:%s", identity); 63 if(p == NULL) { 64 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 65 return GSS_S_FAILURE; 66 } 67 ret = krb5_kt_resolve(context, p, &_gsskrb5_keytab); 68 free(p); 69 } 70 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 71 if(ret) 72 return GSS_S_FAILURE; 73 return GSS_S_COMPLETE; 74 } 75 76 void 77 _gsskrb5i_is_cfx(gsskrb5_ctx ctx, int *is_cfx) 78 { 79 krb5_keyblock *key; 80 int acceptor = (ctx->more_flags & LOCAL) == 0; 81 82 *is_cfx = 0; 83 84 if (acceptor) { 85 if (ctx->auth_context->local_subkey) 86 key = ctx->auth_context->local_subkey; 87 else 88 key = ctx->auth_context->remote_subkey; 89 } else { 90 if (ctx->auth_context->remote_subkey) 91 key = ctx->auth_context->remote_subkey; 92 else 93 key = ctx->auth_context->local_subkey; 94 } 95 if (key == NULL) 96 key = ctx->auth_context->keyblock; 97 98 if (key == NULL) 99 return; 100 101 switch (key->keytype) { 102 case ETYPE_DES_CBC_CRC: 103 case ETYPE_DES_CBC_MD4: 104 case ETYPE_DES_CBC_MD5: 105 case ETYPE_DES3_CBC_MD5: 106 case ETYPE_DES3_CBC_SHA1: 107 case ETYPE_ARCFOUR_HMAC_MD5: 108 case ETYPE_ARCFOUR_HMAC_MD5_56: 109 break; 110 default : 111 *is_cfx = 1; 112 if ((acceptor && ctx->auth_context->local_subkey) || 113 (!acceptor && ctx->auth_context->remote_subkey)) 114 ctx->more_flags |= ACCEPTOR_SUBKEY; 115 break; 116 } 117 } 118 119 120 static OM_uint32 121 gsskrb5_accept_delegated_token 122 (OM_uint32 * minor_status, 123 gsskrb5_ctx ctx, 124 krb5_context context, 125 gss_cred_id_t * delegated_cred_handle 126 ) 127 { 128 krb5_ccache ccache = NULL; 129 krb5_error_code kret; 130 int32_t ac_flags, ret = GSS_S_COMPLETE; 131 132 *minor_status = 0; 133 134 /* XXX Create a new delegated_cred_handle? */ 135 if (delegated_cred_handle == NULL) { 136 kret = krb5_cc_default (context, &ccache); 137 } else { 138 *delegated_cred_handle = NULL; 139 kret = krb5_cc_gen_new (context, &krb5_mcc_ops, &ccache); 140 } 141 if (kret) { 142 ctx->flags &= ~GSS_C_DELEG_FLAG; 143 goto out; 144 } 145 146 kret = krb5_cc_initialize(context, ccache, ctx->source); 147 if (kret) { 148 ctx->flags &= ~GSS_C_DELEG_FLAG; 149 goto out; 150 } 151 152 krb5_auth_con_removeflags(context, 153 ctx->auth_context, 154 KRB5_AUTH_CONTEXT_DO_TIME, 155 &ac_flags); 156 kret = krb5_rd_cred2(context, 157 ctx->auth_context, 158 ccache, 159 &ctx->fwd_data); 160 krb5_auth_con_setflags(context, 161 ctx->auth_context, 162 ac_flags); 163 if (kret) { 164 ctx->flags &= ~GSS_C_DELEG_FLAG; 165 ret = GSS_S_FAILURE; 166 *minor_status = kret; 167 goto out; 168 } 169 170 if (delegated_cred_handle) { 171 gsskrb5_cred handle; 172 173 ret = _gsskrb5_import_cred(minor_status, 174 ccache, 175 NULL, 176 NULL, 177 delegated_cred_handle); 178 if (ret != GSS_S_COMPLETE) 179 goto out; 180 181 handle = (gsskrb5_cred) *delegated_cred_handle; 182 183 handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; 184 krb5_cc_close(context, ccache); 185 ccache = NULL; 186 } 187 188 out: 189 if (ccache) { 190 /* Don't destroy the default cred cache */ 191 if (delegated_cred_handle == NULL) 192 krb5_cc_close(context, ccache); 193 else 194 krb5_cc_destroy(context, ccache); 195 } 196 return ret; 197 } 198 199 static OM_uint32 200 gsskrb5_acceptor_ready(OM_uint32 * minor_status, 201 gsskrb5_ctx ctx, 202 krb5_context context, 203 gss_cred_id_t *delegated_cred_handle) 204 { 205 OM_uint32 ret; 206 int32_t seq_number; 207 int is_cfx = 0; 208 209 krb5_auth_getremoteseqnumber (context, 210 ctx->auth_context, 211 &seq_number); 212 213 _gsskrb5i_is_cfx(ctx, &is_cfx); 214 215 ret = _gssapi_msg_order_create(minor_status, 216 &ctx->order, 217 _gssapi_msg_order_f(ctx->flags), 218 seq_number, 0, is_cfx); 219 if (ret) 220 return ret; 221 222 /* 223 * If requested, set local sequence num to remote sequence if this 224 * isn't a mutual authentication context 225 */ 226 if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { 227 krb5_auth_con_setlocalseqnumber(context, 228 ctx->auth_context, 229 seq_number); 230 } 231 232 /* 233 * We should handle the delegation ticket, in case it's there 234 */ 235 if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { 236 ret = gsskrb5_accept_delegated_token(minor_status, 237 ctx, 238 context, 239 delegated_cred_handle); 240 if (ret) 241 return ret; 242 } else { 243 /* Well, looks like it wasn't there after all */ 244 ctx->flags &= ~GSS_C_DELEG_FLAG; 245 } 246 247 ctx->state = ACCEPTOR_READY; 248 ctx->more_flags |= OPEN; 249 250 return GSS_S_COMPLETE; 251 } 252 253 static OM_uint32 254 gsskrb5_acceptor_start(OM_uint32 * minor_status, 255 gsskrb5_ctx ctx, 256 krb5_context context, 257 const gss_cred_id_t acceptor_cred_handle, 258 const gss_buffer_t input_token_buffer, 259 const gss_channel_bindings_t input_chan_bindings, 260 gss_name_t * src_name, 261 gss_OID * mech_type, 262 gss_buffer_t output_token, 263 OM_uint32 * ret_flags, 264 OM_uint32 * time_rec, 265 gss_cred_id_t * delegated_cred_handle) 266 { 267 krb5_error_code kret; 268 OM_uint32 ret = GSS_S_COMPLETE; 269 krb5_data indata; 270 krb5_flags ap_options; 271 krb5_keytab keytab = NULL; 272 int is_cfx = 0; 273 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; 274 275 /* 276 * We may, or may not, have an escapsulation. 277 */ 278 ret = _gsskrb5_decapsulate (minor_status, 279 input_token_buffer, 280 &indata, 281 "\x01\x00", 282 GSS_KRB5_MECHANISM); 283 284 if (ret) { 285 /* Assume that there is no OID wrapping. */ 286 indata.length = input_token_buffer->length; 287 indata.data = input_token_buffer->value; 288 } 289 290 /* 291 * We need to get our keytab 292 */ 293 if (acceptor_cred == NULL) { 294 if (_gsskrb5_keytab != NULL) 295 keytab = _gsskrb5_keytab; 296 } else if (acceptor_cred->keytab != NULL) { 297 keytab = acceptor_cred->keytab; 298 } 299 300 /* 301 * We need to check the ticket and create the AP-REP packet 302 */ 303 304 { 305 krb5_rd_req_in_ctx in = NULL; 306 krb5_rd_req_out_ctx out = NULL; 307 308 kret = krb5_rd_req_in_ctx_alloc(context, &in); 309 if (kret == 0) 310 kret = krb5_rd_req_in_set_keytab(context, in, keytab); 311 if (kret) { 312 if (in) 313 krb5_rd_req_in_ctx_free(context, in); 314 ret = GSS_S_FAILURE; 315 *minor_status = kret; 316 return ret; 317 } 318 319 kret = krb5_rd_req_ctx(context, 320 &ctx->auth_context, 321 &indata, 322 (acceptor_cred_handle == GSS_C_NO_CREDENTIAL) ? NULL : acceptor_cred->principal, 323 in, &out); 324 krb5_rd_req_in_ctx_free(context, in); 325 if (kret) { 326 ret = GSS_S_FAILURE; 327 *minor_status = kret; 328 return ret; 329 } 330 331 /* 332 * We need to remember some data on the context_handle. 333 */ 334 kret = krb5_rd_req_out_get_ap_req_options(context, out, 335 &ap_options); 336 if (kret == 0) 337 kret = krb5_rd_req_out_get_ticket(context, out, 338 &ctx->ticket); 339 if (kret == 0) 340 kret = krb5_rd_req_out_get_keyblock(context, out, 341 &ctx->service_keyblock); 342 ctx->lifetime = ctx->ticket->ticket.endtime; 343 344 krb5_rd_req_out_ctx_free(context, out); 345 if (kret) { 346 ret = GSS_S_FAILURE; 347 *minor_status = kret; 348 return ret; 349 } 350 } 351 352 353 /* 354 * We need to copy the principal names to the context and the 355 * calling layer. 356 */ 357 kret = krb5_copy_principal(context, 358 ctx->ticket->client, 359 &ctx->source); 360 if (kret) { 361 ret = GSS_S_FAILURE; 362 *minor_status = kret; 363 } 364 365 kret = krb5_copy_principal(context, 366 ctx->ticket->server, 367 &ctx->target); 368 if (kret) { 369 ret = GSS_S_FAILURE; 370 *minor_status = kret; 371 return ret; 372 } 373 374 /* 375 * We need to setup some compat stuff, this assumes that 376 * context_handle->target is already set. 377 */ 378 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 379 if (ret) 380 return ret; 381 382 if (src_name != NULL) { 383 kret = krb5_copy_principal (context, 384 ctx->ticket->client, 385 (gsskrb5_name*)src_name); 386 if (kret) { 387 ret = GSS_S_FAILURE; 388 *minor_status = kret; 389 return ret; 390 } 391 } 392 393 /* 394 * We need to get the flags out of the 8003 checksum. 395 */ 396 { 397 krb5_authenticator authenticator; 398 399 kret = krb5_auth_con_getauthenticator(context, 400 ctx->auth_context, 401 &authenticator); 402 if(kret) { 403 ret = GSS_S_FAILURE; 404 *minor_status = kret; 405 return ret; 406 } 407 408 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 409 ret = _gsskrb5_verify_8003_checksum(minor_status, 410 input_chan_bindings, 411 authenticator->cksum, 412 &ctx->flags, 413 &ctx->fwd_data); 414 415 krb5_free_authenticator(context, &authenticator); 416 if (ret) { 417 return ret; 418 } 419 } else { 420 krb5_crypto crypto; 421 422 kret = krb5_crypto_init(context, 423 ctx->auth_context->keyblock, 424 0, &crypto); 425 if(kret) { 426 krb5_free_authenticator(context, &authenticator); 427 428 ret = GSS_S_FAILURE; 429 *minor_status = kret; 430 return ret; 431 } 432 433 /* 434 * Windows accepts Samba3's use of a kerberos, rather than 435 * GSSAPI checksum here 436 */ 437 438 kret = krb5_verify_checksum(context, 439 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 440 authenticator->cksum); 441 krb5_free_authenticator(context, &authenticator); 442 krb5_crypto_destroy(context, crypto); 443 444 if(kret) { 445 ret = GSS_S_BAD_SIG; 446 *minor_status = kret; 447 return ret; 448 } 449 450 /* 451 * Samba style get some flags (but not DCE-STYLE) 452 */ 453 ctx->flags = 454 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 455 } 456 } 457 458 if(ctx->flags & GSS_C_MUTUAL_FLAG) { 459 krb5_data outbuf; 460 461 _gsskrb5i_is_cfx(ctx, &is_cfx); 462 463 if (is_cfx != 0 464 || (ap_options & AP_OPTS_USE_SUBKEY)) { 465 kret = krb5_auth_con_addflags(context, 466 ctx->auth_context, 467 KRB5_AUTH_CONTEXT_USE_SUBKEY, 468 NULL); 469 ctx->more_flags |= ACCEPTOR_SUBKEY; 470 } 471 472 kret = krb5_mk_rep(context, 473 ctx->auth_context, 474 &outbuf); 475 if (kret) { 476 *minor_status = kret; 477 return GSS_S_FAILURE; 478 } 479 480 if (IS_DCE_STYLE(ctx)) { 481 output_token->length = outbuf.length; 482 output_token->value = outbuf.data; 483 } else { 484 ret = _gsskrb5_encapsulate(minor_status, 485 &outbuf, 486 output_token, 487 "\x02\x00", 488 GSS_KRB5_MECHANISM); 489 krb5_data_free (&outbuf); 490 if (ret) 491 return ret; 492 } 493 } 494 495 ctx->flags |= GSS_C_TRANS_FLAG; 496 497 /* Remember the flags */ 498 499 ctx->lifetime = ctx->ticket->ticket.endtime; 500 ctx->more_flags |= OPEN; 501 502 if (mech_type) 503 *mech_type = GSS_KRB5_MECHANISM; 504 505 if (time_rec) { 506 ret = _gsskrb5_lifetime_left(minor_status, 507 context, 508 ctx->lifetime, 509 time_rec); 510 if (ret) { 511 return ret; 512 } 513 } 514 515 /* 516 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 517 * the client. 518 */ 519 if (IS_DCE_STYLE(ctx)) { 520 /* 521 * Return flags to caller, but we haven't processed 522 * delgations yet 523 */ 524 if (ret_flags) 525 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 526 527 ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; 528 return GSS_S_CONTINUE_NEEDED; 529 } 530 531 ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 532 delegated_cred_handle); 533 534 if (ret_flags) 535 *ret_flags = ctx->flags; 536 537 return ret; 538 } 539 540 static OM_uint32 541 acceptor_wait_for_dcestyle(OM_uint32 * minor_status, 542 gsskrb5_ctx ctx, 543 krb5_context context, 544 const gss_cred_id_t acceptor_cred_handle, 545 const gss_buffer_t input_token_buffer, 546 const gss_channel_bindings_t input_chan_bindings, 547 gss_name_t * src_name, 548 gss_OID * mech_type, 549 gss_buffer_t output_token, 550 OM_uint32 * ret_flags, 551 OM_uint32 * time_rec, 552 gss_cred_id_t * delegated_cred_handle) 553 { 554 OM_uint32 ret; 555 krb5_error_code kret; 556 krb5_data inbuf; 557 int32_t r_seq_number, l_seq_number; 558 559 /* 560 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 561 */ 562 563 inbuf.length = input_token_buffer->length; 564 inbuf.data = input_token_buffer->value; 565 566 /* 567 * We need to remeber the old remote seq_number, then check if the 568 * client has replied with our local seq_number, and then reset 569 * the remote seq_number to the old value 570 */ 571 { 572 kret = krb5_auth_con_getlocalseqnumber(context, 573 ctx->auth_context, 574 &l_seq_number); 575 if (kret) { 576 *minor_status = kret; 577 return GSS_S_FAILURE; 578 } 579 580 kret = krb5_auth_getremoteseqnumber(context, 581 ctx->auth_context, 582 &r_seq_number); 583 if (kret) { 584 *minor_status = kret; 585 return GSS_S_FAILURE; 586 } 587 588 kret = krb5_auth_con_setremoteseqnumber(context, 589 ctx->auth_context, 590 l_seq_number); 591 if (kret) { 592 *minor_status = kret; 593 return GSS_S_FAILURE; 594 } 595 } 596 597 /* 598 * We need to verify the AP_REP, but we need to flag that this is 599 * DCE_STYLE, so don't check the timestamps this time, but put the 600 * flag DO_TIME back afterward. 601 */ 602 { 603 krb5_ap_rep_enc_part *repl; 604 int32_t auth_flags; 605 606 krb5_auth_con_removeflags(context, 607 ctx->auth_context, 608 KRB5_AUTH_CONTEXT_DO_TIME, 609 &auth_flags); 610 611 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 612 if (kret) { 613 *minor_status = kret; 614 return GSS_S_FAILURE; 615 } 616 krb5_free_ap_rep_enc_part(context, repl); 617 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 618 } 619 620 /* We need to check the liftime */ 621 { 622 OM_uint32 lifetime_rec; 623 624 ret = _gsskrb5_lifetime_left(minor_status, 625 context, 626 ctx->lifetime, 627 &lifetime_rec); 628 if (ret) { 629 return ret; 630 } 631 if (lifetime_rec == 0) { 632 return GSS_S_CONTEXT_EXPIRED; 633 } 634 635 if (time_rec) *time_rec = lifetime_rec; 636 } 637 638 /* We need to give the caller the flags which are in use */ 639 if (ret_flags) *ret_flags = ctx->flags; 640 641 if (src_name) { 642 kret = krb5_copy_principal(context, 643 ctx->source, 644 (gsskrb5_name*)src_name); 645 if (kret) { 646 *minor_status = kret; 647 return GSS_S_FAILURE; 648 } 649 } 650 651 /* 652 * After the krb5_rd_rep() the remote and local seq_number should 653 * be the same, because the client just replies the seq_number 654 * from our AP-REP in its AP-REP, but then the client uses the 655 * seq_number from its AP-REQ for GSS_wrap() 656 */ 657 { 658 int32_t tmp_r_seq_number, tmp_l_seq_number; 659 660 kret = krb5_auth_getremoteseqnumber(context, 661 ctx->auth_context, 662 &tmp_r_seq_number); 663 if (kret) { 664 *minor_status = kret; 665 return GSS_S_FAILURE; 666 } 667 668 kret = krb5_auth_con_getlocalseqnumber(context, 669 ctx->auth_context, 670 &tmp_l_seq_number); 671 if (kret) { 672 673 *minor_status = kret; 674 return GSS_S_FAILURE; 675 } 676 677 /* 678 * Here we check if the client has responsed with our local seq_number, 679 */ 680 if (tmp_r_seq_number != tmp_l_seq_number) { 681 return GSS_S_UNSEQ_TOKEN; 682 } 683 } 684 685 /* 686 * We need to reset the remote seq_number, because the client will use, 687 * the old one for the GSS_wrap() calls 688 */ 689 { 690 kret = krb5_auth_con_setremoteseqnumber(context, 691 ctx->auth_context, 692 r_seq_number); 693 if (kret) { 694 *minor_status = kret; 695 return GSS_S_FAILURE; 696 } 697 } 698 699 return gsskrb5_acceptor_ready(minor_status, ctx, context, 700 delegated_cred_handle); 701 } 702 703 704 OM_uint32 705 _gsskrb5_accept_sec_context(OM_uint32 * minor_status, 706 gss_ctx_id_t * context_handle, 707 const gss_cred_id_t acceptor_cred_handle, 708 const gss_buffer_t input_token_buffer, 709 const gss_channel_bindings_t input_chan_bindings, 710 gss_name_t * src_name, 711 gss_OID * mech_type, 712 gss_buffer_t output_token, 713 OM_uint32 * ret_flags, 714 OM_uint32 * time_rec, 715 gss_cred_id_t * delegated_cred_handle) 716 { 717 krb5_context context; 718 OM_uint32 ret; 719 gsskrb5_ctx ctx; 720 721 GSSAPI_KRB5_INIT(&context); 722 723 output_token->length = 0; 724 output_token->value = NULL; 725 726 if (src_name != NULL) 727 *src_name = NULL; 728 if (mech_type) 729 *mech_type = GSS_KRB5_MECHANISM; 730 731 if (*context_handle == GSS_C_NO_CONTEXT) { 732 ret = _gsskrb5_create_ctx(minor_status, 733 context_handle, 734 context, 735 input_chan_bindings, 736 ACCEPTOR_START); 737 if (ret) 738 return ret; 739 } 740 741 ctx = (gsskrb5_ctx)*context_handle; 742 743 744 /* 745 * TODO: check the channel_bindings 746 * (above just sets them to krb5 layer) 747 */ 748 749 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 750 751 switch (ctx->state) { 752 case ACCEPTOR_START: 753 ret = gsskrb5_acceptor_start(minor_status, 754 ctx, 755 context, 756 acceptor_cred_handle, 757 input_token_buffer, 758 input_chan_bindings, 759 src_name, 760 mech_type, 761 output_token, 762 ret_flags, 763 time_rec, 764 delegated_cred_handle); 765 break; 766 case ACCEPTOR_WAIT_FOR_DCESTYLE: 767 ret = acceptor_wait_for_dcestyle(minor_status, 768 ctx, 769 context, 770 acceptor_cred_handle, 771 input_token_buffer, 772 input_chan_bindings, 773 src_name, 774 mech_type, 775 output_token, 776 ret_flags, 777 time_rec, 778 delegated_cred_handle); 779 break; 780 case ACCEPTOR_READY: 781 /* 782 * If we get there, the caller have called 783 * gss_accept_sec_context() one time too many. 784 */ 785 ret = GSS_S_BAD_STATUS; 786 break; 787 default: 788 /* TODO: is this correct here? --metze */ 789 ret = GSS_S_BAD_STATUS; 790 break; 791 } 792 793 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 794 795 if (GSS_ERROR(ret)) { 796 OM_uint32 min2; 797 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 798 } 799 800 return ret; 801 } 802