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 krb5_error_code ret; 381 OM_uint32 maj_stat; 382 /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which 383 tells windows to try again with the corrected timestamp. See 384 [MS-KILE] 2.2.1 KERB-ERROR-DATA */ 385 krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") }; 386 387 /* build server from request if the acceptor had not selected one */ 388 if (server == NULL && indata) { 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 *minor_status = ret; 414 return GSS_S_FAILURE; 415 } 416 417 *minor_status = 0; 418 return GSS_S_CONTINUE_NEEDED; 419} 420 421static OM_uint32 422iakerb_acceptor_start(OM_uint32 * minor_status, 423 gsskrb5_ctx ctx, 424 krb5_context context, 425 const gss_cred_id_t acceptor_cred_handle, 426 const gss_buffer_t input_token_buffer, 427 const gss_channel_bindings_t input_chan_bindings, 428 gss_name_t * src_name, 429 gss_OID * mech_type, 430 gss_buffer_t output_token, 431 OM_uint32 * ret_flags, 432 OM_uint32 * time_rec, 433 gss_cred_id_t * delegated_cred_handle) 434{ 435 krb5_data indata, outdata; 436 gss_buffer_desc idata; 437 krb5_error_code kret; 438 heim_ipc ictx; 439 OM_uint32 ret; 440 441 if (ctx->messages == NULL) { 442 ctx->messages = krb5_storage_emem(); 443 if (ctx->messages == NULL) { 444 *minor_status = ENOMEM; 445 return GSS_S_FAILURE; 446 } 447 } 448 449 ret = _gsskrb5_iakerb_parse_header(minor_status, context, ctx, input_token_buffer, &indata); 450 if (ret == GSS_S_DEFECTIVE_TOKEN) { 451 ctx->acceptor_state = gsskrb5_acceptor_start; 452 return GSS_S_COMPLETE; 453 } else if (ret != GSS_S_COMPLETE) 454 return ret; 455 456 krb5_storage_write(ctx->messages, 457 input_token_buffer->value, 458 input_token_buffer->length); 459 460 idata.value = indata.data; 461 idata.length = indata.length; 462 463 heim_assert(ctx->iakerbrealm != NULL, "realm not set by decoder, non OPT value"); 464 465 if (krb5_realm_is_lkdc(ctx->iakerbrealm)) { 466 467 kret = heim_ipc_init_context("ANY:org.h5l.kdc", &ictx); 468 if (kret) { 469 *minor_status = kret; 470 return GSS_S_FAILURE; 471 } 472 473 kret = heim_ipc_call(ictx, &indata, &outdata, NULL); 474 heim_ipc_free_context(ictx); 475 if (kret) { 476 _gsskrb5_error_token(minor_status, ctx->mech, context, kret, 477 NULL, NULL, output_token); 478 *minor_status = kret; 479 return GSS_S_FAILURE; 480 } 481 482 ret = _gsskrb5_iakerb_make_header(minor_status, context, ctx, ctx->iakerbrealm, &outdata, output_token); 483 heim_ipc_free_data(&outdata); 484 if (ret) 485 return ret; 486 487 } else { 488 /* XXX dont support non local realms right now */ 489 *minor_status = EINVAL; 490 return GSS_S_FAILURE; 491 } 492 493 krb5_storage_write(ctx->messages, 494 output_token->value, 495 output_token->length); 496 497 return GSS_S_CONTINUE_NEEDED; 498} 499 500 501static OM_uint32 502pku2u_acceptor_start(OM_uint32 * minor_status, 503 gsskrb5_ctx ctx, 504 krb5_context context, 505 const gss_cred_id_t acceptor_cred_handle, 506 const gss_buffer_t input_token_buffer, 507 const gss_channel_bindings_t input_chan_bindings, 508 gss_name_t * src_name, 509 gss_OID * mech_type, 510 gss_buffer_t output_token, 511 OM_uint32 * ret_flags, 512 OM_uint32 * time_rec, 513 gss_cred_id_t * delegated_cred_handle) 514{ 515 krb5_data indata, outdata; 516 krb5_error_code kret; 517 heim_ipc ictx; 518 OM_uint32 ret; 519 520 if (ctx->messages == NULL) { 521 ctx->messages = krb5_storage_emem(); 522 if (ctx->messages == NULL) { 523 *minor_status = ENOMEM; 524 return GSS_S_FAILURE; 525 } 526 } 527 528 ret = _gsskrb5_decapsulate (minor_status, 529 input_token_buffer, 530 &indata, 531 "\x05\x01", 532 ctx->mech); 533 if (ret == GSS_S_DEFECTIVE_TOKEN) { 534 ctx->acceptor_state = gsskrb5_acceptor_start; 535 return GSS_S_COMPLETE; 536 } else if (ret != GSS_S_COMPLETE) 537 return ret; 538 539 krb5_storage_write(ctx->messages, 540 input_token_buffer->value, 541 input_token_buffer->length); 542 543 kret = heim_ipc_init_context("ANY:org.h5l.kdc", &ictx); 544 if (kret) { 545 *minor_status = kret; 546 return GSS_S_FAILURE; 547 } 548 549 550 ret = _gsskrb5_encapsulate(minor_status, 551 &outdata, 552 output_token, 553 "\x06\x00", 554 ctx->mech); 555 heim_ipc_free_data(&outdata); 556 if (ret != GSS_S_COMPLETE) 557 return ret; 558 559 krb5_storage_write(ctx->messages, 560 output_token->value, 561 output_token->length); 562 563 564 *minor_status = 0; 565 return GSS_S_FAILURE; 566} 567 568static OM_uint32 569gsskrb5_acceptor_start(OM_uint32 * minor_status, 570 gsskrb5_ctx ctx, 571 krb5_context context, 572 const gss_cred_id_t acceptor_cred_handle, 573 const gss_buffer_t input_token_buffer, 574 const gss_channel_bindings_t input_chan_bindings, 575 gss_name_t * src_name, 576 gss_OID * mech_type, 577 gss_buffer_t output_token, 578 OM_uint32 * ret_flags, 579 OM_uint32 * time_rec, 580 gss_cred_id_t * delegated_cred_handle) 581{ 582 krb5_error_code kret; 583 OM_uint32 ret = GSS_S_COMPLETE; 584 krb5_data indata; 585 krb5_flags ap_options; 586 krb5_keytab keytab = NULL; 587 int is_cfx = 0; 588 const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle; 589 krb5_boolean is_hostbased_service = FALSE; 590 591 /* 592 * We may, or may not, have an escapsulation. 593 */ 594 ret = _gsskrb5_decapsulate (minor_status, 595 input_token_buffer, 596 &indata, 597 "\x01\x00", 598 ctx->mech); 599 600 if (ret) { 601 /* Assume that there is no OID wrapping. */ 602 indata.length = input_token_buffer->length; 603 indata.data = input_token_buffer->value; 604 } 605 606 /* 607 * We need to get our keytab 608 */ 609 if (acceptor_cred == NULL) { 610 if (_gsskrb5_keytab != NULL) 611 keytab = _gsskrb5_keytab; 612 } else if (acceptor_cred->keytab != NULL) { 613 keytab = acceptor_cred->keytab; 614 } 615 616 is_hostbased_service = 617 (acceptor_cred && 618 acceptor_cred->principal && 619 krb5_principal_is_gss_hostbased_service(context, acceptor_cred->principal)); 620 621 /* 622 * We need to check the ticket and create the AP-REP packet 623 */ 624 625 { 626 krb5_rd_req_in_ctx in = NULL; 627 krb5_rd_req_out_ctx out = NULL; 628 krb5_principal server = NULL; 629 630 if (acceptor_cred && !is_hostbased_service) 631 server = acceptor_cred->principal; 632 633 kret = krb5_rd_req_in_ctx_alloc(context, &in); 634 if (kret == 0) 635 kret = krb5_rd_req_in_set_keytab(context, in, keytab); 636 if (kret) { 637 if (in) 638 krb5_rd_req_in_ctx_free(context, in); 639 *minor_status = kret; 640 return GSS_S_FAILURE; 641 } 642 643 kret = krb5_rd_req_ctx(context, 644 &ctx->auth_context, 645 &indata, 646 server, 647 in, &out); 648 krb5_rd_req_in_ctx_free(context, in); 649 switch (kret) { 650 case 0: 651 break; 652 case KRB5KRB_AP_ERR_SKEW: 653 case KRB5KRB_AP_ERR_TKT_NYV: 654 /* 655 * No reply in non-MUTUAL mode, but we don't know that its 656 * non-MUTUAL mode yet, thats inside the 8003 checksum, so 657 * lets only send the error token on clock skew, that 658 * limit when send error token for non-MUTUAL. 659 */ 660 return send_error_token(minor_status, context, kret, 661 server, &indata, ctx->mech, output_token); 662 case KRB5KRB_AP_ERR_MODIFIED: 663 case KRB5_KT_NOTFOUND: 664 case KRB5_KT_END: 665 /* 666 * If the error is on the keytab entry missing or bad 667 * decryption, lets assume that the keytab version was 668 * wrong and tell the client that. 669 */ 670 return send_error_token(minor_status, context, KRB5KRB_AP_ERR_MODIFIED, 671 server, NULL, ctx->mech, output_token); 672 default: 673 *minor_status = kret; 674 return GSS_S_FAILURE; 675 } 676 677 /* 678 * we need to remember some data on the context_handle. 679 */ 680 kret = krb5_rd_req_out_get_ap_req_options(context, out, 681 &ap_options); 682 if (kret == 0) 683 kret = krb5_rd_req_out_get_ticket(context, out, 684 &ctx->ticket); 685 if (kret == 0) 686 kret = krb5_rd_req_out_get_keyblock(context, out, 687 &ctx->service_keyblock); 688 if (kret == 0) { 689 int flags; 690 flags = krb5_rd_req_out_get_flags(context, out); 691 if (flags & KRB5_RD_REQ_OUT_PAC_VALID) 692 ctx->more_flags |= PAC_VALID; 693 } 694 if (kret == 0 && is_hostbased_service) { 695 krb5_principal sp = ctx->ticket->server; 696 697 if (sp->name.name_string.len < 1 || 698 strcmp(sp->name.name_string.val[0], acceptor_cred->principal->name.name_string.val[0]) != 0) 699 { 700 kret = KRB5KRB_AP_WRONG_PRINC; 701 krb5_set_error_message(context, ret, "Expecting service %s but got %s", 702 acceptor_cred->principal->name.name_string.val[0], 703 sp->name.name_string.val[0]); 704 } 705 } 706 707 ctx->endtime = ctx->ticket->ticket.endtime; 708 709 krb5_rd_req_out_ctx_free(context, out); 710 if (kret) { 711 ret = GSS_S_FAILURE; 712 *minor_status = kret; 713 return ret; 714 } 715 } 716 717 718 /* 719 * We need to copy the principal names to the context and the 720 * calling layer. 721 */ 722 kret = krb5_copy_principal(context, 723 ctx->ticket->client, 724 &ctx->source); 725 if (kret) { 726 *minor_status = kret; 727 return GSS_S_FAILURE; 728 } 729 730 kret = krb5_copy_principal(context, 731 ctx->ticket->server, 732 &ctx->target); 733 if (kret) { 734 ret = GSS_S_FAILURE; 735 *minor_status = kret; 736 return ret; 737 } 738 739 /* 740 * We need to setup some compat stuff, this assumes that 741 * context_handle->target is already set. 742 */ 743 ret = _gss_DES3_get_mic_compat(minor_status, ctx, context); 744 if (ret) 745 return ret; 746 747 if (src_name != NULL) { 748 kret = krb5_copy_principal (context, 749 ctx->ticket->client, 750 (gsskrb5_name*)src_name); 751 if (kret) { 752 ret = GSS_S_FAILURE; 753 *minor_status = kret; 754 return ret; 755 } 756 } 757 758 /* 759 * We need to get the flags out of the 8003 checksum. 760 */ 761 762 { 763 krb5_authenticator authenticator; 764 765 kret = krb5_auth_con_getauthenticator(context, 766 ctx->auth_context, 767 &authenticator); 768 if(kret) { 769 ret = GSS_S_FAILURE; 770 *minor_status = kret; 771 return ret; 772 } 773 774 if (authenticator->cksum == NULL) { 775 krb5_free_authenticator(context, &authenticator); 776 *minor_status = 0; 777 return GSS_S_BAD_BINDINGS; 778 } 779 780 if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) { 781 krb5_data finished_data; 782 krb5_crypto crypto = NULL; 783 784 if (ctx->auth_context->remote_subkey) { 785 kret = krb5_crypto_init(context, 786 ctx->auth_context->remote_subkey, 787 0, &crypto); 788 if (kret) { 789 *minor_status = kret; 790 return GSS_S_FAILURE; 791 } 792 } 793 794 krb5_data_zero(&finished_data); 795 796 ret = _gsskrb5_verify_8003_checksum(minor_status, 797 context, 798 crypto, 799 input_chan_bindings, 800 authenticator->cksum, 801 &ctx->flags, 802 &ctx->fwd_data, 803 &finished_data); 804 805 krb5_free_authenticator(context, &authenticator); 806 if (ret) { 807 krb5_crypto_destroy(context, crypto); 808 return ret; 809 } 810 811 if (finished_data.length) { 812 GSS_KRB5_FINISHED finished; 813 krb5_data pkt; 814 815 memset(&finished, 0, sizeof(finished)); 816 817 if (ctx->messages == NULL) { 818 krb5_crypto_destroy(context, crypto); 819 krb5_data_free(&finished_data); 820 *minor_status = 0; 821 return GSS_S_BAD_SIG; 822 } 823 824 kret = krb5_storage_to_data(ctx->messages, &pkt); 825 if (kret) { 826 krb5_crypto_destroy(context, crypto); 827 krb5_data_free(&finished_data); 828 *minor_status = kret; 829 return GSS_S_FAILURE; 830 } 831 832 if (ctx->auth_context->remote_subkey == NULL) { 833 krb5_crypto_destroy(context, crypto); 834 krb5_data_free(&finished_data); 835 krb5_data_free(&pkt); 836 *minor_status = 0; 837 return GSS_S_BAD_SIG; 838 } 839 840 kret = decode_GSS_KRB5_FINISHED(finished_data.data, 841 finished_data.length, 842 &finished, NULL); 843 krb5_data_free(&finished_data); 844 if (kret) { 845 krb5_crypto_destroy(context, crypto); 846 krb5_data_free(&pkt); 847 *minor_status = kret; 848 return GSS_S_FAILURE; 849 } 850 851 kret = krb5_verify_checksum(context, crypto, 852 KRB5_KU_FINISHED, 853 pkt.data, pkt.length, 854 &finished.gss_mic); 855 free_GSS_KRB5_FINISHED(&finished); 856 krb5_data_free(&pkt); 857 if (kret) { 858 krb5_crypto_destroy(context, crypto); 859 *minor_status = kret; 860 return GSS_S_FAILURE; 861 } 862 } 863 krb5_crypto_destroy(context, crypto); 864 865 } else { 866 krb5_crypto crypto; 867 868 kret = krb5_crypto_init(context, 869 ctx->auth_context->keyblock, 870 0, &crypto); 871 if(kret) { 872 krb5_free_authenticator(context, &authenticator); 873 874 ret = GSS_S_FAILURE; 875 *minor_status = kret; 876 return ret; 877 } 878 879 /* 880 * Windows accepts Samba3's use of a kerberos, rather than 881 * GSSAPI checksum here 882 */ 883 884 kret = krb5_verify_checksum(context, 885 crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0, 886 authenticator->cksum); 887 krb5_free_authenticator(context, &authenticator); 888 krb5_crypto_destroy(context, crypto); 889 890 if(kret) { 891 ret = GSS_S_BAD_SIG; 892 *minor_status = kret; 893 return ret; 894 } 895 896 /* 897 * Samba style get some flags (but not DCE-STYLE), use 898 * ap_options to guess the mutual flag. 899 */ 900 ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG; 901 if (ap_options & AP_OPTS_MUTUAL_REQUIRED) 902 ctx->flags |= GSS_C_MUTUAL_FLAG; 903 } 904 } 905 906 if(ctx->flags & GSS_C_MUTUAL_FLAG) { 907 krb5_data outbuf; 908 int use_subkey = 0; 909 910 _gsskrb5i_is_cfx(context, ctx, 1); 911 is_cfx = (ctx->more_flags & IS_CFX); 912 913 if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) { 914 use_subkey = 1; 915 } else { 916 krb5_keyblock *rkey; 917 918 /* 919 * If there is a initiator subkey, copy that to acceptor 920 * subkey to match Windows behavior 921 */ 922 kret = krb5_auth_con_getremotesubkey(context, 923 ctx->auth_context, 924 &rkey); 925 if (kret == 0) { 926 kret = krb5_auth_con_setlocalsubkey(context, 927 ctx->auth_context, 928 rkey); 929 if (kret == 0) 930 use_subkey = 1; 931 krb5_free_keyblock(context, rkey); 932 } 933 } 934 if (use_subkey) { 935 ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY; 936 krb5_auth_con_addflags(context, ctx->auth_context, 937 KRB5_AUTH_CONTEXT_USE_SUBKEY, 938 NULL); 939 } 940 941 kret = krb5_mk_rep(context, 942 ctx->auth_context, 943 &outbuf); 944 if (kret) { 945 *minor_status = kret; 946 return GSS_S_FAILURE; 947 } 948 949 if (IS_DCE_STYLE(ctx)) { 950 output_token->length = outbuf.length; 951 output_token->value = outbuf.data; 952 } else { 953 ret = _gsskrb5_encapsulate(minor_status, 954 &outbuf, 955 output_token, 956 "\x02\x00", 957 ctx->mech); 958 krb5_data_free (&outbuf); 959 if (ret) 960 return ret; 961 } 962 } 963 964 ctx->flags |= GSS_C_TRANS_FLAG; 965 966 /* Remember the flags */ 967 968 ctx->endtime = ctx->ticket->ticket.endtime; 969 ctx->more_flags |= OPEN; 970 971 if (mech_type) 972 *mech_type = ctx->mech; 973 974 if (time_rec) { 975 ret = _gsskrb5_lifetime_left(minor_status, 976 context, 977 ctx->endtime, 978 time_rec); 979 if (ret) { 980 return ret; 981 } 982 } 983 984 /* 985 * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from 986 * the client. 987 */ 988 if (IS_DCE_STYLE(ctx)) { 989 /* 990 * Return flags to caller, but we haven't processed 991 * delgations yet 992 */ 993 if (ret_flags) 994 *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG); 995 996 ctx->acceptor_state = acceptor_wait_for_dcestyle; 997 return GSS_S_CONTINUE_NEEDED; 998 } 999 1000 ret = gsskrb5_acceptor_ready(minor_status, ctx, context, 1001 delegated_cred_handle); 1002 1003 if (ret_flags) 1004 *ret_flags = ctx->flags; 1005 1006 return ret; 1007} 1008 1009static OM_uint32 1010acceptor_wait_for_dcestyle(OM_uint32 * minor_status, 1011 gsskrb5_ctx ctx, 1012 krb5_context context, 1013 const gss_cred_id_t acceptor_cred_handle, 1014 const gss_buffer_t input_token_buffer, 1015 const gss_channel_bindings_t input_chan_bindings, 1016 gss_name_t * src_name, 1017 gss_OID * mech_type, 1018 gss_buffer_t output_token, 1019 OM_uint32 * ret_flags, 1020 OM_uint32 * time_rec, 1021 gss_cred_id_t * delegated_cred_handle) 1022{ 1023 OM_uint32 ret; 1024 krb5_error_code kret; 1025 krb5_data inbuf; 1026 int32_t r_seq_number, l_seq_number; 1027 1028 /* 1029 * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP 1030 */ 1031 1032 inbuf.length = input_token_buffer->length; 1033 inbuf.data = input_token_buffer->value; 1034 1035 /* 1036 * We need to remeber the old remote seq_number, then check if the 1037 * client has replied with our local seq_number, and then reset 1038 * the remote seq_number to the old value 1039 */ 1040 { 1041 kret = krb5_auth_con_getlocalseqnumber(context, 1042 ctx->auth_context, 1043 &l_seq_number); 1044 if (kret) { 1045 *minor_status = kret; 1046 return GSS_S_FAILURE; 1047 } 1048 1049 kret = krb5_auth_con_getremoteseqnumber(context, 1050 ctx->auth_context, 1051 &r_seq_number); 1052 if (kret) { 1053 *minor_status = kret; 1054 return GSS_S_FAILURE; 1055 } 1056 1057 kret = krb5_auth_con_setremoteseqnumber(context, 1058 ctx->auth_context, 1059 l_seq_number); 1060 if (kret) { 1061 *minor_status = kret; 1062 return GSS_S_FAILURE; 1063 } 1064 } 1065 1066 /* 1067 * We need to verify the AP_REP, but we need to flag that this is 1068 * DCE_STYLE, so don't check the timestamps this time, but put the 1069 * flag DO_TIME back afterward. 1070 */ 1071 { 1072 krb5_ap_rep_enc_part *repl; 1073 int32_t auth_flags; 1074 1075 krb5_auth_con_removeflags(context, 1076 ctx->auth_context, 1077 KRB5_AUTH_CONTEXT_DO_TIME, 1078 &auth_flags); 1079 1080 kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl); 1081 if (kret) { 1082 *minor_status = kret; 1083 return GSS_S_FAILURE; 1084 } 1085 krb5_free_ap_rep_enc_part(context, repl); 1086 krb5_auth_con_setflags(context, ctx->auth_context, auth_flags); 1087 } 1088 1089 /* We need to check the liftime */ 1090 { 1091 OM_uint32 lifetime_rec; 1092 1093 ret = _gsskrb5_lifetime_left(minor_status, 1094 context, 1095 ctx->endtime, 1096 &lifetime_rec); 1097 if (ret) { 1098 return ret; 1099 } 1100 if (lifetime_rec == 0) { 1101 return GSS_S_CONTEXT_EXPIRED; 1102 } 1103 1104 if (time_rec) *time_rec = lifetime_rec; 1105 } 1106 1107 /* We need to give the caller the flags which are in use */ 1108 if (ret_flags) *ret_flags = ctx->flags; 1109 1110 if (src_name) { 1111 kret = krb5_copy_principal(context, 1112 ctx->source, 1113 (gsskrb5_name*)src_name); 1114 if (kret) { 1115 *minor_status = kret; 1116 return GSS_S_FAILURE; 1117 } 1118 } 1119 1120 /* 1121 * After the krb5_rd_rep() the remote and local seq_number should 1122 * be the same, because the client just replies the seq_number 1123 * from our AP-REP in its AP-REP, but then the client uses the 1124 * seq_number from its AP-REQ for GSS_wrap() 1125 */ 1126 { 1127 int32_t tmp_r_seq_number, tmp_l_seq_number; 1128 1129 kret = krb5_auth_con_getremoteseqnumber(context, 1130 ctx->auth_context, 1131 &tmp_r_seq_number); 1132 if (kret) { 1133 *minor_status = kret; 1134 return GSS_S_FAILURE; 1135 } 1136 1137 kret = krb5_auth_con_getlocalseqnumber(context, 1138 ctx->auth_context, 1139 &tmp_l_seq_number); 1140 if (kret) { 1141 1142 *minor_status = kret; 1143 return GSS_S_FAILURE; 1144 } 1145 1146 /* 1147 * Here we check if the client has responsed with our local seq_number, 1148 */ 1149 if (tmp_r_seq_number != tmp_l_seq_number) { 1150 return GSS_S_UNSEQ_TOKEN; 1151 } 1152 } 1153 1154 /* 1155 * We need to reset the remote seq_number, because the client will use, 1156 * the old one for the GSS_wrap() calls 1157 */ 1158 { 1159 kret = krb5_auth_con_setremoteseqnumber(context, 1160 ctx->auth_context, 1161 r_seq_number); 1162 if (kret) { 1163 *minor_status = kret; 1164 return GSS_S_FAILURE; 1165 } 1166 } 1167 1168 return gsskrb5_acceptor_ready(minor_status, ctx, context, 1169 delegated_cred_handle); 1170} 1171 1172 1173static OM_uint32 1174accept_sec_context(OM_uint32 * minor_status, 1175 gss_ctx_id_t * context_handle, 1176 const gss_cred_id_t acceptor_cred_handle, 1177 const gss_buffer_t input_token_buffer, 1178 const gss_channel_bindings_t input_chan_bindings, 1179 gss_name_t * src_name, 1180 gss_OID * mech_type, 1181 gss_buffer_t output_token, 1182 OM_uint32 * ret_flags, 1183 OM_uint32 * time_rec, 1184 gss_cred_id_t * delegated_cred_handle, 1185 gss_OID mech, 1186 gsskrb5_acceptor_state acceptor_state) 1187{ 1188 krb5_context context; 1189 OM_uint32 ret; 1190 gsskrb5_ctx ctx; 1191 1192 GSSAPI_KRB5_INIT(&context); 1193 1194 output_token->length = 0; 1195 output_token->value = NULL; 1196 1197 if (src_name != NULL) 1198 *src_name = NULL; 1199 if (mech_type) 1200 *mech_type = mech; 1201 1202 if (*context_handle == GSS_C_NO_CONTEXT) { 1203 ret = _gsskrb5_create_ctx(minor_status, 1204 context_handle, 1205 context, 1206 input_chan_bindings, 1207 mech); 1208 if (ret) 1209 return ret; 1210 1211 /* mark as acceptor */ 1212 ctx = (gsskrb5_ctx)*context_handle; 1213 ctx->gk5c.flags |= GK5C_ACCEPTOR; 1214 1215 ctx->acceptor_state = acceptor_state; 1216 } else { 1217 ctx = (gsskrb5_ctx)*context_handle; 1218 } 1219 1220 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); 1221 1222 do { 1223 ret = ctx->acceptor_state(minor_status, ctx, context, acceptor_cred_handle, 1224 input_token_buffer, input_chan_bindings, 1225 src_name, mech_type, output_token, ret_flags, 1226 time_rec, delegated_cred_handle); 1227 } while (output_token->length == 0 1228 && ret == GSS_S_COMPLETE && 1229 ctx->acceptor_state != step_acceptor_completed); 1230 1231 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); 1232 1233 if (GSS_ERROR(ret)) { 1234 OM_uint32 min2; 1235 _gsskrb5_delete_sec_context(&min2, context_handle, GSS_C_NO_BUFFER); 1236 } 1237 1238 return ret; 1239} 1240 1241OM_uint32 1242_gsspku2u_accept_sec_context(OM_uint32 * minor_status, 1243 gss_ctx_id_t * context_handle, 1244 const gss_cred_id_t acceptor_cred_handle, 1245 const gss_buffer_t input_token_buffer, 1246 const gss_channel_bindings_t input_chan_bindings, 1247 gss_name_t * src_name, 1248 gss_OID * mech_type, 1249 gss_buffer_t output_token, 1250 OM_uint32 * ret_flags, 1251 OM_uint32 * time_rec, 1252 gss_cred_id_t * delegated_cred_handle) 1253{ 1254 return accept_sec_context(minor_status, 1255 context_handle, 1256 acceptor_cred_handle, 1257 input_token_buffer, 1258 input_chan_bindings, 1259 src_name, 1260 mech_type, 1261 output_token, 1262 ret_flags, 1263 time_rec, 1264 delegated_cred_handle, 1265 GSS_PKU2U_MECHANISM, 1266 pku2u_acceptor_start); 1267} 1268 1269OM_uint32 1270_gsskrb5_accept_sec_context(OM_uint32 * minor_status, 1271 gss_ctx_id_t * context_handle, 1272 const gss_cred_id_t acceptor_cred_handle, 1273 const gss_buffer_t input_token_buffer, 1274 const gss_channel_bindings_t input_chan_bindings, 1275 gss_name_t * src_name, 1276 gss_OID * mech_type, 1277 gss_buffer_t output_token, 1278 OM_uint32 * ret_flags, 1279 OM_uint32 * time_rec, 1280 gss_cred_id_t * delegated_cred_handle) 1281{ 1282 return accept_sec_context(minor_status, 1283 context_handle, 1284 acceptor_cred_handle, 1285 input_token_buffer, 1286 input_chan_bindings, 1287 src_name, 1288 mech_type, 1289 output_token, 1290 ret_flags, 1291 time_rec, 1292 delegated_cred_handle, 1293 GSS_KRB5_MECHANISM, 1294 gsskrb5_acceptor_start); 1295} 1296 1297OM_uint32 1298_gssiakerb_accept_sec_context(OM_uint32 * minor_status, 1299 gss_ctx_id_t * context_handle, 1300 const gss_cred_id_t acceptor_cred_handle, 1301 const gss_buffer_t input_token_buffer, 1302 const gss_channel_bindings_t input_chan_bindings, 1303 gss_name_t * src_name, 1304 gss_OID * mech_type, 1305 gss_buffer_t output_token, 1306 OM_uint32 * ret_flags, 1307 OM_uint32 * time_rec, 1308 gss_cred_id_t * delegated_cred_handle) 1309{ 1310 return accept_sec_context(minor_status, 1311 context_handle, 1312 acceptor_cred_handle, 1313 input_token_buffer, 1314 input_chan_bindings, 1315 src_name, 1316 mech_type, 1317 output_token, 1318 ret_flags, 1319 time_rec, 1320 delegated_cred_handle, 1321 GSS_IAKERB_MECHANISM, 1322 iakerb_acceptor_start); 1323} 1324