1/* 2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. 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#include <heim-ipc.h> 39 40#define GKAS(name) static OM_uint32 \ 41name(OM_uint32 *, gsskrb5_ctx, krb5_context, const gss_cred_id_t, \ 42 const gss_buffer_t, const gss_channel_bindings_t, \ 43 gss_name_t *, gss_OID *, gss_buffer_t, \ 44 OM_uint32 *, OM_uint32 *, gss_cred_id_t *) 45 46 47GKAS(acceptor_wait_for_dcestyle); 48GKAS(gsskrb5_acceptor_start); 49GKAS(step_acceptor_completed); 50 51HEIMDAL_MUTEX gssapi_keytab_mutex = HEIMDAL_MUTEX_INITIALIZER; 52krb5_keytab _gsskrb5_keytab; 53 54static krb5_error_code 55validate_keytab(krb5_context context, const char *name, krb5_keytab *id) 56{ 57 krb5_error_code ret; 58 59 ret = krb5_kt_resolve(context, name, id); 60 if (ret) 61 return ret; 62 63 ret = krb5_kt_have_content(context, *id); 64 if (ret) { 65 krb5_kt_close(context, *id); 66 *id = NULL; 67 } 68 69 return ret; 70} 71 72OM_uint32 73_gsskrb5_register_acceptor_identity(OM_uint32 *min_stat, const char *identity) 74{ 75 krb5_context context; 76 krb5_error_code ret; 77 78 *min_stat = 0; 79 80 ret = _gsskrb5_init(&context); 81 if(ret) 82 return GSS_S_FAILURE; 83 84 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); 85 86 if(_gsskrb5_keytab != NULL) { 87 krb5_kt_close(context, _gsskrb5_keytab); 88 _gsskrb5_keytab = NULL; 89 } 90 if (identity == NULL) { 91 ret = krb5_kt_default(context, &_gsskrb5_keytab); 92 } else { 93 /* 94 * First check if we can the keytab as is and if it has content... 95 */ 96 ret = validate_keytab(context, identity, &_gsskrb5_keytab); 97 /* 98 * if it doesn't, lets prepend FILE: and try again 99 */ 100 if (ret) { 101 char *p = NULL; 102 ret = asprintf(&p, "FILE:%s", identity); 103 if(ret < 0 || p == NULL) { 104 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 105 return GSS_S_FAILURE; 106 } 107 ret = validate_keytab(context, p, &_gsskrb5_keytab); 108 free(p); 109 } 110 } 111 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 112 if(ret) { 113 *min_stat = ret; 114 return GSS_S_FAILURE; 115 } 116 return GSS_S_COMPLETE; 117} 118 119void 120_gsskrb5i_is_cfx(krb5_context context, gsskrb5_ctx ctx, int acceptor) 121{ 122 krb5_keyblock *key; 123 124 krb5_auth_con_getlocalseqnumber(context, ctx->auth_context, 125 (int32_t *)&ctx->gk5c.seqnumlo); 126 ctx->gk5c.seqnumhi = 0; 127 128 if (acceptor) { 129 if (ctx->auth_context->local_subkey) 130 key = ctx->auth_context->local_subkey; 131 else 132 key = ctx->auth_context->remote_subkey; 133 } else { 134 if (ctx->auth_context->remote_subkey) 135 key = ctx->auth_context->remote_subkey; 136 else 137 key = ctx->auth_context->local_subkey; 138 } 139 if (key == NULL) 140 key = ctx->auth_context->keyblock; 141 142 if (key == NULL) 143 return; 144 145 switch (key->keytype) { 146 case ETYPE_DES_CBC_CRC: 147 case ETYPE_DES_CBC_MD4: 148 case ETYPE_DES_CBC_MD5: 149 case ETYPE_DES3_CBC_MD5: 150 case ETYPE_OLD_DES3_CBC_SHA1: 151 case ETYPE_DES3_CBC_SHA1: 152 case ETYPE_ARCFOUR_HMAC_MD5: 153 case ETYPE_ARCFOUR_HMAC_MD5_56: 154 break; 155 default : 156 ctx->more_flags |= IS_CFX; 157 158 ctx->gk5c.flags &= ~(GK5C_ACCEPTOR_SUBKEY | GK5C_DCE_STYLE); 159 160 if (acceptor) { 161 ctx->gk5c.flags |= GK5C_ACCEPTOR; 162 if (ctx->auth_context->local_subkey) 163 ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; 164 } else { 165 if (ctx->auth_context->remote_subkey) 166 ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; 167 } 168 169 if (ctx->flags & GSS_C_DCE_STYLE) 170 ctx->gk5c.flags |= GK5C_DCE_STYLE; 171 172 break; 173 } 174 if (ctx->gk5c.crypto) 175 krb5_crypto_destroy(context, ctx->gk5c.crypto); 176 krb5_crypto_init(context, key, 0, &ctx->gk5c.crypto); 177} 178 179 180static OM_uint32 181gsskrb5_accept_delegated_token 182(OM_uint32 * minor_status, 183 gsskrb5_ctx ctx, 184 krb5_context context, 185 gss_cred_id_t * delegated_cred_handle 186 ) 187{ 188 krb5_ccache ccache = NULL; 189 krb5_error_code kret; 190 int32_t ac_flags, ret = GSS_S_COMPLETE; 191 192 *minor_status = 0; 193 194 /* XXX Create a new delegated_cred_handle? */ 195 if (delegated_cred_handle == NULL) { 196 kret = krb5_cc_default (context, &ccache); 197 } else { 198 *delegated_cred_handle = NULL; 199 kret = krb5_cc_new_unique (context, krb5_cc_type_memory, 200 NULL, &ccache); 201 } 202 if (kret) { 203 ctx->flags &= ~GSS_C_DELEG_FLAG; 204 goto out; 205 } 206 207 kret = krb5_cc_initialize(context, ccache, ctx->source); 208 if (kret) { 209 ctx->flags &= ~GSS_C_DELEG_FLAG; 210 goto out; 211 } 212 213 krb5_auth_con_removeflags(context, 214 ctx->auth_context, 215 KRB5_AUTH_CONTEXT_DO_TIME, 216 &ac_flags); 217 kret = krb5_rd_cred2(context, 218 ctx->auth_context, 219 ccache, 220 &ctx->fwd_data); 221 krb5_auth_con_setflags(context, 222 ctx->auth_context, 223 ac_flags); 224 if (kret) { 225 ctx->flags &= ~GSS_C_DELEG_FLAG; 226 ret = GSS_S_FAILURE; 227 *minor_status = kret; 228 goto out; 229 } 230 231 if (delegated_cred_handle) { 232 gsskrb5_cred handle; 233 234 ret = _gsskrb5_krb5_import_cred(minor_status, 235 ccache, 236 NULL, 237 NULL, 238 delegated_cred_handle); 239 if (ret != GSS_S_COMPLETE) 240 goto out; 241 242 handle = (gsskrb5_cred) *delegated_cred_handle; 243 244 handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; 245 krb5_cc_close(context, ccache); 246 ccache = NULL; 247 } 248 249out: 250 if (ccache) { 251 /* Don't destroy the default cred cache */ 252 if (delegated_cred_handle == NULL) 253 krb5_cc_close(context, ccache); 254 else 255 krb5_cc_destroy(context, ccache); 256 } 257 return ret; 258} 259 260 261static OM_uint32 262step_acceptor_completed(OM_uint32 * minor_status, 263 gsskrb5_ctx ctx, 264 krb5_context context, 265 const gss_cred_id_t acceptor_cred_handle, 266 const gss_buffer_t input_token_buffer, 267 const gss_channel_bindings_t input_chan_bindings, 268 gss_name_t * src_name, 269 gss_OID * mech_type, 270 gss_buffer_t output_token, 271 OM_uint32 * ret_flags, 272 OM_uint32 * time_rec, 273 gss_cred_id_t * delegated_cred_handle) 274{ 275 /* 276 * If we get there, the caller have called 277 * gss_accept_sec_context() one time too many. 278 */ 279 return GSS_S_BAD_STATUS; 280} 281 282static OM_uint32 283gsskrb5_acceptor_ready(OM_uint32 * minor_status, 284 gsskrb5_ctx ctx, 285 krb5_context context, 286 gss_cred_id_t *delegated_cred_handle) 287{ 288 OM_uint32 ret; 289 int32_t seq_number; 290 int is_cfx = 0; 291 292 krb5_auth_con_getremoteseqnumber (context, 293 ctx->auth_context, 294 &seq_number); 295 296 _gsskrb5i_is_cfx(context, ctx, 1); 297 is_cfx = (ctx->more_flags & IS_CFX); 298 299 ret = _gssapi_msg_order_create(minor_status, 300 &ctx->gk5c.order, 301 _gssapi_msg_order_f(ctx->flags), 302 seq_number, 0, is_cfx); 303 if (ret) 304 return ret; 305 306 /* 307 * If requested, set local sequence num to remote sequence if this 308 * isn't a mutual authentication context 309 */ 310 if (!(ctx->flags & GSS_C_MUTUAL_FLAG) && _gssapi_msg_order_f(ctx->flags)) { 311 krb5_auth_con_setlocalseqnumber(context, 312 ctx->auth_context, 313 seq_number); 314 } 315 316 /* 317 * We should handle the delegation ticket, in case it's there 318 */ 319 if (ctx->fwd_data.length > 0 && (ctx->flags & GSS_C_DELEG_FLAG)) { 320 ret = gsskrb5_accept_delegated_token(minor_status, 321 ctx, 322 context, 323 delegated_cred_handle); 324 if (ret) 325 return ret; 326 } else { 327 /* Well, looks like it wasn't there after all */ 328 ctx->flags &= ~GSS_C_DELEG_FLAG; 329 } 330 331 ctx->acceptor_state = step_acceptor_completed; 332 333 ctx->more_flags |= OPEN; 334 335 return GSS_S_COMPLETE; 336} 337 338OM_uint32 339_gsskrb5_error_token(OM_uint32 *minor_status, 340 gss_OID mech, 341 krb5_context context, 342 krb5_error_code error_code, 343 krb5_data *e_data, 344 krb5_principal server, 345 gss_buffer_t output_token) 346{ 347 krb5_error_code ret; 348 krb5_data outbuf; 349 350 ret = krb5_mk_error(context, error_code, NULL, e_data, NULL, 351 server, NULL, NULL, &outbuf); 352 if (ret) { 353 *minor_status = ret; 354 return GSS_S_FAILURE; 355 } 356 357 ret = _gsskrb5_encapsulate(minor_status, 358 &outbuf, 359 output_token, 360 "\x03\x00", 361 mech); 362 krb5_data_free (&outbuf); 363 if (ret) 364 return ret; 365 366 *minor_status = 0; 367 return GSS_S_COMPLETE; 368} 369 370static OM_uint32 371send_error_token(OM_uint32 *minor_status, 372 krb5_context context, 373 krb5_error_code kret, 374 krb5_principal server, 375 krb5_data *indata, 376 gss_OID mech, 377 gss_buffer_t output_token) 378{ 379 krb5_principal ap_req_server = NULL; 380 OM_uint32 maj_stat; 381 /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which 382 tells windows to try again with the corrected timestamp. See 383 [MS-KILE] 2.2.1 KERB-ERROR-DATA */ 384 krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") }; 385 386 /* build server from request if the acceptor had not selected one */ 387 if (server == NULL && indata) { 388 krb5_error_code ret; 389 AP_REQ ap_req; 390 391 ret = krb5_decode_ap_req(context, indata, &ap_req); 392 if (ret) { 393 *minor_status = ret; 394 return GSS_S_FAILURE; 395 } 396 ret = _krb5_principalname2krb5_principal(context, 397 &ap_req_server, 398 ap_req.ticket.sname, 399 ap_req.ticket.realm); 400 free_AP_REQ(&ap_req); 401 if (ret) { 402 *minor_status = ret; 403 return GSS_S_FAILURE; 404 } 405 server = ap_req_server; 406 } 407 408 maj_stat = _gsskrb5_error_token(minor_status, mech, context, kret, 409 &e_data, server, output_token); 410 if (ap_req_server) 411 krb5_free_principal(context, ap_req_server); 412 if (maj_stat) 413 return GSS_S_FAILURE; 414 415 *minor_status = 0; 416 return GSS_S_CONTINUE_NEEDED; 417} 418 419static OM_uint32 420iakerb_acceptor_start(OM_uint32 * minor_status, 421 gsskrb5_ctx ctx, 422 krb5_context context, 423 const gss_cred_id_t acceptor_cred_handle, 424 const gss_buffer_t input_token_buffer, 425 const gss_channel_bindings_t input_chan_bindings, 426 gss_name_t * src_name, 427 gss_OID * mech_type, 428 gss_buffer_t output_token, 429 OM_uint32 * ret_flags, 430 OM_uint32 * time_rec, 431 gss_cred_id_t * delegated_cred_handle) 432{ 433 krb5_data indata, outdata; 434 gss_buffer_desc idata; 435 krb5_error_code kret; 436 heim_ipc ictx; 437 OM_uint32 ret; 438 439 if (ctx->messages == NULL) { 440 ctx->messages = krb5_storage_emem(); 441 if (ctx->messages == NULL) { 442 *minor_status = ENOMEM; 443 return GSS_S_FAILURE; 444 } 445 } 446 447 ret = _gsskrb5_iakerb_parse_header(minor_status, context, ctx, input_token_buffer, &indata); 448 if (ret == GSS_S_DEFECTIVE_TOKEN) { 449 ctx->acceptor_state = gsskrb5_acceptor_start; 450 return GSS_S_COMPLETE; 451 } else if (ret != GSS_S_COMPLETE) 452 return ret; 453 454 krb5_storage_write(ctx->messages, 455 input_token_buffer->value, 456 input_token_buffer->length); 457 458 idata.value = indata.data; 459 idata.length = indata.length; 460 461 heim_assert(ctx->iakerbrealm != NULL, "realm not set by decoder, non OPT value"); 462 463 if (krb5_realm_is_lkdc(ctx->iakerbrealm)) { 464 465 kret = heim_ipc_init_context("ANY:org.h5l.kdc", &ictx); 466 if (kret) { 467 *minor_status = kret; 468 return GSS_S_FAILURE; 469 } 470 471 kret = heim_ipc_call(ictx, &indata, &outdata, NULL); 472 heim_ipc_free_context(ictx); 473 if (kret) { 474 _gsskrb5_error_token(minor_status, ctx->mech, context, kret, 475 NULL, NULL, output_token); 476 *minor_status = kret; 477 return GSS_S_FAILURE; 478 } 479 480 ret = _gsskrb5_iakerb_make_header(minor_status, context, ctx, ctx->iakerbrealm, &outdata, output_token); 481 heim_ipc_free_data(&outdata); 482 if (ret) 483 return ret; 484 485 } else { 486 /* XXX dont support non local realms right now */ 487 *minor_status = EINVAL; 488 return GSS_S_FAILURE; 489 } 490 491 krb5_storage_write(ctx->messages, 492 output_token->value, 493 output_token->length); 494 495 return GSS_S_CONTINUE_NEEDED; 496} 497 498 499static OM_uint32 500pku2u_acceptor_start(OM_uint32 * minor_status, 501 gsskrb5_ctx ctx, 502 krb5_context context, 503 const gss_cred_id_t acceptor_cred_handle, 504 const gss_buffer_t input_token_buffer, 505 const gss_channel_bindings_t input_chan_bindings, 506 gss_name_t * src_name, 507 gss_OID * mech_type, 508 gss_buffer_t output_token, 509 OM_uint32 * ret_flags, 510 OM_uint32 * time_rec, 511 gss_cred_id_t * delegated_cred_handle) 512{ 513 krb5_data indata, outdata; 514 krb5_error_code kret; 515 heim_ipc ictx; 516 OM_uint32 ret; 517 518 if (ctx->messages == NULL) { 519 ctx->messages = krb5_storage_emem(); 520 if (ctx->messages == NULL) { 521 *minor_status = ENOMEM; 522 return GSS_S_FAILURE; 523 } 524 } 525 526 ret = _gsskrb5_decapsulate (minor_status, 527 input_token_buffer, 528 &indata, 529 "\x05\x01", 530 ctx->mech); 531 if (ret == GSS_S_DEFECTIVE_TOKEN) { 532 ctx->acceptor_state = gsskrb5_acceptor_start; 533 return GSS_S_COMPLETE; 534 } else if (ret != GSS_S_COMPLETE) 535 return ret; 536 537 krb5_storage_write(ctx->messages, 538 input_token_buffer->value, 539 input_token_buffer->length); 540 541 kret = heim_ipc_init_context("ANY:org.h5l.kdc", &ictx); 542 if (kret) { 543 *minor_status = kret; 544 return GSS_S_FAILURE; 545 } 546 547 548 ret = _gsskrb5_encapsulate(minor_status, 549 &outdata, 550 output_token, 551 "\x06\x00", 552 ctx->mech); 553 heim_ipc_free_data(&outdata); 554 if (ret != GSS_S_COMPLETE) 555 return ret; 556 557 krb5_storage_write(ctx->messages, 558 output_token->value, 559 output_token->length); 560 561 562 *minor_status = 0; 563 return GSS_S_FAILURE; 564} 565 566static OM_uint32 567gsskrb5_acceptor_start(OM_uint32 * minor_status, 568 gsskrb5_ctx ctx, 569 krb5_context context, 570 const gss_cred_id_t acceptor_cred_handle, 571 const gss_buffer_t input_token_buffer, 572 const gss_channel_bindings_t input_chan_bindings, 573 gss_name_t * src_name, 574 gss_OID * mech_type, 575 gss_buffer_t output_token, 576 OM_uint32 * ret_flags, 577 OM_uint32 * time_rec, 578 gss_cred_id_t * delegated_cred_handle) 579{ 580 krb5_error_code kret; 581 OM_uint32 ret = GSS_S_COMPLETE; 582 krb5_data indata; 583 krb5_flags ap_options; 584 krb5_keytab keytab = NULL; 585 int is_cfx = 0; 586 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; 587 krb5_boolean is_hostbased_service = FALSE; 588 589 /* 590 * We may, or may not, have an escapsulation. 591 */ 592 ret = _gsskrb5_decapsulate (minor_status, 593 input_token_buffer, 594 &indata, 595 "\x01\x00", 596 ctx->mech); 597 598 if (ret) { 599 /* Assume that there is no OID wrapping. */ 600 indata.length = input_token_buffer->length; 601 indata.data = input_token_buffer->value; 602 } 603 604 /* 605 * We need to get our keytab 606 */ 607 if (acceptor_cred == NULL) { 608 if (_gsskrb5_keytab != NULL) 609 keytab = _gsskrb5_keytab; 610 } else if (acceptor_cred->keytab != NULL) { 611 keytab = acceptor_cred->keytab; 612 } 613 614 is_hostbased_service = 615 (acceptor_cred && 616 acceptor_cred->principal && 617 krb5_principal_is_gss_hostbased_service(context, acceptor_cred->principal)); 618 619 /* 620 * We need to check the ticket and create the AP-REP packet 621 */ 622 623 { 624 krb5_rd_req_in_ctx in = NULL; 625 krb5_rd_req_out_ctx out = NULL; 626 krb5_principal server = NULL; 627 628 if (acceptor_cred && !is_hostbased_service) 629 server = acceptor_cred->principal; 630 631 kret = krb5_rd_req_in_ctx_alloc(context, &in); 632 if (kret == 0) 633 kret = krb5_rd_req_in_set_keytab(context, in, keytab); 634 if (kret) { 635 if (in) 636 krb5_rd_req_in_ctx_free(context, in); 637 *minor_status = kret; 638 return GSS_S_FAILURE; 639 } 640 641 kret = krb5_rd_req_ctx(context, 642 &ctx->auth_context, 643 &indata, 644 server, 645 in, &out); 646 krb5_rd_req_in_ctx_free(context, in); 647 if (ret && _gss_mg_log_level(5)) { 648 const char *e = krb5_get_error_message(context, ret); 649 char *s = NULL; 650 if (server) 651 (void)krb5_unparse_name(context, server, &s); 652 _gss_mg_log(5, "gss-asc: rd_req (server: %s) failed with: %d: %s", 653 s ? s : "<not specified>", 654 ret, e); 655 krb5_free_error_message(context, e); 656 if (s) 657 krb5_xfree(s); 658 } 659 660 661 switch (kret) { 662 case 0: 663 break; 664 case KRB5KRB_AP_ERR_SKEW: 665 case KRB5KRB_AP_ERR_TKT_NYV: 666 /* 667 * No reply in non-MUTUAL mode, but we don't know that its 668 * non-MUTUAL mode yet, thats inside the 8003 checksum, so 669 * lets only send the error token on clock skew, that 670 * limit when send error token for non-MUTUAL. 671 */ 672 return send_error_token(minor_status, context, kret, 673 server, &indata, ctx->mech, output_token); 674 case KRB5KRB_AP_ERR_MODIFIED: 675 case KRB5_KT_NOTFOUND: 676 case KRB5_KT_END: 677 /* 678 * If the error is on the keytab entry missing or bad 679 * decryption, lets assume that the keytab version was 680 * wrong and tell the client that. 681 */ 682 return send_error_token(minor_status, context, KRB5KRB_AP_ERR_MODIFIED, 683 server, NULL, ctx->mech, output_token); 684 default: 685 *minor_status = kret; 686 return GSS_S_FAILURE; 687 } 688 689 /* 690 * we need to remember some data on the context_handle. 691 */ 692 kret = krb5_rd_req_out_get_ap_req_options(context, out, 693 &ap_options); 694 if (kret == 0) 695 kret = krb5_rd_req_out_get_ticket(context, out, 696 &ctx->ticket); 697 if (kret == 0) 698 kret = krb5_rd_req_out_get_keyblock(context, out, 699 &ctx->service_keyblock); 700 if (kret == 0) { 701 int flags; 702 flags = krb5_rd_req_out_get_flags(context, out); 703 if (flags & KRB5_RD_REQ_OUT_PAC_VALID) 704 ctx->more_flags |= PAC_VALID; 705 } 706 if (kret == 0 && is_hostbased_service) { 707 krb5_principal sp = ctx->ticket->server; 708 709 if (sp->name.name_string.len < 1 || 710 strcmp(sp->name.name_string.val[0], acceptor_cred->principal->name.name_string.val[0]) != 0) 711 { 712 kret = KRB5KRB_AP_WRONG_PRINC; 713 krb5_set_error_message(context, ret, "Expecting service %s but got %s", 714 acceptor_cred->principal->name.name_string.val[0], 715 sp->name.name_string.val[0]); 716 } 717 } 718 719 ctx->endtime = ctx->ticket->ticket.endtime; 720 721 krb5_rd_req_out_ctx_free(context, out); 722 if (kret) { 723 ret = GSS_S_FAILURE; 724 *minor_status = kret; 725 return ret; 726 } 727 } 728 729 730 /* 731 * We need to copy the principal names to the context and the 732 * calling layer. 733 */ 734 kret = krb5_copy_principal(context, 735 ctx->ticket->client, 736 &ctx->source); 737 if (kret) { 738 *minor_status = kret; 739 return GSS_S_FAILURE; 740 } 741 742 kret = krb5_copy_principal(context, 743 ctx->ticket->server, 744 &ctx->target); 745 if (kret) { 746 ret = GSS_S_FAILURE; 747 *minor_status = kret; 748 return ret; 749 } 750 751 /* 752 * We need to setup some compat stuff, this assumes that 753 * context_handle->target is already set. 754 */ 755 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 756 if (ret) 757 return ret; 758 759 if (src_name != NULL) { 760 kret = krb5_copy_principal (context, 761 ctx->ticket->client, 762 (gsskrb5_name*)src_name); 763 if (kret) { 764 ret = GSS_S_FAILURE; 765 *minor_status = kret; 766 return ret; 767 } 768 } 769 770 /* 771 * We need to get the flags out of the 8003 checksum. 772 */ 773 774 { 775 krb5_authenticator authenticator; 776 777 kret = krb5_auth_con_getauthenticator(context, 778 ctx->auth_context, 779 &authenticator); 780 if(kret) { 781 ret = GSS_S_FAILURE; 782 *minor_status = kret; 783 return ret; 784 } 785 786 if (authenticator->cksum == NULL) { 787 krb5_free_authenticator(context, &authenticator); 788 *minor_status = 0; 789 return GSS_S_BAD_BINDINGS; 790 } 791 792 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 793 krb5_data finished_data; 794 krb5_crypto crypto = NULL; 795 796 if (ctx->auth_context->remote_subkey) { 797 kret = krb5_crypto_init(context, 798 ctx->auth_context->remote_subkey, 799 0, &crypto); 800 if (kret) { 801 *minor_status = kret; 802 return GSS_S_FAILURE; 803 } 804 } 805 806 krb5_data_zero(&finished_data); 807 808 ret = _gsskrb5_verify_8003_checksum(minor_status, 809 context, 810 crypto, 811 input_chan_bindings, 812 authenticator->cksum, 813 &ctx->flags, 814 &ctx->fwd_data, 815 &finished_data); 816 817 krb5_free_authenticator(context, &authenticator); 818 if (ret) { 819 krb5_crypto_destroy(context, crypto); 820 return ret; 821 } 822 823 if (finished_data.length) { 824 GSS_KRB5_FINISHED finished; 825 krb5_data pkt; 826 827 memset(&finished, 0, sizeof(finished)); 828 829 if (ctx->messages == NULL) { 830 krb5_crypto_destroy(context, crypto); 831 krb5_data_free(&finished_data); 832 *minor_status = 0; 833 return GSS_S_BAD_SIG; 834 } 835 836 kret = krb5_storage_to_data(ctx->messages, &pkt); 837 if (kret) { 838 krb5_crypto_destroy(context, crypto); 839 krb5_data_free(&finished_data); 840 *minor_status = kret; 841 return GSS_S_FAILURE; 842 } 843 844 if (ctx->auth_context->remote_subkey == NULL) { 845 krb5_crypto_destroy(context, crypto); 846 krb5_data_free(&finished_data); 847 krb5_data_free(&pkt); 848 *minor_status = 0; 849 return GSS_S_BAD_SIG; 850 } 851 852 kret = decode_GSS_KRB5_FINISHED(finished_data.data, 853 finished_data.length, 854 &finished, NULL); 855 krb5_data_free(&finished_data); 856 if (kret) { 857 krb5_crypto_destroy(context, crypto); 858 krb5_data_free(&pkt); 859 *minor_status = kret; 860 return GSS_S_FAILURE; 861 } 862 863 kret = krb5_verify_checksum(context, crypto, 864 KRB5_KU_FINISHED, 865 pkt.data, pkt.length, 866 &finished.gss_mic); 867 free_GSS_KRB5_FINISHED(&finished); 868 krb5_data_free(&pkt); 869 if (kret) { 870 krb5_crypto_destroy(context, crypto); 871 *minor_status = kret; 872 return GSS_S_FAILURE; 873 } 874 } 875 krb5_crypto_destroy(context, crypto); 876 877 } else { 878 krb5_crypto crypto; 879 880 kret = krb5_crypto_init(context, 881 ctx->auth_context->keyblock, 882 0, &crypto); 883 if(kret) { 884 krb5_free_authenticator(context, &authenticator); 885 886 ret = GSS_S_FAILURE; 887 *minor_status = kret; 888 return ret; 889 } 890 891 /* 892 * Windows accepts Samba3's use of a kerberos, rather than 893 * GSSAPI checksum here 894 */ 895 896 kret = krb5_verify_checksum(context, 897 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 898 authenticator->cksum); 899 krb5_free_authenticator(context, &authenticator); 900 krb5_crypto_destroy(context, crypto); 901 902 if(kret) { 903 ret = GSS_S_BAD_SIG; 904 *minor_status = kret; 905 return ret; 906 } 907 908 /* 909 * Samba style get some flags (but not DCE-STYLE), use 910 * ap_options to guess the mutual flag. 911 */ 912 ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 913 if (ap_options & AP_OPTS_MUTUAL_REQUIRED) 914 ctx->flags |= GSS_C_MUTUAL_FLAG; 915 } 916 } 917 918 if(ctx->flags & GSS_C_MUTUAL_FLAG) { 919 krb5_data outbuf; 920 int use_subkey = 0; 921 922 _gsskrb5i_is_cfx(context, ctx, 1); 923 is_cfx = (ctx->more_flags & IS_CFX); 924 925 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { 926 use_subkey = 1; 927 } else { 928 krb5_keyblock *rkey; 929 930 /* 931 * If there is a initiator subkey, copy that to acceptor 932 * subkey to match Windows behavior 933 */ 934 kret = krb5_auth_con_getremotesubkey(context, 935 ctx->auth_context, 936 &rkey); 937 if (kret == 0) { 938 kret = krb5_auth_con_setlocalsubkey(context, 939 ctx->auth_context, 940 rkey); 941 if (kret == 0) 942 use_subkey = 1; 943 krb5_free_keyblock(context, rkey); 944 } 945 } 946 if (use_subkey) { 947 ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; 948 krb5_auth_con_addflags(context, ctx->auth_context, 949 KRB5_AUTH_CONTEXT_USE_SUBKEY, 950 NULL); 951 } 952 953 kret = krb5_mk_rep(context, 954 ctx->auth_context, 955 &outbuf); 956 if (kret) { 957 *minor_status = kret; 958 return GSS_S_FAILURE; 959 } 960 961 if (IS_DCE_STYLE(ctx)) { 962 output_token->length = outbuf.length; 963 output_token->value = outbuf.data; 964 } else { 965 ret = _gsskrb5_encapsulate(minor_status, 966 &outbuf, 967 output_token, 968 "\x02\x00", 969 ctx->mech); 970 krb5_data_free (&outbuf); 971 if (ret) 972 return ret; 973 } 974 } 975 976 ctx->flags |= GSS_C_TRANS_FLAG; 977 978 /* Remember the flags */ 979 980 ctx->endtime = ctx->ticket->ticket.endtime; 981 ctx->more_flags |= OPEN; 982 983 if (mech_type) 984 *mech_type = ctx->mech; 985 986 if (time_rec) { 987 ret = _gsskrb5_lifetime_left(minor_status, 988 context, 989 ctx->endtime, 990 time_rec); 991 if (ret) { 992 return ret; 993 } 994 } 995 996 /* 997 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 998 * the client. 999 */ 1000 if (IS_DCE_STYLE(ctx)) { 1001 /* 1002 * Return flags to caller, but we haven't processed 1003 * delgations yet 1004 */ 1005 if (ret_flags) 1006 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 1007 1008 ctx->acceptor_state = acceptor_wait_for_dcestyle; 1009 return GSS_S_CONTINUE_NEEDED; 1010 } 1011 1012 ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 1013 delegated_cred_handle); 1014 1015 if (ret_flags) 1016 *ret_flags = ctx->flags; 1017 1018 return ret; 1019} 1020 1021static OM_uint32 1022acceptor_wait_for_dcestyle(OM_uint32 * minor_status, 1023 gsskrb5_ctx ctx, 1024 krb5_context context, 1025 const gss_cred_id_t acceptor_cred_handle, 1026 const gss_buffer_t input_token_buffer, 1027 const gss_channel_bindings_t input_chan_bindings, 1028 gss_name_t * src_name, 1029 gss_OID * mech_type, 1030 gss_buffer_t output_token, 1031 OM_uint32 * ret_flags, 1032 OM_uint32 * time_rec, 1033 gss_cred_id_t * delegated_cred_handle) 1034{ 1035 OM_uint32 ret; 1036 krb5_error_code kret; 1037 krb5_data inbuf; 1038 int32_t r_seq_number, l_seq_number; 1039 1040 /* 1041 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 1042 */ 1043 1044 inbuf.length = input_token_buffer->length; 1045 inbuf.data = input_token_buffer->value; 1046 1047 /* 1048 * We need to remeber the old remote seq_number, then check if the 1049 * client has replied with our local seq_number, and then reset 1050 * the remote seq_number to the old value 1051 */ 1052 { 1053 kret = krb5_auth_con_getlocalseqnumber(context, 1054 ctx->auth_context, 1055 &l_seq_number); 1056 if (kret) { 1057 *minor_status = kret; 1058 return GSS_S_FAILURE; 1059 } 1060 1061 kret = krb5_auth_con_getremoteseqnumber(context, 1062 ctx->auth_context, 1063 &r_seq_number); 1064 if (kret) { 1065 *minor_status = kret; 1066 return GSS_S_FAILURE; 1067 } 1068 1069 kret = krb5_auth_con_setremoteseqnumber(context, 1070 ctx->auth_context, 1071 l_seq_number); 1072 if (kret) { 1073 *minor_status = kret; 1074 return GSS_S_FAILURE; 1075 } 1076 } 1077 1078 /* 1079 * We need to verify the AP_REP, but we need to flag that this is 1080 * DCE_STYLE, so don't check the timestamps this time, but put the 1081 * flag DO_TIME back afterward. 1082 */ 1083 { 1084 krb5_ap_rep_enc_part *repl; 1085 int32_t auth_flags; 1086 1087 krb5_auth_con_removeflags(context, 1088 ctx->auth_context, 1089 KRB5_AUTH_CONTEXT_DO_TIME, 1090 &auth_flags); 1091 1092 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 1093 if (kret) { 1094 *minor_status = kret; 1095 return GSS_S_FAILURE; 1096 } 1097 krb5_free_ap_rep_enc_part(context, repl); 1098 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 1099 } 1100 1101 /* We need to check the liftime */ 1102 { 1103 OM_uint32 lifetime_rec; 1104 1105 ret = _gsskrb5_lifetime_left(minor_status, 1106 context, 1107 ctx->endtime, 1108 &lifetime_rec); 1109 if (ret) { 1110 return ret; 1111 } 1112 if (lifetime_rec == 0) { 1113 return GSS_S_CONTEXT_EXPIRED; 1114 } 1115 1116 if (time_rec) *time_rec = lifetime_rec; 1117 } 1118 1119 /* We need to give the caller the flags which are in use */ 1120 if (ret_flags) *ret_flags = ctx->flags; 1121 1122 if (src_name) { 1123 kret = krb5_copy_principal(context, 1124 ctx->source, 1125 (gsskrb5_name*)src_name); 1126 if (kret) { 1127 *minor_status = kret; 1128 return GSS_S_FAILURE; 1129 } 1130 } 1131 1132 /* 1133 * After the krb5_rd_rep() the remote and local seq_number should 1134 * be the same, because the client just replies the seq_number 1135 * from our AP-REP in its AP-REP, but then the client uses the 1136 * seq_number from its AP-REQ for GSS_wrap() 1137 */ 1138 { 1139 int32_t tmp_r_seq_number, tmp_l_seq_number; 1140 1141 kret = krb5_auth_con_getremoteseqnumber(context, 1142 ctx->auth_context, 1143 &tmp_r_seq_number); 1144 if (kret) { 1145 *minor_status = kret; 1146 return GSS_S_FAILURE; 1147 } 1148 1149 kret = krb5_auth_con_getlocalseqnumber(context, 1150 ctx->auth_context, 1151 &tmp_l_seq_number); 1152 if (kret) { 1153 1154 *minor_status = kret; 1155 return GSS_S_FAILURE; 1156 } 1157 1158 /* 1159 * Here we check if the client has responsed with our local seq_number, 1160 */ 1161 if (tmp_r_seq_number != tmp_l_seq_number) { 1162 return GSS_S_UNSEQ_TOKEN; 1163 } 1164 } 1165 1166 /* 1167 * We need to reset the remote seq_number, because the client will use, 1168 * the old one for the GSS_wrap() calls 1169 */ 1170 { 1171 kret = krb5_auth_con_setremoteseqnumber(context, 1172 ctx->auth_context, 1173 r_seq_number); 1174 if (kret) { 1175 *minor_status = kret; 1176 return GSS_S_FAILURE; 1177 } 1178 } 1179 1180 return gsskrb5_acceptor_ready(minor_status, ctx, context, 1181 delegated_cred_handle); 1182} 1183 1184 1185static OM_uint32 1186accept_sec_context(OM_uint32 * minor_status, 1187 gss_ctx_id_t * context_handle, 1188 const gss_cred_id_t acceptor_cred_handle, 1189 const gss_buffer_t input_token_buffer, 1190 const gss_channel_bindings_t input_chan_bindings, 1191 gss_name_t * src_name, 1192 gss_OID * mech_type, 1193 gss_buffer_t output_token, 1194 OM_uint32 * ret_flags, 1195 OM_uint32 * time_rec, 1196 gss_cred_id_t * delegated_cred_handle, 1197 gss_OID mech, 1198 gsskrb5_acceptor_state acceptor_state) 1199{ 1200 krb5_context context; 1201 OM_uint32 ret; 1202 gsskrb5_ctx ctx; 1203 1204 GSSAPI_KRB5_INIT(&context); 1205 1206 output_token->length = 0; 1207 output_token->value = NULL; 1208 1209 if (src_name != NULL) 1210 *src_name = NULL; 1211 if (mech_type) 1212 *mech_type = mech; 1213 1214 if (*context_handle == GSS_C_NO_CONTEXT) { 1215 ret = _gsskrb5_create_ctx(minor_status, 1216 context_handle, 1217 context, 1218 input_chan_bindings, 1219 mech); 1220 if (ret) 1221 return ret; 1222 1223 /* mark as acceptor */ 1224 ctx = (gsskrb5_ctx)*context_handle; 1225 ctx->gk5c.flags |= GK5C_ACCEPTOR; 1226 1227 ctx->acceptor_state = acceptor_state; 1228 } else { 1229 ctx = (gsskrb5_ctx)*context_handle; 1230 } 1231 1232 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1233 1234 do { 1235 ret = ctx->acceptor_state(minor_status, ctx, context, acceptor_cred_handle, 1236 input_token_buffer, input_chan_bindings, 1237 src_name, mech_type, output_token, ret_flags, 1238 time_rec, delegated_cred_handle); 1239 } while (output_token->length == 0 1240 && ret == GSS_S_COMPLETE && 1241 ctx->acceptor_state != step_acceptor_completed); 1242 1243 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1244 1245 if (GSS_ERROR(ret)) { 1246 OM_uint32 min2; 1247 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 1248 } 1249 1250 return ret; 1251} 1252 1253OM_uint32 1254_gsspku2u_accept_sec_context(OM_uint32 * minor_status, 1255 gss_ctx_id_t * context_handle, 1256 const gss_cred_id_t acceptor_cred_handle, 1257 const gss_buffer_t input_token_buffer, 1258 const gss_channel_bindings_t input_chan_bindings, 1259 gss_name_t * src_name, 1260 gss_OID * mech_type, 1261 gss_buffer_t output_token, 1262 OM_uint32 * ret_flags, 1263 OM_uint32 * time_rec, 1264 gss_cred_id_t * delegated_cred_handle) 1265{ 1266 return accept_sec_context(minor_status, 1267 context_handle, 1268 acceptor_cred_handle, 1269 input_token_buffer, 1270 input_chan_bindings, 1271 src_name, 1272 mech_type, 1273 output_token, 1274 ret_flags, 1275 time_rec, 1276 delegated_cred_handle, 1277 GSS_PKU2U_MECHANISM, 1278 pku2u_acceptor_start); 1279} 1280 1281OM_uint32 1282_gsskrb5_accept_sec_context(OM_uint32 * minor_status, 1283 gss_ctx_id_t * context_handle, 1284 const gss_cred_id_t acceptor_cred_handle, 1285 const gss_buffer_t input_token_buffer, 1286 const gss_channel_bindings_t input_chan_bindings, 1287 gss_name_t * src_name, 1288 gss_OID * mech_type, 1289 gss_buffer_t output_token, 1290 OM_uint32 * ret_flags, 1291 OM_uint32 * time_rec, 1292 gss_cred_id_t * delegated_cred_handle) 1293{ 1294 return accept_sec_context(minor_status, 1295 context_handle, 1296 acceptor_cred_handle, 1297 input_token_buffer, 1298 input_chan_bindings, 1299 src_name, 1300 mech_type, 1301 output_token, 1302 ret_flags, 1303 time_rec, 1304 delegated_cred_handle, 1305 GSS_KRB5_MECHANISM, 1306 gsskrb5_acceptor_start); 1307} 1308 1309OM_uint32 1310_gssiakerb_accept_sec_context(OM_uint32 * minor_status, 1311 gss_ctx_id_t * context_handle, 1312 const gss_cred_id_t acceptor_cred_handle, 1313 const gss_buffer_t input_token_buffer, 1314 const gss_channel_bindings_t input_chan_bindings, 1315 gss_name_t * src_name, 1316 gss_OID * mech_type, 1317 gss_buffer_t output_token, 1318 OM_uint32 * ret_flags, 1319 OM_uint32 * time_rec, 1320 gss_cred_id_t * delegated_cred_handle) 1321{ 1322 return accept_sec_context(minor_status, 1323 context_handle, 1324 acceptor_cred_handle, 1325 input_token_buffer, 1326 input_chan_bindings, 1327 src_name, 1328 mech_type, 1329 output_token, 1330 ret_flags, 1331 time_rec, 1332 delegated_cred_handle, 1333 GSS_IAKERB_MECHANISM, 1334 iakerb_acceptor_start); 1335} 1336