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 free_Authenticator(ctx->auth_context->authenticator); 429 return send_error_token(minor_status, context, kret, 430 server, &indata, output_token); 431 } else if (kret) { 432 *minor_status = kret; 433 return GSS_S_FAILURE; 434 } 435 436 /* 437 * we need to remember some data on the context_handle. 438 */ 439 kret = krb5_rd_req_out_get_ap_req_options(context, out, 440 &ap_options); 441 if (kret == 0) 442 kret = krb5_rd_req_out_get_ticket(context, out, 443 &ctx->ticket); 444 if (kret == 0) 445 kret = krb5_rd_req_out_get_keyblock(context, out, 446 &ctx->service_keyblock); 447 ctx->lifetime = ctx->ticket->ticket.endtime; 448 449 krb5_rd_req_out_ctx_free(context, out); 450 if (kret) { 451 ret = GSS_S_FAILURE; 452 *minor_status = kret; 453 return ret; 454 } 455 } 456 457 458 /* 459 * We need to copy the principal names to the context and the 460 * calling layer. 461 */ 462 kret = krb5_copy_principal(context, 463 ctx->ticket->client, 464 &ctx->source); 465 if (kret) { 466 ret = GSS_S_FAILURE; 467 *minor_status = kret; 468 } 469 470 kret = krb5_copy_principal(context, 471 ctx->ticket->server, 472 &ctx->target); 473 if (kret) { 474 ret = GSS_S_FAILURE; 475 *minor_status = kret; 476 return ret; 477 } 478 479 /* 480 * We need to setup some compat stuff, this assumes that 481 * context_handle->target is already set. 482 */ 483 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 484 if (ret) 485 return ret; 486 487 if (src_name != NULL) { 488 kret = krb5_copy_principal (context, 489 ctx->ticket->client, 490 (gsskrb5_name*)src_name); 491 if (kret) { 492 ret = GSS_S_FAILURE; 493 *minor_status = kret; 494 return ret; 495 } 496 } 497 498 /* 499 * We need to get the flags out of the 8003 checksum. 500 */ 501 502 { 503 krb5_authenticator authenticator; 504 505 kret = krb5_auth_con_getauthenticator(context, 506 ctx->auth_context, 507 &authenticator); 508 if(kret) { 509 ret = GSS_S_FAILURE; 510 *minor_status = kret; 511 return ret; 512 } 513 514 if (authenticator->cksum == NULL) { 515 krb5_free_authenticator(context, &authenticator); 516 *minor_status = 0; 517 return GSS_S_BAD_BINDINGS; 518 } 519 520 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 521 ret = _gsskrb5_verify_8003_checksum(minor_status, 522 input_chan_bindings, 523 authenticator->cksum, 524 &ctx->flags, 525 &ctx->fwd_data); 526 527 krb5_free_authenticator(context, &authenticator); 528 if (ret) { 529 return ret; 530 } 531 } else { 532 krb5_crypto crypto; 533 534 kret = krb5_crypto_init(context, 535 ctx->auth_context->keyblock, 536 0, &crypto); 537 if(kret) { 538 krb5_free_authenticator(context, &authenticator); 539 540 ret = GSS_S_FAILURE; 541 *minor_status = kret; 542 return ret; 543 } 544 545 /* 546 * Windows accepts Samba3's use of a kerberos, rather than 547 * GSSAPI checksum here 548 */ 549 550 kret = krb5_verify_checksum(context, 551 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 552 authenticator->cksum); 553 krb5_free_authenticator(context, &authenticator); 554 krb5_crypto_destroy(context, crypto); 555 556 if(kret) { 557 ret = GSS_S_BAD_SIG; 558 *minor_status = kret; 559 return ret; 560 } 561 562 /* 563 * Samba style get some flags (but not DCE-STYLE), use 564 * ap_options to guess the mutual flag. 565 */ 566 ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 567 if (ap_options & AP_OPTS_MUTUAL_REQUIRED) 568 ctx->flags |= GSS_C_MUTUAL_FLAG; 569 } 570 } 571 572 if(ctx->flags & GSS_C_MUTUAL_FLAG) { 573 krb5_data outbuf; 574 int use_subkey = 0; 575 576 _gsskrb5i_is_cfx(context, ctx, 1); 577 is_cfx = (ctx->more_flags & IS_CFX); 578 579 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { 580 use_subkey = 1; 581 } else { 582 krb5_keyblock *rkey; 583 584 /* 585 * If there is a initiator subkey, copy that to acceptor 586 * subkey to match Windows behavior 587 */ 588 kret = krb5_auth_con_getremotesubkey(context, 589 ctx->auth_context, 590 &rkey); 591 if (kret == 0) { 592 kret = krb5_auth_con_setlocalsubkey(context, 593 ctx->auth_context, 594 rkey); 595 if (kret == 0) 596 use_subkey = 1; 597 krb5_free_keyblock(context, rkey); 598 } 599 } 600 if (use_subkey) { 601 ctx->more_flags |= ACCEPTOR_SUBKEY; 602 krb5_auth_con_addflags(context, ctx->auth_context, 603 KRB5_AUTH_CONTEXT_USE_SUBKEY, 604 NULL); 605 } 606 607 kret = krb5_mk_rep(context, 608 ctx->auth_context, 609 &outbuf); 610 if (kret) { 611 *minor_status = kret; 612 return GSS_S_FAILURE; 613 } 614 615 if (IS_DCE_STYLE(ctx)) { 616 output_token->length = outbuf.length; 617 output_token->value = outbuf.data; 618 } else { 619 ret = _gsskrb5_encapsulate(minor_status, 620 &outbuf, 621 output_token, 622 "\x02\x00", 623 GSS_KRB5_MECHANISM); 624 krb5_data_free (&outbuf); 625 if (ret) 626 return ret; 627 } 628 } 629 630 ctx->flags |= GSS_C_TRANS_FLAG; 631 632 /* Remember the flags */ 633 634 ctx->lifetime = ctx->ticket->ticket.endtime; 635 ctx->more_flags |= OPEN; 636 637 if (mech_type) 638 *mech_type = GSS_KRB5_MECHANISM; 639 640 if (time_rec) { 641 ret = _gsskrb5_lifetime_left(minor_status, 642 context, 643 ctx->lifetime, 644 time_rec); 645 if (ret) { 646 return ret; 647 } 648 } 649 650 /* 651 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 652 * the client. 653 */ 654 if (IS_DCE_STYLE(ctx)) { 655 /* 656 * Return flags to caller, but we haven't processed 657 * delgations yet 658 */ 659 if (ret_flags) 660 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 661 662 ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE; 663 return GSS_S_CONTINUE_NEEDED; 664 } 665 666 ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 667 delegated_cred_handle); 668 669 if (ret_flags) 670 *ret_flags = ctx->flags; 671 672 return ret; 673 } 674 675 static OM_uint32 676 acceptor_wait_for_dcestyle(OM_uint32 * minor_status, 677 gsskrb5_ctx ctx, 678 krb5_context context, 679 const gss_cred_id_t acceptor_cred_handle, 680 const gss_buffer_t input_token_buffer, 681 const gss_channel_bindings_t input_chan_bindings, 682 gss_name_t * src_name, 683 gss_OID * mech_type, 684 gss_buffer_t output_token, 685 OM_uint32 * ret_flags, 686 OM_uint32 * time_rec, 687 gss_cred_id_t * delegated_cred_handle) 688 { 689 OM_uint32 ret; 690 krb5_error_code kret; 691 krb5_data inbuf; 692 int32_t r_seq_number, l_seq_number; 693 694 /* 695 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 696 */ 697 698 inbuf.length = input_token_buffer->length; 699 inbuf.data = input_token_buffer->value; 700 701 /* 702 * We need to remeber the old remote seq_number, then check if the 703 * client has replied with our local seq_number, and then reset 704 * the remote seq_number to the old value 705 */ 706 { 707 kret = krb5_auth_con_getlocalseqnumber(context, 708 ctx->auth_context, 709 &l_seq_number); 710 if (kret) { 711 *minor_status = kret; 712 return GSS_S_FAILURE; 713 } 714 715 kret = krb5_auth_con_getremoteseqnumber(context, 716 ctx->auth_context, 717 &r_seq_number); 718 if (kret) { 719 *minor_status = kret; 720 return GSS_S_FAILURE; 721 } 722 723 kret = krb5_auth_con_setremoteseqnumber(context, 724 ctx->auth_context, 725 l_seq_number); 726 if (kret) { 727 *minor_status = kret; 728 return GSS_S_FAILURE; 729 } 730 } 731 732 /* 733 * We need to verify the AP_REP, but we need to flag that this is 734 * DCE_STYLE, so don't check the timestamps this time, but put the 735 * flag DO_TIME back afterward. 736 */ 737 { 738 krb5_ap_rep_enc_part *repl; 739 int32_t auth_flags; 740 741 krb5_auth_con_removeflags(context, 742 ctx->auth_context, 743 KRB5_AUTH_CONTEXT_DO_TIME, 744 &auth_flags); 745 746 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 747 if (kret) { 748 *minor_status = kret; 749 return GSS_S_FAILURE; 750 } 751 krb5_free_ap_rep_enc_part(context, repl); 752 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 753 } 754 755 /* We need to check the liftime */ 756 { 757 OM_uint32 lifetime_rec; 758 759 ret = _gsskrb5_lifetime_left(minor_status, 760 context, 761 ctx->lifetime, 762 &lifetime_rec); 763 if (ret) { 764 return ret; 765 } 766 if (lifetime_rec == 0) { 767 return GSS_S_CONTEXT_EXPIRED; 768 } 769 770 if (time_rec) *time_rec = lifetime_rec; 771 } 772 773 /* We need to give the caller the flags which are in use */ 774 if (ret_flags) *ret_flags = ctx->flags; 775 776 if (src_name) { 777 kret = krb5_copy_principal(context, 778 ctx->source, 779 (gsskrb5_name*)src_name); 780 if (kret) { 781 *minor_status = kret; 782 return GSS_S_FAILURE; 783 } 784 } 785 786 /* 787 * After the krb5_rd_rep() the remote and local seq_number should 788 * be the same, because the client just replies the seq_number 789 * from our AP-REP in its AP-REP, but then the client uses the 790 * seq_number from its AP-REQ for GSS_wrap() 791 */ 792 { 793 int32_t tmp_r_seq_number, tmp_l_seq_number; 794 795 kret = krb5_auth_con_getremoteseqnumber(context, 796 ctx->auth_context, 797 &tmp_r_seq_number); 798 if (kret) { 799 *minor_status = kret; 800 return GSS_S_FAILURE; 801 } 802 803 kret = krb5_auth_con_getlocalseqnumber(context, 804 ctx->auth_context, 805 &tmp_l_seq_number); 806 if (kret) { 807 808 *minor_status = kret; 809 return GSS_S_FAILURE; 810 } 811 812 /* 813 * Here we check if the client has responsed with our local seq_number, 814 */ 815 if (tmp_r_seq_number != tmp_l_seq_number) { 816 return GSS_S_UNSEQ_TOKEN; 817 } 818 } 819 820 /* 821 * We need to reset the remote seq_number, because the client will use, 822 * the old one for the GSS_wrap() calls 823 */ 824 { 825 kret = krb5_auth_con_setremoteseqnumber(context, 826 ctx->auth_context, 827 r_seq_number); 828 if (kret) { 829 *minor_status = kret; 830 return GSS_S_FAILURE; 831 } 832 } 833 834 return gsskrb5_acceptor_ready(minor_status, ctx, context, 835 delegated_cred_handle); 836 } 837 838 839 OM_uint32 GSSAPI_CALLCONV 840 _gsskrb5_accept_sec_context(OM_uint32 * minor_status, 841 gss_ctx_id_t * context_handle, 842 const gss_cred_id_t acceptor_cred_handle, 843 const gss_buffer_t input_token_buffer, 844 const gss_channel_bindings_t input_chan_bindings, 845 gss_name_t * src_name, 846 gss_OID * mech_type, 847 gss_buffer_t output_token, 848 OM_uint32 * ret_flags, 849 OM_uint32 * time_rec, 850 gss_cred_id_t * delegated_cred_handle) 851 { 852 krb5_context context; 853 OM_uint32 ret; 854 gsskrb5_ctx ctx; 855 856 GSSAPI_KRB5_INIT(&context); 857 858 output_token->length = 0; 859 output_token->value = NULL; 860 861 if (src_name != NULL) 862 *src_name = NULL; 863 if (mech_type) 864 *mech_type = GSS_KRB5_MECHANISM; 865 866 if (*context_handle == GSS_C_NO_CONTEXT) { 867 ret = _gsskrb5_create_ctx(minor_status, 868 context_handle, 869 context, 870 input_chan_bindings, 871 ACCEPTOR_START); 872 if (ret) 873 return ret; 874 } 875 876 ctx = (gsskrb5_ctx)*context_handle; 877 878 879 /* 880 * TODO: check the channel_bindings 881 * (above just sets them to krb5 layer) 882 */ 883 884 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 885 886 switch (ctx->state) { 887 case ACCEPTOR_START: 888 ret = gsskrb5_acceptor_start(minor_status, 889 ctx, 890 context, 891 acceptor_cred_handle, 892 input_token_buffer, 893 input_chan_bindings, 894 src_name, 895 mech_type, 896 output_token, 897 ret_flags, 898 time_rec, 899 delegated_cred_handle); 900 break; 901 case ACCEPTOR_WAIT_FOR_DCESTYLE: 902 ret = acceptor_wait_for_dcestyle(minor_status, 903 ctx, 904 context, 905 acceptor_cred_handle, 906 input_token_buffer, 907 input_chan_bindings, 908 src_name, 909 mech_type, 910 output_token, 911 ret_flags, 912 time_rec, 913 delegated_cred_handle); 914 break; 915 case ACCEPTOR_READY: 916 /* 917 * If we get there, the caller have called 918 * gss_accept_sec_context() one time too many. 919 */ 920 ret = GSS_S_BAD_STATUS; 921 break; 922 default: 923 /* TODO: is this correct here? --metze */ 924 ret = GSS_S_BAD_STATUS; 925 break; 926 } 927 928 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 929 930 if (GSS_ERROR(ret)) { 931 OM_uint32 min2; 932 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 933 } 934 935 return ret; 936 } 937