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