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