1 /* $NetBSD: init_sec_context.c,v 1.5 2023/06/19 21:41:43 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 - 2008 Kungliga Tekniska Hgskolan 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 38 /* 39 * copy the addresses from `input_chan_bindings' (if any) to 40 * the auth context `ac' 41 */ 42 43 static OM_uint32 44 set_addresses (krb5_context context, 45 krb5_auth_context ac, 46 const gss_channel_bindings_t input_chan_bindings) 47 { 48 /* Port numbers are expected to be in application_data.value, 49 * initator's port first */ 50 51 krb5_address initiator_addr, acceptor_addr; 52 krb5_error_code kret; 53 54 if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS 55 || input_chan_bindings->application_data.length != 56 2 * sizeof(ac->local_port)) 57 return 0; 58 59 memset(&initiator_addr, 0, sizeof(initiator_addr)); 60 memset(&acceptor_addr, 0, sizeof(acceptor_addr)); 61 62 ac->local_port = 63 *(int16_t *) input_chan_bindings->application_data.value; 64 65 ac->remote_port = 66 *((int16_t *) input_chan_bindings->application_data.value + 1); 67 68 kret = _gsskrb5i_address_to_krb5addr(context, 69 input_chan_bindings->acceptor_addrtype, 70 &input_chan_bindings->acceptor_address, 71 ac->remote_port, 72 &acceptor_addr); 73 if (kret) 74 return kret; 75 76 kret = _gsskrb5i_address_to_krb5addr(context, 77 input_chan_bindings->initiator_addrtype, 78 &input_chan_bindings->initiator_address, 79 ac->local_port, 80 &initiator_addr); 81 if (kret) { 82 krb5_free_address (context, &acceptor_addr); 83 return kret; 84 } 85 86 kret = krb5_auth_con_setaddrs(context, 87 ac, 88 &initiator_addr, /* local address */ 89 &acceptor_addr); /* remote address */ 90 91 krb5_free_address (context, &initiator_addr); 92 krb5_free_address (context, &acceptor_addr); 93 94 #if 0 95 free(input_chan_bindings->application_data.value); 96 input_chan_bindings->application_data.value = NULL; 97 input_chan_bindings->application_data.length = 0; 98 #endif 99 100 return kret; 101 } 102 103 OM_uint32 104 _gsskrb5_create_ctx( 105 OM_uint32 * minor_status, 106 gss_ctx_id_t * context_handle, 107 krb5_context context, 108 const gss_channel_bindings_t input_chan_bindings, 109 enum gss_ctx_id_t_state state) 110 { 111 krb5_error_code kret; 112 gsskrb5_ctx ctx; 113 114 *context_handle = NULL; 115 116 ctx = malloc(sizeof(*ctx)); 117 if (ctx == NULL) { 118 *minor_status = ENOMEM; 119 return GSS_S_FAILURE; 120 } 121 ctx->auth_context = NULL; 122 ctx->deleg_auth_context = NULL; 123 ctx->source = NULL; 124 ctx->target = NULL; 125 ctx->kcred = NULL; 126 ctx->ccache = NULL; 127 ctx->state = state; 128 ctx->flags = 0; 129 ctx->more_flags = 0; 130 ctx->service_keyblock = NULL; 131 ctx->ticket = NULL; 132 krb5_data_zero(&ctx->fwd_data); 133 ctx->endtime = 0; 134 ctx->order = NULL; 135 ctx->crypto = NULL; 136 HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex); 137 138 kret = krb5_auth_con_init (context, &ctx->auth_context); 139 if (kret) { 140 *minor_status = kret; 141 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 142 free(ctx); 143 return GSS_S_FAILURE; 144 } 145 146 kret = krb5_auth_con_init (context, &ctx->deleg_auth_context); 147 if (kret) { 148 *minor_status = kret; 149 krb5_auth_con_free(context, ctx->auth_context); 150 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 151 free(ctx); 152 return GSS_S_FAILURE; 153 } 154 155 kret = set_addresses(context, ctx->auth_context, input_chan_bindings); 156 if (kret) { 157 *minor_status = kret; 158 159 krb5_auth_con_free(context, ctx->auth_context); 160 krb5_auth_con_free(context, ctx->deleg_auth_context); 161 162 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 163 free(ctx); 164 return GSS_S_BAD_BINDINGS; 165 } 166 167 kret = set_addresses(context, ctx->deleg_auth_context, input_chan_bindings); 168 if (kret) { 169 *minor_status = kret; 170 171 krb5_auth_con_free(context, ctx->auth_context); 172 krb5_auth_con_free(context, ctx->deleg_auth_context); 173 174 HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex); 175 free(ctx); 176 return GSS_S_BAD_BINDINGS; 177 } 178 179 /* 180 * We need a sequence number 181 */ 182 183 krb5_auth_con_addflags(context, 184 ctx->auth_context, 185 KRB5_AUTH_CONTEXT_DO_SEQUENCE | 186 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, 187 NULL); 188 189 /* 190 * We need a sequence number 191 */ 192 193 krb5_auth_con_addflags(context, 194 ctx->deleg_auth_context, 195 KRB5_AUTH_CONTEXT_DO_SEQUENCE | 196 KRB5_AUTH_CONTEXT_CLEAR_FORWARDED_CRED, 197 NULL); 198 199 *context_handle = (gss_ctx_id_t)ctx; 200 201 return GSS_S_COMPLETE; 202 } 203 204 205 static OM_uint32 206 gsskrb5_get_creds( 207 OM_uint32 * minor_status, 208 krb5_context context, 209 krb5_ccache ccache, 210 gsskrb5_ctx ctx, 211 gss_const_name_t target_name, 212 OM_uint32 time_req, 213 OM_uint32 * time_rec) 214 { 215 OM_uint32 ret; 216 krb5_error_code kret; 217 krb5_creds this_cred; 218 OM_uint32 lifetime_rec; 219 220 if (ctx->target) { 221 krb5_free_principal(context, ctx->target); 222 ctx->target = NULL; 223 } 224 if (ctx->kcred) { 225 krb5_free_creds(context, ctx->kcred); 226 ctx->kcred = NULL; 227 } 228 229 ret = _gsskrb5_canon_name(minor_status, context, target_name, 230 &ctx->target); 231 if (ret) 232 return ret; 233 234 memset(&this_cred, 0, sizeof(this_cred)); 235 this_cred.client = ctx->source; 236 this_cred.server = ctx->target; 237 238 if (time_req && time_req != GSS_C_INDEFINITE) { 239 krb5_timestamp ts; 240 241 krb5_timeofday (context, &ts); 242 this_cred.times.endtime = ts + time_req; 243 } else { 244 this_cred.times.endtime = 0; 245 } 246 247 this_cred.session.keytype = KEYTYPE_NULL; 248 249 kret = krb5_get_credentials(context, 250 0, 251 ccache, 252 &this_cred, 253 &ctx->kcred); 254 if (kret) { 255 *minor_status = kret; 256 return GSS_S_FAILURE; 257 } 258 259 ctx->endtime = ctx->kcred->times.endtime; 260 261 ret = _gsskrb5_lifetime_left(minor_status, context, 262 ctx->endtime, &lifetime_rec); 263 if (ret) return ret; 264 265 if (lifetime_rec == 0) { 266 *minor_status = 0; 267 return GSS_S_CONTEXT_EXPIRED; 268 } 269 270 if (time_rec) *time_rec = lifetime_rec; 271 272 return GSS_S_COMPLETE; 273 } 274 275 static OM_uint32 276 gsskrb5_initiator_ready( 277 OM_uint32 * minor_status, 278 gsskrb5_ctx ctx, 279 krb5_context context) 280 { 281 OM_uint32 ret; 282 int32_t seq_number; 283 int is_cfx = 0; 284 OM_uint32 flags = ctx->flags; 285 286 krb5_free_creds(context, ctx->kcred); 287 ctx->kcred = NULL; 288 289 if (ctx->more_flags & CLOSE_CCACHE) 290 krb5_cc_close(context, ctx->ccache); 291 ctx->ccache = NULL; 292 293 krb5_auth_con_getremoteseqnumber (context, ctx->auth_context, &seq_number); 294 295 _gsskrb5i_is_cfx(context, ctx, 0); 296 is_cfx = (ctx->more_flags & IS_CFX); 297 298 ret = _gssapi_msg_order_create(minor_status, 299 &ctx->order, 300 _gssapi_msg_order_f(flags), 301 seq_number, 0, is_cfx); 302 if (ret) return ret; 303 304 ctx->state = INITIATOR_READY; 305 ctx->more_flags |= OPEN; 306 307 return GSS_S_COMPLETE; 308 } 309 310 /* 311 * handle delegated creds in init-sec-context 312 */ 313 314 static void 315 do_delegation (krb5_context context, 316 krb5_auth_context ac, 317 krb5_ccache ccache, 318 krb5_creds *cred, 319 krb5_const_principal name, 320 krb5_data *fwd_data, 321 uint32_t flagmask, 322 uint32_t *flags) 323 { 324 krb5_creds creds; 325 KDCOptions fwd_flags; 326 krb5_error_code kret; 327 328 memset (&creds, 0, sizeof(creds)); 329 krb5_data_zero (fwd_data); 330 331 kret = krb5_cc_get_principal(context, ccache, &creds.client); 332 if (kret) 333 goto out; 334 335 kret = krb5_make_principal(context, 336 &creds.server, 337 creds.client->realm, 338 KRB5_TGS_NAME, 339 creds.client->realm, 340 NULL); 341 if (kret) 342 goto out; 343 344 creds.times.endtime = 0; 345 346 memset(&fwd_flags, 0, sizeof(fwd_flags)); 347 fwd_flags.forwarded = 1; 348 fwd_flags.forwardable = 1; 349 350 if (name->name.name_string.len < 2) 351 goto out; 352 353 kret = krb5_get_forwarded_creds(context, 354 ac, 355 ccache, 356 KDCOptions2int(fwd_flags), 357 name->name.name_string.val[1], 358 &creds, 359 fwd_data); 360 361 out: 362 if (kret) 363 *flags &= ~flagmask; 364 else 365 *flags |= flagmask; 366 367 if (creds.client) 368 krb5_free_principal(context, creds.client); 369 if (creds.server) 370 krb5_free_principal(context, creds.server); 371 } 372 373 /* 374 * first stage of init-sec-context 375 */ 376 377 static OM_uint32 378 init_auth 379 (OM_uint32 * minor_status, 380 gsskrb5_cred cred, 381 gsskrb5_ctx ctx, 382 krb5_context context, 383 gss_const_name_t name, 384 const gss_OID mech_type, 385 OM_uint32 req_flags, 386 OM_uint32 time_req, 387 const gss_buffer_t input_token, 388 gss_OID * actual_mech_type, 389 gss_buffer_t output_token, 390 OM_uint32 * ret_flags, 391 OM_uint32 * time_rec 392 ) 393 { 394 OM_uint32 ret = GSS_S_FAILURE; 395 krb5_error_code kret; 396 krb5_data fwd_data; 397 OM_uint32 lifetime_rec; 398 399 krb5_data_zero(&fwd_data); 400 401 *minor_status = 0; 402 403 if (actual_mech_type) 404 *actual_mech_type = GSS_KRB5_MECHANISM; 405 406 if (cred == NULL) { 407 kret = krb5_cc_default (context, &ctx->ccache); 408 if (kret) { 409 *minor_status = kret; 410 ret = GSS_S_FAILURE; 411 goto failure; 412 } 413 ctx->more_flags |= CLOSE_CCACHE; 414 } else 415 ctx->ccache = cred->ccache; 416 417 kret = krb5_cc_get_principal (context, ctx->ccache, &ctx->source); 418 if (kret) { 419 *minor_status = kret; 420 ret = GSS_S_FAILURE; 421 goto failure; 422 } 423 424 /* 425 * This is hideous glue for (NFS) clients that wants to limit the 426 * available enctypes to what it can support (encryption in 427 * kernel). 428 */ 429 if (cred && cred->enctypes) 430 krb5_set_default_in_tkt_etypes(context, cred->enctypes); 431 432 ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, 433 ctx, name, time_req, time_rec); 434 if (ret) 435 goto failure; 436 437 ctx->endtime = ctx->kcred->times.endtime; 438 439 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 440 if (ret) 441 goto failure; 442 443 ret = _gsskrb5_lifetime_left(minor_status, 444 context, 445 ctx->endtime, 446 &lifetime_rec); 447 if (ret) 448 goto failure; 449 450 if (lifetime_rec == 0) { 451 *minor_status = 0; 452 ret = GSS_S_CONTEXT_EXPIRED; 453 goto failure; 454 } 455 456 krb5_auth_con_setkey(context, 457 ctx->auth_context, 458 &ctx->kcred->session); 459 460 kret = krb5_auth_con_generatelocalsubkey(context, 461 ctx->auth_context, 462 &ctx->kcred->session); 463 if(kret) { 464 *minor_status = kret; 465 ret = GSS_S_FAILURE; 466 goto failure; 467 } 468 469 return GSS_S_COMPLETE; 470 471 failure: 472 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) 473 krb5_cc_close(context, ctx->ccache); 474 ctx->ccache = NULL; 475 476 return ret; 477 478 } 479 480 static OM_uint32 481 init_auth_restart 482 (OM_uint32 * minor_status, 483 gsskrb5_cred cred, 484 gsskrb5_ctx ctx, 485 krb5_context context, 486 OM_uint32 req_flags, 487 const gss_channel_bindings_t input_chan_bindings, 488 const gss_buffer_t input_token, 489 gss_OID * actual_mech_type, 490 gss_buffer_t output_token, 491 OM_uint32 * ret_flags, 492 OM_uint32 * time_rec 493 ) 494 { 495 OM_uint32 ret = GSS_S_FAILURE; 496 krb5_error_code kret; 497 krb5_flags ap_options; 498 krb5_data outbuf; 499 uint32_t flags; 500 krb5_data authenticator; 501 Checksum cksum; 502 krb5_enctype enctype; 503 krb5_data fwd_data, timedata; 504 int32_t offset = 0, oldoffset = 0; 505 uint32_t flagmask; 506 507 krb5_data_zero(&outbuf); 508 krb5_data_zero(&fwd_data); 509 510 *minor_status = 0; 511 512 /* 513 * If the credential doesn't have ok-as-delegate, check if there 514 * is a realm setting and use that. 515 */ 516 if (!ctx->kcred->flags.b.ok_as_delegate) { 517 krb5_data data; 518 519 ret = krb5_cc_get_config(context, ctx->ccache, NULL, 520 "realm-config", &data); 521 if (ret == 0) { 522 /* XXX 1 is use ok-as-delegate */ 523 if (data.length < 1 || ((((unsigned char *)data.data)[0]) & 1) == 0) 524 req_flags &= ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); 525 krb5_data_free(&data); 526 } 527 } 528 529 flagmask = 0; 530 531 /* if we used GSS_C_DELEG_POLICY_FLAG, trust KDC */ 532 if ((req_flags & GSS_C_DELEG_POLICY_FLAG) 533 && ctx->kcred->flags.b.ok_as_delegate) 534 flagmask |= GSS_C_DELEG_FLAG | GSS_C_DELEG_POLICY_FLAG; 535 /* if there still is a GSS_C_DELEG_FLAG, use that */ 536 if (req_flags & GSS_C_DELEG_FLAG) 537 flagmask |= GSS_C_DELEG_FLAG; 538 539 540 flags = 0; 541 ap_options = 0; 542 if (flagmask & GSS_C_DELEG_FLAG) { 543 do_delegation (context, 544 ctx->deleg_auth_context, 545 ctx->ccache, ctx->kcred, ctx->target, 546 &fwd_data, flagmask, &flags); 547 } 548 549 if (req_flags & GSS_C_MUTUAL_FLAG) { 550 flags |= GSS_C_MUTUAL_FLAG; 551 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 552 } 553 554 if (req_flags & GSS_C_REPLAY_FLAG) 555 flags |= GSS_C_REPLAY_FLAG; 556 if (req_flags & GSS_C_SEQUENCE_FLAG) 557 flags |= GSS_C_SEQUENCE_FLAG; 558 #if 0 559 if (req_flags & GSS_C_ANON_FLAG) 560 ; /* XXX */ 561 #endif 562 if (req_flags & GSS_C_DCE_STYLE) { 563 /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ 564 flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; 565 ap_options |= AP_OPTS_MUTUAL_REQUIRED; 566 } 567 if (req_flags & GSS_C_IDENTIFY_FLAG) 568 flags |= GSS_C_IDENTIFY_FLAG; 569 if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) 570 flags |= GSS_C_EXTENDED_ERROR_FLAG; 571 572 if (req_flags & GSS_C_CONF_FLAG) { 573 flags |= GSS_C_CONF_FLAG; 574 } 575 if (req_flags & GSS_C_INTEG_FLAG) { 576 flags |= GSS_C_INTEG_FLAG; 577 } 578 if (cred == NULL || !(cred->cred_flags & GSS_CF_NO_CI_FLAGS)) { 579 flags |= GSS_C_CONF_FLAG; 580 flags |= GSS_C_INTEG_FLAG; 581 } 582 flags |= GSS_C_TRANS_FLAG; 583 584 if (ret_flags) 585 *ret_flags = flags; 586 ctx->flags = flags; 587 ctx->more_flags |= LOCAL; 588 589 ret = _gsskrb5_create_8003_checksum (minor_status, 590 input_chan_bindings, 591 flags, 592 &fwd_data, 593 &cksum); 594 krb5_data_free (&fwd_data); 595 if (ret) 596 goto failure; 597 598 enctype = ctx->auth_context->keyblock->keytype; 599 600 ret = krb5_cc_get_config(context, ctx->ccache, ctx->target, 601 "time-offset", &timedata); 602 if (ret == 0) { 603 if (timedata.length == 4) { 604 const u_char *p = timedata.data; 605 if (p[0] < 128) { 606 offset = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); 607 } else { 608 /* 609 * (p[0] << 24), if p[0] > 127 -> offset is negative, but *p is 610 * positive, so this is overflow -- overflow we want, but UBSAN 611 * flags it. 612 * 613 * NOTE: We assume the platform is a twos-complement platform. 614 */ 615 offset = INT32_MIN; 616 offset |= ((p[0] & 0x7f) <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0); 617 } 618 } 619 krb5_data_free(&timedata); 620 } 621 622 if (offset) { 623 krb5_get_kdc_sec_offset (context, &oldoffset, NULL); 624 krb5_set_kdc_sec_offset (context, offset, -1); 625 } 626 627 kret = _krb5_build_authenticator(context, 628 ctx->auth_context, 629 enctype, 630 ctx->kcred, 631 &cksum, 632 &authenticator, 633 KRB5_KU_AP_REQ_AUTH); 634 635 if (kret) { 636 if (offset) 637 krb5_set_kdc_sec_offset (context, oldoffset, -1); 638 *minor_status = kret; 639 ret = GSS_S_FAILURE; 640 goto failure; 641 } 642 643 kret = krb5_build_ap_req (context, 644 enctype, 645 ctx->kcred, 646 ap_options, 647 authenticator, 648 &outbuf); 649 if (offset) 650 krb5_set_kdc_sec_offset (context, oldoffset, -1); 651 if (kret) { 652 *minor_status = kret; 653 ret = GSS_S_FAILURE; 654 goto failure; 655 } 656 657 if (flags & GSS_C_DCE_STYLE) { 658 output_token->value = outbuf.data; 659 output_token->length = outbuf.length; 660 } else { 661 ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, 662 (u_char *)(intptr_t)"\x01\x00", 663 GSS_KRB5_MECHANISM); 664 krb5_data_free (&outbuf); 665 if (ret) 666 goto failure; 667 } 668 669 free_Checksum(&cksum); 670 671 if (flags & GSS_C_MUTUAL_FLAG) { 672 ctx->state = INITIATOR_WAIT_FOR_MUTAL; 673 return GSS_S_CONTINUE_NEEDED; 674 } 675 676 return gsskrb5_initiator_ready(minor_status, ctx, context); 677 failure: 678 if (ctx->ccache && (ctx->more_flags & CLOSE_CCACHE)) 679 krb5_cc_close(context, ctx->ccache); 680 ctx->ccache = NULL; 681 682 return ret; 683 } 684 685 static krb5_error_code 686 handle_error_packet(krb5_context context, 687 gsskrb5_ctx ctx, 688 krb5_data indata) 689 { 690 krb5_error_code kret; 691 KRB_ERROR error; 692 693 kret = krb5_rd_error(context, &indata, &error); 694 if (kret == 0) { 695 kret = krb5_error_from_rd_error(context, &error, NULL); 696 697 /* save the time skrew for this host */ 698 if (kret == KRB5KRB_AP_ERR_SKEW) { 699 krb5_data timedata; 700 unsigned char p[4]; 701 int32_t t = error.stime - time(NULL); 702 703 p[0] = (t >> 24) & 0xFF; 704 p[1] = (t >> 16) & 0xFF; 705 p[2] = (t >> 8) & 0xFF; 706 p[3] = (t >> 0) & 0xFF; 707 708 timedata.data = p; 709 timedata.length = sizeof(p); 710 711 krb5_cc_set_config(context, ctx->ccache, ctx->target, 712 "time-offset", &timedata); 713 714 if ((ctx->more_flags & RETRIED) == 0) 715 ctx->state = INITIATOR_RESTART; 716 ctx->more_flags |= RETRIED; 717 } 718 free_KRB_ERROR (&error); 719 } 720 return kret; 721 } 722 723 724 static OM_uint32 725 repl_mutual 726 (OM_uint32 * minor_status, 727 gsskrb5_ctx ctx, 728 krb5_context context, 729 const gss_OID mech_type, 730 OM_uint32 req_flags, 731 OM_uint32 time_req, 732 const gss_channel_bindings_t input_chan_bindings, 733 const gss_buffer_t input_token, 734 gss_OID * actual_mech_type, 735 gss_buffer_t output_token, 736 OM_uint32 * ret_flags, 737 OM_uint32 * time_rec 738 ) 739 { 740 OM_uint32 ret; 741 krb5_error_code kret; 742 krb5_data indata; 743 krb5_ap_rep_enc_part *repl; 744 745 output_token->length = 0; 746 output_token->value = NULL; 747 748 if (actual_mech_type) 749 *actual_mech_type = GSS_KRB5_MECHANISM; 750 751 if (IS_DCE_STYLE(ctx)) { 752 /* There is no OID wrapping. */ 753 indata.length = input_token->length; 754 indata.data = input_token->value; 755 kret = krb5_rd_rep(context, 756 ctx->auth_context, 757 &indata, 758 &repl); 759 if (kret) { 760 ret = _gsskrb5_decapsulate(minor_status, 761 input_token, 762 &indata, 763 "\x03\x00", 764 GSS_KRB5_MECHANISM); 765 if (ret == GSS_S_COMPLETE) { 766 *minor_status = handle_error_packet(context, ctx, indata); 767 } else { 768 *minor_status = kret; 769 } 770 return GSS_S_FAILURE; 771 } 772 } else { 773 ret = _gsskrb5_decapsulate (minor_status, 774 input_token, 775 &indata, 776 "\x02\x00", 777 GSS_KRB5_MECHANISM); 778 if (ret == GSS_S_DEFECTIVE_TOKEN) { 779 /* check if there is an error token sent instead */ 780 ret = _gsskrb5_decapsulate (minor_status, 781 input_token, 782 &indata, 783 "\x03\x00", 784 GSS_KRB5_MECHANISM); 785 if (ret == GSS_S_COMPLETE) { 786 *minor_status = handle_error_packet(context, ctx, indata); 787 return GSS_S_FAILURE; 788 } 789 } 790 kret = krb5_rd_rep (context, 791 ctx->auth_context, 792 &indata, 793 &repl); 794 if (kret) { 795 *minor_status = kret; 796 return GSS_S_FAILURE; 797 } 798 } 799 800 krb5_free_ap_rep_enc_part (context, 801 repl); 802 803 *minor_status = 0; 804 if (time_rec) 805 _gsskrb5_lifetime_left(minor_status, 806 context, 807 ctx->endtime, 808 time_rec); 809 if (ret_flags) 810 *ret_flags = ctx->flags; 811 812 if (req_flags & GSS_C_DCE_STYLE) { 813 int32_t local_seq, remote_seq; 814 krb5_data outbuf; 815 816 /* 817 * So DCE_STYLE is strange. The client echos the seq number 818 * that the server used in the server's mk_rep in its own 819 * mk_rep(). After when done, it resets to it's own seq number 820 * for the gss_wrap calls. 821 */ 822 823 krb5_auth_con_getremoteseqnumber(context, ctx->auth_context, &remote_seq); 824 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, &local_seq); 825 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, remote_seq); 826 827 kret = krb5_mk_rep(context, ctx->auth_context, &outbuf); 828 if (kret) { 829 *minor_status = kret; 830 return GSS_S_FAILURE; 831 } 832 833 /* reset local seq number */ 834 krb5_auth_con_setlocalseqnumber(context, ctx->auth_context, local_seq); 835 836 output_token->length = outbuf.length; 837 output_token->value = outbuf.data; 838 } 839 840 return gsskrb5_initiator_ready(minor_status, ctx, context); 841 } 842 843 /* 844 * gss_init_sec_context 845 */ 846 847 OM_uint32 GSSAPI_CALLCONV _gsskrb5_init_sec_context 848 (OM_uint32 * minor_status, 849 gss_const_cred_id_t cred_handle, 850 gss_ctx_id_t * context_handle, 851 gss_const_name_t target_name, 852 const gss_OID mech_type, 853 OM_uint32 req_flags, 854 OM_uint32 time_req, 855 const gss_channel_bindings_t input_chan_bindings, 856 const gss_buffer_t input_token, 857 gss_OID * actual_mech_type, 858 gss_buffer_t output_token, 859 OM_uint32 * ret_flags, 860 OM_uint32 * time_rec 861 ) 862 { 863 krb5_context context; 864 gsskrb5_cred cred = (gsskrb5_cred)cred_handle; 865 gsskrb5_ctx ctx; 866 OM_uint32 ret; 867 868 GSSAPI_KRB5_INIT (&context); 869 870 output_token->length = 0; 871 output_token->value = NULL; 872 873 if (context_handle == NULL) { 874 *minor_status = 0; 875 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 876 } 877 878 if (ret_flags) 879 *ret_flags = 0; 880 if (time_rec) 881 *time_rec = 0; 882 883 if (target_name == GSS_C_NO_NAME) { 884 if (actual_mech_type) 885 *actual_mech_type = GSS_C_NO_OID; 886 *minor_status = 0; 887 return GSS_S_BAD_NAME; 888 } 889 890 if (mech_type != GSS_C_NO_OID && 891 !gss_oid_equal(mech_type, GSS_KRB5_MECHANISM)) 892 return GSS_S_BAD_MECH; 893 894 if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) { 895 OM_uint32 ret1; 896 897 if (*context_handle != GSS_C_NO_CONTEXT) { 898 *minor_status = 0; 899 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 900 } 901 902 ret1 = _gsskrb5_create_ctx(minor_status, 903 context_handle, 904 context, 905 input_chan_bindings, 906 INITIATOR_START); 907 if (ret1) 908 return ret1; 909 } 910 911 if (*context_handle == GSS_C_NO_CONTEXT) { 912 *minor_status = 0; 913 return GSS_S_FAILURE | GSS_S_CALL_BAD_STRUCTURE; 914 } 915 916 ctx = (gsskrb5_ctx) *context_handle; 917 918 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 919 920 again: 921 switch (ctx->state) { 922 case INITIATOR_START: 923 ret = init_auth(minor_status, 924 cred, 925 ctx, 926 context, 927 target_name, 928 mech_type, 929 req_flags, 930 time_req, 931 input_token, 932 actual_mech_type, 933 output_token, 934 ret_flags, 935 time_rec); 936 if (ret != GSS_S_COMPLETE) 937 break; 938 /* FALLTHROUGH */ 939 case INITIATOR_RESTART: 940 ret = init_auth_restart(minor_status, 941 cred, 942 ctx, 943 context, 944 req_flags, 945 input_chan_bindings, 946 input_token, 947 actual_mech_type, 948 output_token, 949 ret_flags, 950 time_rec); 951 break; 952 case INITIATOR_WAIT_FOR_MUTAL: 953 ret = repl_mutual(minor_status, 954 ctx, 955 context, 956 mech_type, 957 req_flags, 958 time_req, 959 input_chan_bindings, 960 input_token, 961 actual_mech_type, 962 output_token, 963 ret_flags, 964 time_rec); 965 if (ctx->state == INITIATOR_RESTART) 966 goto again; 967 break; 968 case INITIATOR_READY: 969 /* 970 * If we get there, the caller have called 971 * gss_init_sec_context() one time too many. 972 */ 973 _gsskrb5_set_status(EINVAL, "init_sec_context " 974 "called one time too many"); 975 *minor_status = EINVAL; 976 ret = GSS_S_BAD_STATUS; 977 break; 978 default: 979 _gsskrb5_set_status(EINVAL, "init_sec_context " 980 "invalid state %d for client", 981 (int)ctx->state); 982 *minor_status = EINVAL; 983 ret = GSS_S_BAD_STATUS; 984 break; 985 } 986 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 987 988 /* destroy context in case of error */ 989 if (GSS_ERROR(ret)) { 990 OM_uint32 min2; 991 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 992 } 993 994 return ret; 995 996 } 997