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