1/* 2 * Copyright (c) 1997-2008 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 "kdc_locl.h" 37 38/* 39 * return the realm of a krbtgt-ticket or NULL 40 */ 41 42static Realm 43get_krbtgt_realm(const PrincipalName *p) 44{ 45 if(p->name_string.len == 2 46 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0) 47 return p->name_string.val[1]; 48 else 49 return NULL; 50} 51 52/* 53 * The KDC might add a signed path to the ticket authorization data 54 * field. This is to avoid server impersonating clients and the 55 * request constrained delegation. 56 * 57 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single 58 * entry of type KRB5SignedPath. 59 */ 60 61static krb5_error_code 62find_KRB5SignedPath(krb5_context context, 63 const AuthorizationData *ad, 64 krb5_data *data) 65{ 66 AuthorizationData child; 67 krb5_error_code ret; 68 int pos; 69 70 if (ad == NULL || ad->len == 0) 71 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 72 73 pos = ad->len - 1; 74 75 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 76 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 77 78 ret = decode_AuthorizationData(ad->val[pos].ad_data.data, 79 ad->val[pos].ad_data.length, 80 &child, 81 NULL); 82 if (ret) { 83 krb5_set_error_message(context, ret, "Failed to decode " 84 "IF_RELEVANT with %d", ret); 85 return ret; 86 } 87 88 if (child.len != 1) { 89 free_AuthorizationData(&child); 90 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 91 } 92 93 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) { 94 free_AuthorizationData(&child); 95 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 96 } 97 98 if (data) 99 ret = der_copy_octet_string(&child.val[0].ad_data, data); 100 free_AuthorizationData(&child); 101 return ret; 102} 103 104krb5_error_code 105_kdc_add_KRB5SignedPath(krb5_context context, 106 krb5_kdc_configuration *config, 107 hdb_entry_ex *krbtgt, 108 krb5_enctype enctype, 109 krb5_principal client, 110 krb5_const_principal server, 111 krb5_principals principals, 112 EncTicketPart *tkt) 113{ 114 krb5_error_code ret; 115 KRB5SignedPath sp; 116 krb5_data data; 117 krb5_crypto crypto = NULL; 118 size_t size = 0; 119 120 if (server && principals) { 121 ret = add_Principals(principals, server); 122 if (ret) 123 return ret; 124 } 125 126 { 127 KRB5SignedPathData spd; 128 129 spd.client = client; 130 spd.authtime = tkt->authtime; 131 spd.delegated = principals; 132 spd.method_data = NULL; 133 134 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 135 &spd, &size, ret); 136 if (ret) 137 return ret; 138 if (data.length != size) 139 krb5_abortx(context, "internal asn.1 encoder error"); 140 } 141 142 { 143 Key *key; 144 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key); 145 if (ret == 0) 146 ret = krb5_crypto_init(context, &key->key, 0, &crypto); 147 if (ret) { 148 free(data.data); 149 return ret; 150 } 151 } 152 153 /* 154 * Fill in KRB5SignedPath 155 */ 156 157 sp.etype = enctype; 158 sp.delegated = principals; 159 sp.method_data = NULL; 160 161 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0, 162 data.data, data.length, &sp.cksum); 163 krb5_crypto_destroy(context, crypto); 164 free(data.data); 165 if (ret) 166 return ret; 167 168 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret); 169 free_Checksum(&sp.cksum); 170 if (ret) 171 return ret; 172 if (data.length != size) 173 krb5_abortx(context, "internal asn.1 encoder error"); 174 175 176 /* 177 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in 178 * authorization data field. 179 */ 180 181 ret = _kdc_tkt_add_if_relevant_ad(context, tkt, 182 KRB5_AUTHDATA_SIGNTICKET, &data); 183 krb5_data_free(&data); 184 185 return ret; 186} 187 188static krb5_error_code 189check_KRB5SignedPath(krb5_context context, 190 krb5_kdc_configuration *config, 191 hdb_entry_ex *krbtgt, 192 krb5_principal cp, 193 EncTicketPart *tkt, 194 krb5_principals *delegated, 195 int *signedpath) 196{ 197 krb5_error_code ret; 198 krb5_data data; 199 krb5_crypto crypto = NULL; 200 201 if (delegated) 202 *delegated = NULL; 203 204 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data); 205 if (ret == 0) { 206 KRB5SignedPathData spd; 207 KRB5SignedPath sp; 208 size_t size = 0; 209 210 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL); 211 krb5_data_free(&data); 212 if (ret) 213 return ret; 214 215 spd.client = cp; 216 spd.authtime = tkt->authtime; 217 spd.delegated = sp.delegated; 218 spd.method_data = sp.method_data; 219 220 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length, 221 &spd, &size, ret); 222 if (ret) { 223 free_KRB5SignedPath(&sp); 224 return ret; 225 } 226 if (data.length != size) 227 krb5_abortx(context, "internal asn.1 encoder error"); 228 229 { 230 Key *key; 231 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key); 232 if (ret == 0) 233 ret = krb5_crypto_init(context, &key->key, 0, &crypto); 234 if (ret) { 235 free(data.data); 236 free_KRB5SignedPath(&sp); 237 return ret; 238 } 239 } 240 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 241 data.data, data.length, 242 &sp.cksum); 243 krb5_crypto_destroy(context, crypto); 244 free(data.data); 245 if (ret) { 246 free_KRB5SignedPath(&sp); 247 kdc_log(context, config, 5, 248 "KRB5SignedPath not signed correctly, not marking as signed"); 249 return 0; 250 } 251 252 if (delegated && sp.delegated) { 253 254 *delegated = malloc(sizeof(*sp.delegated)); 255 if (*delegated == NULL) { 256 free_KRB5SignedPath(&sp); 257 return ENOMEM; 258 } 259 260 ret = copy_Principals(*delegated, sp.delegated); 261 if (ret) { 262 free_KRB5SignedPath(&sp); 263 free(*delegated); 264 *delegated = NULL; 265 return ret; 266 } 267 } 268 free_KRB5SignedPath(&sp); 269 270 *signedpath = 1; 271 } 272 273 return 0; 274} 275 276/* 277 * 278 */ 279 280static krb5_error_code 281check_PAC(krb5_context context, 282 krb5_kdc_configuration *config, 283 const krb5_principal client_principal, 284 const krb5_principal delegated_proxy_principal, 285 hdb_entry_ex *client, 286 hdb_entry_ex *server, 287 hdb_entry_ex *krbtgt, 288 const EncryptionKey *server_check_key, 289 const EncryptionKey *krbtgt_check_key, 290 const EncryptionKey *server_sign_key, 291 const EncryptionKey *krbtgt_sign_key, 292 EncTicketPart *tkt, 293 krb5_data *rspac, 294 int *signedpath) 295{ 296 AuthorizationData *ad = tkt->authorization_data; 297 unsigned i, j; 298 krb5_error_code ret; 299 300 if (ad == NULL || ad->len == 0) 301 return 0; 302 303 for (i = 0; i < ad->len; i++) { 304 AuthorizationData child; 305 306 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT) 307 continue; 308 309 ret = decode_AuthorizationData(ad->val[i].ad_data.data, 310 ad->val[i].ad_data.length, 311 &child, 312 NULL); 313 if (ret) { 314 krb5_set_error_message(context, ret, "Failed to decode " 315 "IF_RELEVANT with %d", ret); 316 return ret; 317 } 318 for (j = 0; j < child.len; j++) { 319 320 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) { 321 int signed_pac = 0; 322 krb5_pac pac; 323 324 /* Found PAC */ 325 ret = krb5_pac_parse(context, 326 child.val[j].ad_data.data, 327 child.val[j].ad_data.length, 328 &pac); 329 free_AuthorizationData(&child); 330 if (ret) 331 return ret; 332 333 ret = krb5_pac_verify(context, pac, tkt->authtime, 334 client_principal, 335 server_check_key, krbtgt_check_key); 336 if (ret) { 337 krb5_pac_free(context, pac); 338 return ret; 339 } 340 341 ret = _kdc_pac_verify(context, client_principal, 342 delegated_proxy_principal, 343 client, server, krbtgt, &pac, &signed_pac); 344 if (ret) { 345 krb5_pac_free(context, pac); 346 return ret; 347 } 348 349 /* 350 * Only re-sign PAC if we could verify it with the PAC 351 * function. The no-verify case happens when we get in 352 * a PAC from cross realm from a Windows domain and 353 * that there is no PAC verification function. 354 */ 355 if (signed_pac) { 356 *signedpath = 1; 357 ret = _krb5_pac_sign(context, pac, tkt->authtime, 358 client_principal, 359 server_sign_key, krbtgt_sign_key, rspac); 360 } 361 krb5_pac_free(context, pac); 362 363 return ret; 364 } 365 } 366 free_AuthorizationData(&child); 367 } 368 return 0; 369} 370 371/* 372 * 373 */ 374 375static krb5_error_code 376check_tgs_flags(krb5_context context, 377 krb5_kdc_configuration *config, 378 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et) 379{ 380 KDCOptions f = b->kdc_options; 381 382 if(f.validate){ 383 if(!tgt->flags.invalid || tgt->starttime == NULL){ 384 kdc_log(context, config, 0, 385 "Bad request to validate ticket"); 386 return KRB5KDC_ERR_BADOPTION; 387 } 388 if(*tgt->starttime > kdc_time){ 389 kdc_log(context, config, 0, 390 "Early request to validate ticket"); 391 return KRB5KRB_AP_ERR_TKT_NYV; 392 } 393 /* XXX tkt = tgt */ 394 et->flags.invalid = 0; 395 }else if(tgt->flags.invalid){ 396 kdc_log(context, config, 0, 397 "Ticket-granting ticket has INVALID flag set"); 398 return KRB5KRB_AP_ERR_TKT_INVALID; 399 } 400 401 if(f.forwardable){ 402 if(!tgt->flags.forwardable){ 403 kdc_log(context, config, 0, 404 "Bad request for forwardable ticket"); 405 return KRB5KDC_ERR_BADOPTION; 406 } 407 et->flags.forwardable = 1; 408 } 409 if(f.forwarded){ 410 if(!tgt->flags.forwardable){ 411 kdc_log(context, config, 0, 412 "Request to forward non-forwardable ticket"); 413 return KRB5KDC_ERR_BADOPTION; 414 } 415 et->flags.forwarded = 1; 416 et->caddr = b->addresses; 417 } 418 if(tgt->flags.forwarded) 419 et->flags.forwarded = 1; 420 421 if(f.proxiable){ 422 if(!tgt->flags.proxiable){ 423 kdc_log(context, config, 0, 424 "Bad request for proxiable ticket"); 425 return KRB5KDC_ERR_BADOPTION; 426 } 427 et->flags.proxiable = 1; 428 } 429 if(f.proxy){ 430 if(!tgt->flags.proxiable){ 431 kdc_log(context, config, 0, 432 "Request to proxy non-proxiable ticket"); 433 return KRB5KDC_ERR_BADOPTION; 434 } 435 et->flags.proxy = 1; 436 et->caddr = b->addresses; 437 } 438 if(tgt->flags.proxy) 439 et->flags.proxy = 1; 440 441 if(f.allow_postdate){ 442 if(!tgt->flags.may_postdate){ 443 kdc_log(context, config, 0, 444 "Bad request for post-datable ticket"); 445 return KRB5KDC_ERR_BADOPTION; 446 } 447 et->flags.may_postdate = 1; 448 } 449 if(f.postdated){ 450 if(!tgt->flags.may_postdate){ 451 kdc_log(context, config, 0, 452 "Bad request for postdated ticket"); 453 return KRB5KDC_ERR_BADOPTION; 454 } 455 if(b->from) 456 *et->starttime = *b->from; 457 et->flags.postdated = 1; 458 et->flags.invalid = 1; 459 }else if(b->from && *b->from > kdc_time + context->max_skew){ 460 kdc_log(context, config, 0, "Ticket cannot be postdated"); 461 return KRB5KDC_ERR_CANNOT_POSTDATE; 462 } 463 464 if(f.renewable){ 465 if(!tgt->flags.renewable || tgt->renew_till == NULL){ 466 kdc_log(context, config, 0, 467 "Bad request for renewable ticket"); 468 return KRB5KDC_ERR_BADOPTION; 469 } 470 et->flags.renewable = 1; 471 ALLOC(et->renew_till); 472 _kdc_fix_time(&b->rtime); 473 *et->renew_till = *b->rtime; 474 } 475 if(f.renew){ 476 time_t old_life; 477 if(!tgt->flags.renewable || tgt->renew_till == NULL){ 478 kdc_log(context, config, 0, 479 "Request to renew non-renewable ticket"); 480 return KRB5KDC_ERR_BADOPTION; 481 } 482 old_life = tgt->endtime; 483 if(tgt->starttime) 484 old_life -= *tgt->starttime; 485 else 486 old_life -= tgt->authtime; 487 et->endtime = *et->starttime + old_life; 488 if (et->renew_till != NULL) 489 et->endtime = min(*et->renew_till, et->endtime); 490 } 491 492#if 0 493 /* checks for excess flags */ 494 if(f.request_anonymous && !config->allow_anonymous){ 495 kdc_log(context, config, 0, 496 "Request for anonymous ticket"); 497 return KRB5KDC_ERR_BADOPTION; 498 } 499#endif 500 return 0; 501} 502 503/* 504 * Determine if constrained delegation is allowed from this client to this server 505 */ 506 507static krb5_error_code 508check_constrained_delegation(krb5_context context, 509 krb5_kdc_configuration *config, 510 HDB *clientdb, 511 hdb_entry_ex *client, 512 hdb_entry_ex *server, 513 krb5_const_principal target) 514{ 515 const HDB_Ext_Constrained_delegation_acl *acl; 516 krb5_error_code ret; 517 size_t i; 518 519 /* 520 * constrained_delegation (S4U2Proxy) only works within 521 * the same realm. We use the already canonicalized version 522 * of the principals here, while "target" is the principal 523 * provided by the client. 524 */ 525 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) { 526 ret = KRB5KDC_ERR_BADOPTION; 527 kdc_log(context, config, 0, 528 "Bad request for constrained delegation"); 529 return ret; 530 } 531 532 if (clientdb->hdb_check_constrained_delegation) { 533 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target); 534 if (ret == 0) 535 return 0; 536 } else { 537 /* if client delegates to itself, that ok */ 538 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE) 539 return 0; 540 541 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl); 542 if (ret) { 543 krb5_clear_error_message(context); 544 return ret; 545 } 546 547 if (acl) { 548 for (i = 0; i < acl->len; i++) { 549 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE) 550 return 0; 551 } 552 } 553 ret = KRB5KDC_ERR_BADOPTION; 554 } 555 kdc_log(context, config, 0, 556 "Bad request for constrained delegation"); 557 return ret; 558} 559 560/* 561 * Determine if s4u2self is allowed from this client to this server 562 * 563 * For example, regardless of the principal being impersonated, if the 564 * 'client' and 'server' are the same, then it's safe. 565 */ 566 567static krb5_error_code 568check_s4u2self(krb5_context context, 569 krb5_kdc_configuration *config, 570 HDB *clientdb, 571 hdb_entry_ex *client, 572 krb5_const_principal server) 573{ 574 krb5_error_code ret; 575 576 /* if client does a s4u2self to itself, that ok */ 577 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE) 578 return 0; 579 580 if (clientdb->hdb_check_s4u2self) { 581 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server); 582 if (ret == 0) 583 return 0; 584 } else { 585 ret = KRB5KDC_ERR_BADOPTION; 586 } 587 return ret; 588} 589 590/* 591 * 592 */ 593 594static krb5_error_code 595verify_flags (krb5_context context, 596 krb5_kdc_configuration *config, 597 const EncTicketPart *et, 598 const char *pstr) 599{ 600 if(et->endtime < kdc_time){ 601 kdc_log(context, config, 0, "Ticket expired (%s)", pstr); 602 return KRB5KRB_AP_ERR_TKT_EXPIRED; 603 } 604 if(et->flags.invalid){ 605 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr); 606 return KRB5KRB_AP_ERR_TKT_NYV; 607 } 608 return 0; 609} 610 611/* 612 * 613 */ 614 615static krb5_error_code 616fix_transited_encoding(krb5_context context, 617 krb5_kdc_configuration *config, 618 krb5_boolean check_policy, 619 const TransitedEncoding *tr, 620 EncTicketPart *et, 621 const char *client_realm, 622 const char *server_realm, 623 const char *tgt_realm) 624{ 625 krb5_error_code ret = 0; 626 char **realms, **tmp; 627 unsigned int num_realms; 628 size_t i; 629 630 switch (tr->tr_type) { 631 case DOMAIN_X500_COMPRESS: 632 break; 633 case 0: 634 /* 635 * Allow empty content of type 0 because that is was Microsoft 636 * generates in their TGT. 637 */ 638 if (tr->contents.length == 0) 639 break; 640 kdc_log(context, config, 0, 641 "Transited type 0 with non empty content"); 642 return KRB5KDC_ERR_TRTYPE_NOSUPP; 643 default: 644 kdc_log(context, config, 0, 645 "Unknown transited type: %u", tr->tr_type); 646 return KRB5KDC_ERR_TRTYPE_NOSUPP; 647 } 648 649 ret = krb5_domain_x500_decode(context, 650 tr->contents, 651 &realms, 652 &num_realms, 653 client_realm, 654 server_realm); 655 if(ret){ 656 krb5_warn(context, ret, 657 "Decoding transited encoding"); 658 return ret; 659 } 660 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) { 661 /* not us, so add the previous realm to transited set */ 662 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) { 663 ret = ERANGE; 664 goto free_realms; 665 } 666 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms)); 667 if(tmp == NULL){ 668 ret = ENOMEM; 669 goto free_realms; 670 } 671 realms = tmp; 672 realms[num_realms] = strdup(tgt_realm); 673 if(realms[num_realms] == NULL){ 674 ret = ENOMEM; 675 goto free_realms; 676 } 677 num_realms++; 678 } 679 if(num_realms == 0) { 680 if(strcmp(client_realm, server_realm)) 681 kdc_log(context, config, 0, 682 "cross-realm %s -> %s", client_realm, server_realm); 683 } else { 684 size_t l = 0; 685 char *rs; 686 for(i = 0; i < num_realms; i++) 687 l += strlen(realms[i]) + 2; 688 rs = malloc(l); 689 if(rs != NULL) { 690 *rs = '\0'; 691 for(i = 0; i < num_realms; i++) { 692 if(i > 0) 693 strlcat(rs, ", ", l); 694 strlcat(rs, realms[i], l); 695 } 696 kdc_log(context, config, 0, 697 "cross-realm %s -> %s via [%s]", 698 client_realm, server_realm, rs); 699 free(rs); 700 } 701 } 702 if(check_policy) { 703 ret = krb5_check_transited(context, client_realm, 704 server_realm, 705 realms, num_realms, NULL); 706 if(ret) { 707 krb5_warn(context, ret, "cross-realm %s -> %s", 708 client_realm, server_realm); 709 goto free_realms; 710 } 711 et->flags.transited_policy_checked = 1; 712 } 713 et->transited.tr_type = DOMAIN_X500_COMPRESS; 714 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents); 715 if(ret) 716 krb5_warn(context, ret, "Encoding transited encoding"); 717 free_realms: 718 for(i = 0; i < num_realms; i++) 719 free(realms[i]); 720 free(realms); 721 return ret; 722} 723 724 725static krb5_error_code 726tgs_make_reply(kdc_request_t r, 727 KDC_REQ_BODY *b, 728 krb5_const_principal tgt_name, 729 const EncTicketPart *tgt, 730 const EncryptionKey *serverkey, 731 const krb5_keyblock *sessionkey, 732 krb5_kvno kvno, 733 AuthorizationData *auth_data, 734 hdb_entry_ex *server, 735 krb5_principal server_principal, 736 const char *server_name, 737 hdb_entry_ex *client, 738 krb5_principal client_principal, 739 hdb_entry_ex *krbtgt, 740 krb5_enctype krbtgt_etype, 741 krb5_principals spp, 742 const krb5_data *rspac, 743 const METHOD_DATA *enc_pa_data, 744 krb5_data *reply) 745{ 746 KDC_REP rep; 747 EncKDCRepPart ek; 748 EncTicketPart et; 749 KDCOptions f = b->kdc_options; 750 krb5_error_code ret; 751 int is_weak = 0; 752 753 memset(&rep, 0, sizeof(rep)); 754 memset(&et, 0, sizeof(et)); 755 memset(&ek, 0, sizeof(ek)); 756 757 rep.pvno = 5; 758 rep.msg_type = krb_tgs_rep; 759 760 et.authtime = tgt->authtime; 761 _kdc_fix_time(&b->till); 762 et.endtime = min(tgt->endtime, *b->till); 763 ALLOC(et.starttime); 764 *et.starttime = kdc_time; 765 766 ret = check_tgs_flags(r->context, r->config, b, tgt, &et); 767 if(ret) 768 goto out; 769 770 /* We should check the transited encoding if: 771 1) the request doesn't ask not to be checked 772 2) globally enforcing a check 773 3) principal requires checking 774 4) we allow non-check per-principal, but principal isn't marked as allowing this 775 5) we don't globally allow this 776 */ 777 778#define GLOBAL_FORCE_TRANSITED_CHECK \ 779 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK) 780#define GLOBAL_ALLOW_PER_PRINCIPAL \ 781 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL) 782#define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \ 783 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST) 784 785/* these will consult the database in future release */ 786#define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0 787#define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0 788 789 ret = fix_transited_encoding(r->context, r->config, 790 !f.disable_transited_check || 791 GLOBAL_FORCE_TRANSITED_CHECK /* || 792 PRINCIPAL_FORCE_TRANSITED_CHECK(server) */ || 793 !((GLOBAL_ALLOW_PER_PRINCIPAL /* && 794 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server) */ ) || 795 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK), 796 &tgt->transited, &et, 797 krb5_principal_get_realm(r->context, client_principal), 798 krb5_principal_get_realm(r->context, server->entry.principal), 799 krb5_principal_get_realm(r->context, krbtgt->entry.principal)); 800 if(ret) 801 goto out; 802 803 copy_Realm(&server_principal->realm, &rep.ticket.realm); 804 _krb5_principal2principalname(&rep.ticket.sname, server_principal); 805 copy_Realm(&tgt_name->realm, &rep.crealm); 806 807 copy_PrincipalName(&tgt_name->name, &rep.cname); 808 rep.ticket.tkt_vno = 5; 809 810 ek.caddr = et.caddr; 811 if(et.caddr == NULL) 812 et.caddr = tgt->caddr; 813 814 { 815 time_t life; 816 life = et.endtime - *et.starttime; 817 if(client && client->entry.max_life) 818 life = min(life, *client->entry.max_life); 819 if(server->entry.max_life) 820 life = min(life, *server->entry.max_life); 821 et.endtime = *et.starttime + life; 822 } 823 if(f.renewable_ok && tgt->flags.renewable && 824 et.renew_till == NULL && et.endtime < *b->till && 825 tgt->renew_till != NULL) 826 { 827 et.flags.renewable = 1; 828 ALLOC(et.renew_till); 829 *et.renew_till = *b->till; 830 } 831 if(et.renew_till){ 832 time_t renew; 833 renew = *et.renew_till - et.authtime; 834 if(client && client->entry.max_renew) 835 renew = min(renew, *client->entry.max_renew); 836 if(server->entry.max_renew) 837 renew = min(renew, *server->entry.max_renew); 838 *et.renew_till = et.authtime + renew; 839 } 840 841 if(et.renew_till){ 842 *et.renew_till = min(*et.renew_till, *tgt->renew_till); 843 *et.starttime = min(*et.starttime, *et.renew_till); 844 et.endtime = min(et.endtime, *et.renew_till); 845 } 846 847 *et.starttime = min(*et.starttime, et.endtime); 848 849 if(*et.starttime == et.endtime){ 850 ret = KRB5KDC_ERR_NEVER_VALID; 851 goto out; 852 } 853 if(et.renew_till && et.endtime == *et.renew_till){ 854 free(et.renew_till); 855 et.renew_till = NULL; 856 et.flags.renewable = 0; 857 } 858 859 et.flags.pre_authent = tgt->flags.pre_authent; 860 et.flags.hw_authent = tgt->flags.hw_authent; 861 et.flags.anonymous = tgt->flags.anonymous; 862 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate; 863 864 if(rspac->length) { 865 /* 866 * No not need to filter out the any PAC from the 867 * auth_data since it's signed by the KDC. 868 */ 869 ret = _kdc_tkt_add_if_relevant_ad(r->context, &et, 870 KRB5_AUTHDATA_WIN2K_PAC, rspac); 871 if (ret) 872 goto out; 873 } 874 875 if (auth_data) { 876 unsigned int i = 0; 877 878 /* XXX check authdata */ 879 880 if (et.authorization_data == NULL) { 881 et.authorization_data = calloc(1, sizeof(*et.authorization_data)); 882 if (et.authorization_data == NULL) { 883 ret = ENOMEM; 884 krb5_set_error_message(r->context, ret, "malloc: out of memory"); 885 goto out; 886 } 887 } 888 for(i = 0; i < auth_data->len ; i++) { 889 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]); 890 if (ret) { 891 krb5_set_error_message(r->context, ret, "malloc: out of memory"); 892 goto out; 893 } 894 } 895 896 /* Filter out type KRB5SignedPath */ 897 ret = find_KRB5SignedPath(r->context, et.authorization_data, NULL); 898 if (ret == 0) { 899 if (et.authorization_data->len == 1) { 900 free_AuthorizationData(et.authorization_data); 901 free(et.authorization_data); 902 et.authorization_data = NULL; 903 } else { 904 AuthorizationData *ad = et.authorization_data; 905 free_AuthorizationDataElement(&ad->val[ad->len - 1]); 906 ad->len--; 907 } 908 } 909 } 910 911 ret = krb5_copy_keyblock_contents(r->context, sessionkey, &et.key); 912 if (ret) 913 goto out; 914 et.crealm = tgt_name->realm; 915 et.cname = tgt_name->name; 916 917 ek.key = et.key; 918 /* MIT must have at least one last_req */ 919 ek.last_req.len = 1; 920 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); 921 if (ek.last_req.val == NULL) { 922 ret = ENOMEM; 923 goto out; 924 } 925 ek.nonce = b->nonce; 926 ek.flags = et.flags; 927 ek.authtime = et.authtime; 928 ek.starttime = et.starttime; 929 ek.endtime = et.endtime; 930 ek.renew_till = et.renew_till; 931 ek.srealm = rep.ticket.realm; 932 ek.sname = rep.ticket.sname; 933 934 _kdc_log_timestamp(r->context, r->config, "TGS-REQ", et.authtime, et.starttime, 935 et.endtime, et.renew_till); 936 937 /* Don't sign cross realm tickets, they can't be checked anyway */ 938 { 939 char *sr = get_krbtgt_realm(&ek.sname); 940 941 if (sr == NULL || strcmp(sr, ek.srealm) == 0) { 942 ret = _kdc_add_KRB5SignedPath(r->context, 943 r->config, 944 krbtgt, 945 krbtgt_etype, 946 client_principal, 947 NULL, 948 spp, 949 &et); 950 if (ret) 951 goto out; 952 } 953 } 954 955 if (enc_pa_data->len) { 956 rep.padata = calloc(1, sizeof(*rep.padata)); 957 if (rep.padata == NULL) { 958 ret = ENOMEM; 959 goto out; 960 } 961 ret = copy_METHOD_DATA(enc_pa_data, rep.padata); 962 if (ret) 963 goto out; 964 } 965 966 if (krb5_enctype_valid(r->context, et.key.keytype) != 0 967 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype)) 968 { 969 krb5_enctype_enable(r->context, et.key.keytype); 970 is_weak = 1; 971 } 972 973 974 /* It is somewhat unclear where the etype in the following 975 encryption should come from. What we have is a session 976 key in the passed tgt, and a list of preferred etypes 977 *for the new ticket*. Should we pick the best possible 978 etype, given the keytype in the tgt, or should we look 979 at the etype list here as well? What if the tgt 980 session key is DES3 and we want a ticket with a (say) 981 CAST session key. Should the DES3 etype be added to the 982 etype list, even if we don't want a session key with 983 DES3? */ 984 ret = _kdc_encode_reply(r->context, r->config, r, b->nonce, 985 &rep, &et, &ek, et.key.keytype, 986 kvno, 987 serverkey, 0, r->rk_is_subkey, 988 &r->e_text, reply); 989 if (is_weak) 990 krb5_enctype_disable(r->context, et.key.keytype); 991 992out: 993 free_TGS_REP(&rep); 994 free_TransitedEncoding(&et.transited); 995 if(et.starttime) 996 free(et.starttime); 997 if(et.renew_till) 998 free(et.renew_till); 999 if(et.authorization_data) { 1000 free_AuthorizationData(et.authorization_data); 1001 free(et.authorization_data); 1002 } 1003 free_LastReq(&ek.last_req); 1004 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); 1005 free_EncryptionKey(&et.key); 1006 return ret; 1007} 1008 1009static krb5_error_code 1010tgs_check_authenticator(krb5_context context, 1011 krb5_kdc_configuration *config, 1012 krb5_auth_context ac, 1013 KDC_REQ_BODY *b, 1014 const char **e_text, 1015 krb5_keyblock *key) 1016{ 1017 krb5_authenticator auth; 1018 size_t len = 0; 1019 unsigned char *buf; 1020 size_t buf_size; 1021 krb5_error_code ret; 1022 krb5_crypto crypto; 1023 1024 krb5_auth_con_getauthenticator(context, ac, &auth); 1025 if(auth->cksum == NULL){ 1026 kdc_log(context, config, 0, "No authenticator in request"); 1027 ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 1028 goto out; 1029 } 1030 /* 1031 * according to RFC1510 it doesn't need to be keyed, 1032 * but according to the latest draft it needs to. 1033 */ 1034 if ( 1035#if 0 1036!krb5_checksum_is_keyed(context, auth->cksum->cksumtype) 1037 || 1038#endif 1039 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { 1040 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d", 1041 auth->cksum->cksumtype); 1042 ret = KRB5KRB_AP_ERR_INAPP_CKSUM; 1043 goto out; 1044 } 1045 1046 /* XXX should not re-encode this */ 1047 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret); 1048 if(ret){ 1049 const char *msg = krb5_get_error_message(context, ret); 1050 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg); 1051 krb5_free_error_message(context, msg); 1052 goto out; 1053 } 1054 if(buf_size != len) { 1055 free(buf); 1056 kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); 1057 *e_text = "KDC internal error"; 1058 ret = KRB5KRB_ERR_GENERIC; 1059 goto out; 1060 } 1061 ret = krb5_crypto_init(context, key, 0, &crypto); 1062 if (ret) { 1063 const char *msg = krb5_get_error_message(context, ret); 1064 free(buf); 1065 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); 1066 krb5_free_error_message(context, msg); 1067 goto out; 1068 } 1069 ret = krb5_verify_checksum(context, 1070 crypto, 1071 KRB5_KU_TGS_REQ_AUTH_CKSUM, 1072 buf, 1073 len, 1074 auth->cksum); 1075 free(buf); 1076 krb5_crypto_destroy(context, crypto); 1077 if(ret){ 1078 const char *msg = krb5_get_error_message(context, ret); 1079 kdc_log(context, config, 0, 1080 "Failed to verify authenticator checksum: %s", msg); 1081 krb5_free_error_message(context, msg); 1082 goto out; 1083 } 1084 1085out: 1086 free_Authenticator(auth); 1087 free(auth); 1088 return ret; 1089} 1090 1091/* 1092 * 1093 */ 1094 1095static const char * 1096find_rpath(krb5_context context, Realm crealm, Realm srealm) 1097{ 1098 const char *new_realm = krb5_config_get_string(context, 1099 NULL, 1100 "capaths", 1101 crealm, 1102 srealm, 1103 NULL); 1104 return new_realm; 1105} 1106 1107 1108static krb5_boolean 1109need_referral(krb5_context context, krb5_kdc_configuration *config, 1110 const KDCOptions * const options, krb5_principal server, 1111 krb5_realm **realms) 1112{ 1113 const char *name; 1114 1115 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST) 1116 return FALSE; 1117 1118 if (server->name.name_string.len == 1) 1119 name = server->name.name_string.val[0]; 1120 else if (server->name.name_string.len > 1) 1121 name = server->name.name_string.val[1]; 1122 else 1123 return FALSE; 1124 1125 kdc_log(context, config, 0, "Searching referral for %s", name); 1126 1127 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0; 1128} 1129 1130static krb5_error_code 1131tgs_parse_request(kdc_request_t r, 1132 KDC_REQ_BODY *b, 1133 const PA_DATA *tgs_req, 1134 krb5_ticket **ticket, 1135 const char *from, 1136 const struct sockaddr *from_addr, 1137 time_t **csec, 1138 int **cusec, 1139 AuthorizationData **auth_data) 1140{ 1141 krb5_ap_req ap_req; 1142 krb5_error_code ret; 1143 krb5_auth_context ac = NULL; 1144 krb5_flags ap_req_options; 1145 krb5_flags verify_ap_req_flags; 1146 krb5_crypto crypto; 1147 Key *tkey; 1148 krb5_keyblock *subkey = NULL; 1149 unsigned usage; 1150 1151 *auth_data = NULL; 1152 *csec = NULL; 1153 *cusec = NULL; 1154 1155 memset(&ap_req, 0, sizeof(ap_req)); 1156 ret = krb5_decode_ap_req(r->context, &tgs_req->padata_value, &ap_req); 1157 if (ret){ 1158 const char *msg = krb5_get_error_message(r->context, ret); 1159 kdc_log(r->context, r->config, 0, "Failed to decode AP-REQ: %s", msg); 1160 krb5_free_error_message(r->context, msg); 1161 goto out; 1162 } 1163 1164 if (!get_krbtgt_realm(&ap_req.ticket.sname)){ 1165 /* XXX check for ticket.sname == req.sname */ 1166 kdc_log(r->context, r->config, 0, "PA-DATA is not a ticket-granting ticket"); 1167 ret = KRB5KDC_ERR_POLICY; /* ? */ 1168 goto out; 1169 } 1170 1171 ret = _krb5_principalname2krb5_principal(r->context, 1172 &r->server_princ, 1173 ap_req.ticket.sname, 1174 ap_req.ticket.realm); 1175 if (ret) 1176 goto out; 1177 1178 ret = krb5_unparse_name(r->context, r->server_princ, &r->server_name); 1179 if (ret) 1180 goto out; 1181 1182 1183 ret = _kdc_db_fetch(r->context, r->config, r->server_princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, &r->server); 1184 1185 if (ret == HDB_ERR_NOT_FOUND_HERE) { 1186 kdc_log(r->context, r->config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", r->server_name); 1187 ret = HDB_ERR_NOT_FOUND_HERE; 1188 goto out; 1189 } else if (ret){ 1190 const char *msg = krb5_get_error_message(r->context, ret); 1191 kdc_log(r->context, r->config, 0, 1192 "Ticket-granting ticket user %s not found in database: %s", r->server_name, msg); 1193 krb5_free_error_message(r->context, msg); 1194 ret = KRB5KRB_AP_ERR_NOT_US; 1195 goto out; 1196 } 1197 1198 if (ap_req.ticket.enc_part.kvno && 1199 *ap_req.ticket.enc_part.kvno != r->server->entry.kvno){ 1200 1201 kdc_log(r->context, r->config, 0, 1202 "Ticket kvno = %d, DB kvno = %d (%s)", 1203 *ap_req.ticket.enc_part.kvno, 1204 r->server->entry.kvno, 1205 r->server_name); 1206 ret = KRB5KRB_AP_ERR_BADKEYVER; 1207 goto out; 1208 } 1209 1210 r->server_enctype = ap_req.ticket.enc_part.etype; 1211 1212 ret = hdb_enctype2key(r->context, &r->server->entry, 1213 ap_req.ticket.enc_part.etype, &tkey); 1214 if (ret) { 1215 char *str = NULL; 1216 1217 krb5_enctype_to_string(r->context, ap_req.ticket.enc_part.etype, &str); 1218 kdc_log(r->context, r->config, 0, 1219 "No server key with enctype %s found for %s", 1220 str ? str : "<unknown enctype>", 1221 r->server_name); 1222 free(str); 1223 ret = KRB5KRB_AP_ERR_BADKEYVER; 1224 goto out; 1225 } 1226 1227 if (b->kdc_options.validate) 1228 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; 1229 else 1230 verify_ap_req_flags = 0; 1231 1232 ret = krb5_verify_ap_req2(r->context, 1233 &ac, 1234 &ap_req, 1235 r->server_princ, 1236 &tkey->key, 1237 verify_ap_req_flags, 1238 &ap_req_options, 1239 ticket, 1240 KRB5_KU_TGS_REQ_AUTH); 1241 if(ret) { 1242 const char *msg = krb5_get_error_message(r->context, ret); 1243 kdc_log(r->context, r->config, 0, "Failed to verify AP-REQ: %s: (krbtgt was %s)", 1244 msg, r->server_name); 1245 krb5_free_error_message(r->context, msg); 1246 goto out; 1247 } 1248 1249 heim_assert(ticket != NULL, "verify ap_req2 w/o ticket ?"); 1250 1251 { 1252 krb5_authenticator auth; 1253 krb5_data data; 1254 1255 ret = krb5_auth_con_getauthenticator(r->context, ac, &auth); 1256 if (ret == 0) { 1257 *csec = malloc(sizeof(**csec)); 1258 if (*csec == NULL) { 1259 krb5_free_authenticator(r->context, &auth); 1260 kdc_log(r->context, r->config, 0, "malloc failed"); 1261 goto out; 1262 } 1263 **csec = auth->ctime; 1264 *cusec = malloc(sizeof(**cusec)); 1265 if (*cusec == NULL) { 1266 krb5_free_authenticator(r->context, &auth); 1267 kdc_log(r->context, r->config, 0, "malloc failed"); 1268 goto out; 1269 } 1270 **cusec = auth->cusec; 1271 1272 ret = _krb5_get_ad(r->context, auth->authorization_data, NULL, KRB5_PADATA_FX_FAST_ARMOR, &data); 1273 krb5_free_authenticator(r->context, &auth); 1274 1275 if (ret == 0) { 1276 krb5_data_free(&data); 1277 kdc_log(r->context, r->config, 0, "Authenticator to TGS-REQ contains FX-fast-armor (reply attack)"); 1278 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 1279 goto out; 1280 } 1281 } 1282 } 1283 1284 ret = tgs_check_authenticator(r->context, r->config, 1285 ac, b, &r->e_text, &(*ticket)->ticket.key); 1286 if (ret) { 1287 krb5_auth_con_free(r->context, ac); 1288 goto out; 1289 } 1290 1291 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY; 1292 r->rk_is_subkey = 1; 1293 1294 ret = krb5_auth_con_getremotesubkey(r->context, ac, &subkey); 1295 if(ret){ 1296 const char *msg = krb5_get_error_message(r->context, ret); 1297 krb5_auth_con_free(r->context, ac); 1298 kdc_log(r->context, r->config, 0, "Failed to get remote subkey: %s", msg); 1299 krb5_free_error_message(r->context, msg); 1300 goto out; 1301 } 1302 if(subkey == NULL){ 1303 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION; 1304 r->rk_is_subkey = 0; 1305 1306 ret = krb5_auth_con_getkey(r->context, ac, &subkey); 1307 if(ret) { 1308 const char *msg = krb5_get_error_message(r->context, ret); 1309 krb5_auth_con_free(r->context, ac); 1310 kdc_log(r->context, r->config, 0, "Failed to get session key: %s", msg); 1311 krb5_free_error_message(r->context, msg); 1312 goto out; 1313 } 1314 } 1315 if(subkey == NULL){ 1316 krb5_auth_con_free(r->context, ac); 1317 kdc_log(r->context, r->config, 0, 1318 "Failed to get key for enc-authorization-data"); 1319 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1320 goto out; 1321 } 1322 1323 krb5_free_keyblock_contents(r->context, &r->reply_key); 1324 ret = krb5_copy_keyblock_contents(r->context, subkey, &r->reply_key); 1325 krb5_free_keyblock(r->context, subkey); 1326 if (ret) 1327 goto out; 1328 1329 1330 if (b->enc_authorization_data) { 1331 krb5_data ad; 1332 1333 ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto); 1334 if (ret) { 1335 const char *msg = krb5_get_error_message(r->context, ret); 1336 krb5_auth_con_free(r->context, ac); 1337 kdc_log(r->context, r->config, 0, "krb5_crypto_init failed: %s", msg); 1338 krb5_free_error_message(r->context, msg); 1339 goto out; 1340 } 1341 ret = krb5_decrypt_EncryptedData (r->context, 1342 crypto, 1343 usage, 1344 b->enc_authorization_data, 1345 &ad); 1346 krb5_crypto_destroy(r->context, crypto); 1347 if(ret){ 1348 krb5_auth_con_free(r->context, ac); 1349 kdc_log(r->context, r->config, 0, 1350 "Failed to decrypt enc-authorization-data"); 1351 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1352 goto out; 1353 } 1354 ALLOC(*auth_data); 1355 if (*auth_data == NULL) { 1356 krb5_data_free(&ad); 1357 krb5_auth_con_free(r->context, ac); 1358 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1359 goto out; 1360 } 1361 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL); 1362 krb5_data_free(&ad); 1363 if(ret){ 1364 krb5_auth_con_free(r->context, ac); 1365 free(*auth_data); 1366 *auth_data = NULL; 1367 kdc_log(r->context, r->config, 0, "Failed to decode authorization data"); 1368 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ 1369 goto out; 1370 } 1371 1372 ret = _krb5_get_ad(r->context, *auth_data, NULL, KRB5_PADATA_FX_FAST_ARMOR, &ad); 1373 if (ret == 0) { 1374 krb5_data_free(&ad); 1375 kdc_log(r->context, r->config, 0, "enc-authorization to TGS-REQ contains FX-fast-armor (reply attack)"); 1376 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; 1377 goto out; 1378 } 1379 } 1380 1381 /* 1382 * Check for FAST request 1383 */ 1384 1385 ret = _kdc_fast_unwrap_request(r, *ticket, ac); 1386 if (ret) 1387 goto out; 1388 1389 1390 krb5_auth_con_free(r->context, ac); 1391 1392out: 1393 free_AP_REQ(&ap_req); 1394 1395 return ret; 1396} 1397 1398static krb5_error_code 1399build_server_referral(krb5_context context, 1400 krb5_kdc_configuration *config, 1401 krb5_crypto session, 1402 krb5_const_realm referred_realm, 1403 const PrincipalName *true_principal_name, 1404 const PrincipalName *requested_principal, 1405 krb5_data *outdata) 1406{ 1407 PA_ServerReferralData ref; 1408 krb5_error_code ret; 1409 EncryptedData ed; 1410 krb5_data data; 1411 size_t size = 0; 1412 1413 memset(&ref, 0, sizeof(ref)); 1414 1415 if (referred_realm) { 1416 ALLOC(ref.referred_realm); 1417 if (ref.referred_realm == NULL) 1418 goto eout; 1419 *ref.referred_realm = strdup(referred_realm); 1420 if (*ref.referred_realm == NULL) 1421 goto eout; 1422 } 1423 if (true_principal_name) { 1424 ALLOC(ref.true_principal_name); 1425 if (ref.true_principal_name == NULL) 1426 goto eout; 1427 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name); 1428 if (ret) 1429 goto eout; 1430 } 1431 if (requested_principal) { 1432 ALLOC(ref.requested_principal_name); 1433 if (ref.requested_principal_name == NULL) 1434 goto eout; 1435 ret = copy_PrincipalName(requested_principal, 1436 ref.requested_principal_name); 1437 if (ret) 1438 goto eout; 1439 } 1440 1441 ASN1_MALLOC_ENCODE(PA_ServerReferralData, 1442 data.data, data.length, 1443 &ref, &size, ret); 1444 free_PA_ServerReferralData(&ref); 1445 if (ret) 1446 return ret; 1447 if (data.length != size) 1448 krb5_abortx(context, "internal asn.1 encoder error"); 1449 1450 ret = krb5_encrypt_EncryptedData(context, session, 1451 KRB5_KU_PA_SERVER_REFERRAL, 1452 data.data, data.length, 1453 0 /* kvno */, &ed); 1454 free(data.data); 1455 if (ret) 1456 return ret; 1457 1458 ASN1_MALLOC_ENCODE(EncryptedData, 1459 outdata->data, outdata->length, 1460 &ed, &size, ret); 1461 free_EncryptedData(&ed); 1462 if (ret) 1463 return ret; 1464 if (outdata->length != size) 1465 krb5_abortx(context, "internal asn.1 encoder error"); 1466 1467 return 0; 1468eout: 1469 free_PA_ServerReferralData(&ref); 1470 krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); 1471 return ENOMEM; 1472} 1473 1474static krb5_error_code 1475tgs_build_reply(kdc_request_t r, 1476 KDC_REQ *req, 1477 KDC_REQ_BODY *b, 1478 hdb_entry_ex *krbtgt, 1479 krb5_enctype krbtgt_etype, 1480 krb5_ticket *ticket, 1481 krb5_data *reply, 1482 const char *from, 1483 AuthorizationData **auth_data, 1484 const struct sockaddr *from_addr) 1485{ 1486 krb5_kdc_configuration *config = r->config; 1487 krb5_context context = r->context; 1488 krb5_error_code ret; 1489 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL; 1490 krb5_principal krbtgt_principal = NULL; 1491 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL; 1492 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL; 1493 HDB *clientdb, *s4u2self_impersonated_clientdb; 1494 krb5_realm ref_realm = NULL; 1495 EncTicketPart *tgt = &ticket->ticket; 1496 krb5_principals spp = NULL; 1497 const EncryptionKey *ekey; 1498 krb5_keyblock sessionkey; 1499 krb5_kvno kvno; 1500 krb5_data rspac; 1501 1502 hdb_entry_ex *krbtgt_out = NULL; 1503 1504 METHOD_DATA enc_pa_data; 1505 1506 PrincipalName *s; 1507 Realm realm; 1508 int nloop = 0; 1509 EncTicketPart adtkt; 1510 char opt_str[128]; 1511 int signedpath = 0; 1512 1513 Key *tkey_check; 1514 Key *tkey_sign; 1515 Key *tkey_krbtgt_check = NULL; 1516 int flags = HDB_F_FOR_TGS_REQ; 1517 1518 memset(&sessionkey, 0, sizeof(sessionkey)); 1519 memset(&adtkt, 0, sizeof(adtkt)); 1520 krb5_data_zero(&rspac); 1521 memset(&enc_pa_data, 0, sizeof(enc_pa_data)); 1522 1523 if (b->sname == NULL) { 1524 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1525 kdc_log(context, config, 0, "TGS request w/o sname"); 1526 goto out; 1527 } 1528 1529 s = b->sname; 1530 realm = b->realm; 1531 1532 /* 1533 * Always to do CANON, see comment below about returned server principal (rsp). 1534 */ 1535 flags |= HDB_F_CANON; 1536 1537 if(b->kdc_options.enc_tkt_in_skey){ 1538 Ticket *t; 1539 hdb_entry_ex *uu; 1540 krb5_principal p; 1541 Key *uukey; 1542 1543 if(b->additional_tickets == NULL || 1544 b->additional_tickets->len == 0){ 1545 ret = KRB5KDC_ERR_BADOPTION; /* ? */ 1546 kdc_log(context, config, 0, 1547 "No second ticket present in request"); 1548 goto out; 1549 } 1550 t = &b->additional_tickets->val[0]; 1551 if(!get_krbtgt_realm(&t->sname)){ 1552 kdc_log(context, config, 0, 1553 "Additional ticket is not a ticket-granting ticket"); 1554 ret = KRB5KDC_ERR_POLICY; 1555 goto out; 1556 } 1557 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm); 1558 ret = _kdc_db_fetch(context, config, p, 1559 HDB_F_GET_KRBTGT, t->enc_part.kvno, 1560 NULL, &uu); 1561 krb5_free_principal(context, p); 1562 if(ret){ 1563 if (ret == HDB_ERR_NOENTRY) 1564 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1565 goto out; 1566 } 1567 ret = hdb_enctype2key(context, &uu->entry, 1568 t->enc_part.etype, &uukey); 1569 if(ret){ 1570 _kdc_free_ent(context, uu); 1571 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 1572 goto out; 1573 } 1574 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0); 1575 _kdc_free_ent(context, uu); 1576 if(ret) 1577 goto out; 1578 1579 ret = verify_flags(context, config, &adtkt, spn); 1580 if (ret) 1581 goto out; 1582 1583 s = &adtkt.cname; 1584 realm = adtkt.crealm; 1585 } 1586 1587 _krb5_principalname2krb5_principal(context, &sp, *s, realm); 1588 ret = krb5_unparse_name(context, sp, &spn); 1589 if (ret) 1590 goto out; 1591 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); 1592 ret = krb5_unparse_name(context, cp, &cpn); 1593 if (ret) 1594 goto out; 1595 unparse_flags (KDCOptions2int(b->kdc_options), 1596 asn1_KDCOptions_units(), 1597 opt_str, sizeof(opt_str)); 1598 if(*opt_str) 1599 kdc_log(context, config, 0, 1600 "TGS-REQ %s from %s for %s [%s]", 1601 cpn, from, spn, opt_str); 1602 else 1603 kdc_log(context, config, 0, 1604 "TGS-REQ %s from %s for %s", cpn, from, spn); 1605 1606 /* 1607 * Fetch server 1608 */ 1609 1610server_lookup: 1611 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags, 1612 NULL, NULL, &server); 1613 1614 if(ret == HDB_ERR_NOT_FOUND_HERE) { 1615 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn); 1616 goto out; 1617 } else if(ret){ 1618 const char *new_rlm, *msg; 1619 Realm req_rlm; 1620 krb5_realm *realms; 1621 1622 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) { 1623 if(nloop++ < 2) { 1624 new_rlm = find_rpath(context, tgt->crealm, req_rlm); 1625 if(new_rlm) { 1626 kdc_log(context, config, 5, "krbtgt for realm %s " 1627 "not found, trying %s", 1628 req_rlm, new_rlm); 1629 krb5_free_principal(context, sp); 1630 free(spn); 1631 krb5_make_principal(context, &sp, realm, 1632 KRB5_TGS_NAME, new_rlm, NULL); 1633 ret = krb5_unparse_name(context, sp, &spn); 1634 if (ret) 1635 goto out; 1636 1637 if (ref_realm) 1638 free(ref_realm); 1639 ref_realm = strdup(new_rlm); 1640 goto server_lookup; 1641 } 1642 } 1643 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) { 1644 if (strcmp(realms[0], sp->realm) != 0) { 1645 kdc_log(context, config, 5, 1646 "Returning a referral to realm %s for " 1647 "server %s that was not found", 1648 realms[0], spn); 1649 krb5_free_principal(context, sp); 1650 free(spn); 1651 krb5_make_principal(context, &sp, realm, KRB5_TGS_NAME, 1652 realms[0], NULL); 1653 ret = krb5_unparse_name(context, sp, &spn); 1654 if (ret) 1655 goto out; 1656 1657 if (ref_realm) 1658 free(ref_realm); 1659 ref_realm = strdup(realms[0]); 1660 1661 krb5_free_host_realm(context, realms); 1662 goto server_lookup; 1663 } 1664 krb5_free_host_realm(context, realms); 1665 } 1666 msg = krb5_get_error_message(context, ret); 1667 kdc_log(context, config, 0, 1668 "Server not found in database: %s: %s", spn, msg); 1669 krb5_free_error_message(context, msg); 1670 if (ret == HDB_ERR_NOENTRY) 1671 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; 1672 goto out; 1673 } 1674 1675 /* the name returned to the client depend on what was asked for, 1676 * return canonical name if kdc_options.canonicalize was set, the 1677 * client wants the true name of the principal, if not it just 1678 * wants the name its asked for. 1679 */ 1680 1681 if (b->kdc_options.canonicalize) 1682 rsp = server->entry.principal; 1683 else 1684 rsp = sp; 1685 1686 1687 /* 1688 * Select enctype, return key and kvno. 1689 */ 1690 1691 { 1692 krb5_enctype etype; 1693 1694 if(b->kdc_options.enc_tkt_in_skey) { 1695 size_t i; 1696 ekey = &adtkt.key; 1697 for(i = 0; i < b->etype.len; i++) 1698 if (b->etype.val[i] == adtkt.key.keytype) 1699 break; 1700 if(i == b->etype.len) { 1701 kdc_log(context, config, 0, 1702 "Addition ticket have not matching etypes"); 1703 krb5_clear_error_message(context); 1704 ret = KRB5KDC_ERR_ETYPE_NOSUPP; 1705 goto out; 1706 } 1707 etype = b->etype.val[i]; 1708 kvno = 0; 1709 } else { 1710 Key *skey; 1711 1712 ret = _kdc_find_etype(context, 1713 config->tgs_use_strongest_session_key, FALSE, 1714 server, b->etype.val, b->etype.len, NULL, 1715 &skey); 1716 if(ret) { 1717 kdc_log(context, config, 0, 1718 "Server (%s) has no support for etypes", spn); 1719 goto out; 1720 } 1721 ekey = &skey->key; 1722 etype = skey->key.keytype; 1723 kvno = server->entry.kvno; 1724 } 1725 1726 ret = krb5_generate_random_keyblock(context, etype, &sessionkey); 1727 if (ret) 1728 goto out; 1729 } 1730 1731 /* 1732 * Check that service is in the same realm as the krbtgt. If it's 1733 * not the same, it's someone that is using a uni-directional trust 1734 * backward. 1735 */ 1736 1737 /* 1738 * Validate authoriation data 1739 */ 1740 1741 ret = hdb_enctype2key(context, &krbtgt->entry, 1742 krbtgt_etype, &tkey_check); 1743 if(ret) { 1744 kdc_log(context, config, 0, 1745 "Failed to find key for krbtgt PAC check"); 1746 goto out; 1747 } 1748 1749 /* 1750 * Now refetch the primary krbtgt, and get the current kvno (the 1751 * sign check may have been on an old kvno, and the server may 1752 * have been an incoming trust) 1753 */ 1754 1755 { 1756 const char *remote_realm = 1757 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1); 1758 1759 ret = krb5_make_principal(context, 1760 &krbtgt_principal, 1761 remote_realm, 1762 KRB5_TGS_NAME, 1763 remote_realm, 1764 NULL); 1765 if(ret) { 1766 kdc_log(context, config, 0, 1767 "Failed to generate krbtgt principal"); 1768 goto out; 1769 } 1770 } 1771 1772 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out); 1773 if (ret) { 1774 krb5_error_code ret2; 1775 char *ktpn, *ktpn2; 1776 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn); 1777 ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2); 1778 kdc_log(context, config, 0, 1779 "Request with wrong krbtgt: %s, %s not found in our database", 1780 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>"); 1781 if(ret == 0) 1782 free(ktpn); 1783 if(ret2 == 0) 1784 free(ktpn2); 1785 ret = KRB5KRB_AP_ERR_NOT_US; 1786 goto out; 1787 } 1788 1789 /* 1790 * The first realm is the realm of the service, the second is 1791 * krbtgt/<this>/@REALM component of the krbtgt DN the request was 1792 * encrypted to. The redirection via the krbtgt_out entry allows 1793 * the DB to possibly correct the case of the realm (Samba4 does 1794 * this) before the strcmp() 1795 */ 1796 if (strcmp(krb5_principal_get_realm(context, server->entry.principal), 1797 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) { 1798 char *ktpn; 1799 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn); 1800 kdc_log(context, config, 0, 1801 "Request with wrong krbtgt: %s", 1802 (ret == 0) ? ktpn : "<unknown>"); 1803 if(ret == 0) 1804 free(ktpn); 1805 ret = KRB5KRB_AP_ERR_NOT_US; 1806 goto out; 1807 } 1808 1809 ret = hdb_enctype2key(context, &krbtgt_out->entry, 1810 krbtgt_etype, &tkey_sign); 1811 if(ret) { 1812 kdc_log(context, config, 0, 1813 "Failed to find key for krbtgt PAC signature"); 1814 goto out; 1815 } 1816 1817 /* 1818 * Check if we would know the krbtgt key for the PAC. We would 1819 * only know this if the krbtgt principal was the same (ie, in our 1820 * realm, regardless of KVNO) 1821 */ 1822 1823 if (krb5_principal_compare(context, krbtgt_out->entry.principal, krbtgt->entry.principal)) 1824 tkey_krbtgt_check = tkey_check; 1825 1826 1827 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags, 1828 NULL, &clientdb, &client); 1829 if(ret == HDB_ERR_NOT_FOUND_HERE) { 1830 /* This is OK, we are just trying to find out if they have 1831 * been disabled or deleted in the meantime, missing secrets 1832 * is OK */ 1833 } else if(ret){ 1834 const char *krbtgt_realm, *msg; 1835 1836 /* 1837 * If the client belongs to the same realm as our krbtgt, it 1838 * should exist in the local database. 1839 * 1840 */ 1841 1842 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal); 1843 1844 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) { 1845 if (ret == HDB_ERR_NOENTRY) 1846 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1847 kdc_log(context, config, 1, "Client no longer in database: %s", 1848 cpn); 1849 goto out; 1850 } 1851 1852 msg = krb5_get_error_message(context, ret); 1853 kdc_log(context, config, 1, "Client not found in database: %s", msg); 1854 krb5_free_error_message(context, msg); 1855 } 1856 1857 ret = check_PAC(context, config, cp, NULL, 1858 client, server, krbtgt, 1859 &tkey_check->key, 1860 tkey_krbtgt_check ? &tkey_krbtgt_check->key : NULL, 1861 ekey, &tkey_sign->key, 1862 tgt, &rspac, &signedpath); 1863 if (ret) { 1864 const char *msg = krb5_get_error_message(context, ret); 1865 kdc_log(context, config, 0, 1866 "Verify PAC failed for %s (%s) from %s with %s", 1867 spn, cpn, from, msg); 1868 krb5_free_error_message(context, msg); 1869 goto out; 1870 } 1871 1872 /* also check the krbtgt for signature */ 1873 ret = check_KRB5SignedPath(context, 1874 config, 1875 krbtgt, 1876 cp, 1877 tgt, 1878 &spp, 1879 &signedpath); 1880 if (ret) { 1881 const char *msg = krb5_get_error_message(context, ret); 1882 kdc_log(context, config, 0, 1883 "KRB5SignedPath check failed for %s (%s) from %s with %s", 1884 spn, cpn, from, msg); 1885 krb5_free_error_message(context, msg); 1886 goto out; 1887 } 1888 1889 /* 1890 * Process request 1891 */ 1892 1893 /* by default the tgt principal matches the client principal */ 1894 tp = cp; 1895 tpn = cpn; 1896 1897 if (client) { 1898 const PA_DATA *sdata; 1899 int i = 0; 1900 1901 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER); 1902 if (sdata) { 1903 krb5_crypto crypto; 1904 krb5_data datack; 1905 PA_S4U2Self self; 1906 const char *str; 1907 1908 ret = decode_PA_S4U2Self(sdata->padata_value.data, 1909 sdata->padata_value.length, 1910 &self, NULL); 1911 if (ret) { 1912 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self"); 1913 goto out; 1914 } 1915 1916 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack); 1917 if (ret) 1918 goto out; 1919 1920 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto); 1921 if (ret) { 1922 const char *msg = krb5_get_error_message(context, ret); 1923 free_PA_S4U2Self(&self); 1924 krb5_data_free(&datack); 1925 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); 1926 krb5_free_error_message(context, msg); 1927 goto out; 1928 } 1929 1930 ret = krb5_verify_checksum(context, 1931 crypto, 1932 KRB5_KU_OTHER_CKSUM, 1933 datack.data, 1934 datack.length, 1935 &self.cksum); 1936 krb5_data_free(&datack); 1937 krb5_crypto_destroy(context, crypto); 1938 if (ret) { 1939 const char *msg = krb5_get_error_message(context, ret); 1940 free_PA_S4U2Self(&self); 1941 kdc_log(context, config, 0, 1942 "krb5_verify_checksum failed for S4U2Self: %s", msg); 1943 krb5_free_error_message(context, msg); 1944 goto out; 1945 } 1946 1947 ret = _krb5_principalname2krb5_principal(context, 1948 &tp, 1949 self.name, 1950 self.realm); 1951 free_PA_S4U2Self(&self); 1952 if (ret) 1953 goto out; 1954 1955 ret = krb5_unparse_name(context, tp, &tpn); 1956 if (ret) 1957 goto out; 1958 1959 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */ 1960 if(rspac.data) { 1961 krb5_pac p = NULL; 1962 krb5_data_free(&rspac); 1963 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags, 1964 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client); 1965 if (ret) { 1966 const char *msg; 1967 1968 /* 1969 * If the client belongs to the same realm as our krbtgt, it 1970 * should exist in the local database. 1971 * 1972 */ 1973 1974 if (ret == HDB_ERR_NOENTRY) 1975 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; 1976 msg = krb5_get_error_message(context, ret); 1977 kdc_log(context, config, 1, 1978 "S2U4Self principal to impersonate %s not found in database: %s", 1979 tpn, msg); 1980 krb5_free_error_message(context, msg); 1981 goto out; 1982 } 1983 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p); 1984 if (ret) { 1985 kdc_log(context, config, 0, "PAC generation failed for -- %s", 1986 tpn); 1987 goto out; 1988 } 1989 if (p != NULL) { 1990 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime, 1991 s4u2self_impersonated_client->entry.principal, 1992 ekey, &tkey_sign->key, 1993 &rspac); 1994 krb5_pac_free(context, p); 1995 if (ret) { 1996 kdc_log(context, config, 0, "PAC signing failed for -- %s", 1997 tpn); 1998 goto out; 1999 } 2000 } 2001 } 2002 2003 /* 2004 * Check that service doing the impersonating is 2005 * requesting a ticket to it-self. 2006 */ 2007 ret = check_s4u2self(context, config, clientdb, client, sp); 2008 if (ret) { 2009 kdc_log(context, config, 0, "S4U2Self: %s is not allowed " 2010 "to impersonate to service " 2011 "(tried for user %s to service %s)", 2012 cpn, tpn, spn); 2013 goto out; 2014 } 2015 2016 /* 2017 * If the service isn't trusted for authentication to 2018 * delegation, remove the forward flag. 2019 */ 2020 2021 if (client->entry.flags.trusted_for_delegation) { 2022 str = "[forwardable]"; 2023 } else { 2024 b->kdc_options.forwardable = 0; 2025 str = ""; 2026 } 2027 kdc_log(context, config, 0, "s4u2self %s impersonating %s to " 2028 "service %s %s", cpn, tpn, spn, str); 2029 } 2030 } 2031 2032 /* 2033 * Constrained delegation 2034 */ 2035 2036 if (client != NULL 2037 && b->additional_tickets != NULL 2038 && b->additional_tickets->len != 0 2039 && b->kdc_options.enc_tkt_in_skey == 0) 2040 { 2041 int ad_signedpath = 0; 2042 Key *clientkey; 2043 Ticket *t; 2044 2045 /* 2046 * Require that the KDC have issued the service's krbtgt (not 2047 * self-issued ticket with kimpersonate(1). 2048 */ 2049 if (!signedpath) { 2050 ret = KRB5KDC_ERR_BADOPTION; 2051 kdc_log(context, config, 0, 2052 "Constrained delegation done on service ticket %s/%s", 2053 cpn, spn); 2054 goto out; 2055 } 2056 2057 t = &b->additional_tickets->val[0]; 2058 2059 ret = hdb_enctype2key(context, &client->entry, 2060 t->enc_part.etype, &clientkey); 2061 if(ret){ 2062 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ 2063 goto out; 2064 } 2065 2066 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0); 2067 if (ret) { 2068 kdc_log(context, config, 0, 2069 "failed to decrypt ticket for " 2070 "constrained delegation from %s to %s ", cpn, spn); 2071 goto out; 2072 } 2073 2074 ret = _krb5_principalname2krb5_principal(context, 2075 &tp, 2076 adtkt.cname, 2077 adtkt.crealm); 2078 if (ret) 2079 goto out; 2080 2081 ret = krb5_unparse_name(context, tp, &tpn); 2082 if (ret) 2083 goto out; 2084 2085 ret = _krb5_principalname2krb5_principal(context, 2086 &dp, 2087 t->sname, 2088 t->realm); 2089 if (ret) 2090 goto out; 2091 2092 ret = krb5_unparse_name(context, dp, &dpn); 2093 if (ret) 2094 goto out; 2095 2096 /* check that ticket is valid */ 2097 if (adtkt.flags.forwardable == 0) { 2098 kdc_log(context, config, 0, 2099 "Missing forwardable flag on ticket for " 2100 "constrained delegation from %s (%s) as %s to %s ", 2101 cpn, dpn, tpn, spn); 2102 ret = KRB5KDC_ERR_BADOPTION; 2103 goto out; 2104 } 2105 2106 ret = check_constrained_delegation(context, config, clientdb, 2107 client, server, sp); 2108 if (ret) { 2109 kdc_log(context, config, 0, 2110 "constrained delegation from %s (%s) as %s to %s not allowed", 2111 cpn, dpn, tpn, spn); 2112 goto out; 2113 } 2114 2115 ret = verify_flags(context, config, &adtkt, tpn); 2116 if (ret) { 2117 goto out; 2118 } 2119 2120 krb5_data_free(&rspac); 2121 2122 /* 2123 * generate the PAC for the user. 2124 * 2125 * TODO: pass in t->sname and t->realm and build 2126 * a S4U_DELEGATION_INFO blob to the PAC. 2127 */ 2128 ret = check_PAC(context, config, tp, dp, 2129 client, server, krbtgt, 2130 &clientkey->key, &tkey_check->key, 2131 ekey, &tkey_sign->key, 2132 &adtkt, &rspac, &ad_signedpath); 2133 if (ret) { 2134 const char *msg = krb5_get_error_message(context, ret); 2135 kdc_log(context, config, 0, 2136 "Verify delegated PAC failed to %s for client" 2137 "%s (%s) as %s from %s with %s", 2138 spn, cpn, dpn, tpn, from, msg); 2139 krb5_free_error_message(context, msg); 2140 goto out; 2141 } 2142 2143 /* 2144 * Check that the KDC issued the user's ticket. 2145 */ 2146 ret = check_KRB5SignedPath(context, 2147 config, 2148 krbtgt, 2149 cp, 2150 &adtkt, 2151 NULL, 2152 &ad_signedpath); 2153 if (ret) { 2154 const char *msg = krb5_get_error_message(context, ret); 2155 kdc_log(context, config, 0, 2156 "KRB5SignedPath check from service %s failed " 2157 "for delegation to %s for client %s (%s)" 2158 "from %s failed with %s", 2159 spn, tpn, dpn, cpn, from, msg); 2160 krb5_free_error_message(context, msg); 2161 goto out; 2162 } 2163 2164 if (!ad_signedpath) { 2165 ret = KRB5KDC_ERR_BADOPTION; 2166 kdc_log(context, config, 0, 2167 "Ticket not signed with PAC nor SignedPath service %s failed " 2168 "for delegation to %s for client %s (%s)" 2169 "from %s", 2170 spn, tpn, dpn, cpn, from); 2171 goto out; 2172 } 2173 2174 kdc_log(context, config, 0, "constrained delegation for %s " 2175 "from %s (%s) to %s", tpn, cpn, dpn, spn); 2176 } 2177 2178 /* 2179 * Check flags 2180 */ 2181 2182 ret = kdc_check_flags(context, config, 2183 client, cpn, 2184 server, spn, 2185 FALSE); 2186 if(ret) 2187 goto out; 2188 2189 if((b->kdc_options.validate || b->kdc_options.renew) && 2190 !krb5_principal_compare(context, 2191 krbtgt->entry.principal, 2192 server->entry.principal)){ 2193 kdc_log(context, config, 0, "Inconsistent request."); 2194 ret = KRB5KDC_ERR_SERVER_NOMATCH; 2195 goto out; 2196 } 2197 2198 /* check for valid set of addresses */ 2199 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { 2200 ret = KRB5KRB_AP_ERR_BADADDR; 2201 kdc_log(context, config, 0, "Request from wrong address"); 2202 goto out; 2203 } 2204 2205 /* 2206 * If this is an referral, add server referral data to the 2207 * auth_data reply . 2208 */ 2209 if (ref_realm) { 2210 PA_DATA pa; 2211 krb5_crypto crypto; 2212 2213 kdc_log(context, config, 0, 2214 "Adding server referral to %s", ref_realm); 2215 2216 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto); 2217 if (ret) 2218 goto out; 2219 2220 ret = build_server_referral(context, config, crypto, ref_realm, 2221 NULL, s, &pa.padata_value); 2222 krb5_crypto_destroy(context, crypto); 2223 if (ret) { 2224 kdc_log(context, config, 0, 2225 "Failed building server referral"); 2226 goto out; 2227 } 2228 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL; 2229 2230 ret = add_METHOD_DATA(&enc_pa_data, &pa); 2231 krb5_data_free(&pa.padata_value); 2232 if (ret) { 2233 kdc_log(context, config, 0, 2234 "Add server referral METHOD-DATA failed"); 2235 goto out; 2236 } 2237 } 2238 2239 /* 2240 * 2241 */ 2242 2243 ret = tgs_make_reply(r, 2244 b, 2245 tp, 2246 tgt, 2247 ekey, 2248 &sessionkey, 2249 kvno, 2250 *auth_data, 2251 server, 2252 rsp, 2253 spn, 2254 client, 2255 cp, 2256 krbtgt_out, 2257 krbtgt_etype, 2258 spp, 2259 &rspac, 2260 &enc_pa_data, 2261 reply); 2262 2263out: 2264 if (tpn != cpn) 2265 free(tpn); 2266 free(spn); 2267 free(cpn); 2268 if (dpn) 2269 free(dpn); 2270 2271 krb5_data_free(&rspac); 2272 krb5_free_keyblock_contents(context, &sessionkey); 2273 if(krbtgt_out) 2274 _kdc_free_ent(context, krbtgt_out); 2275 if(server) 2276 _kdc_free_ent(context, server); 2277 if(client) 2278 _kdc_free_ent(context, client); 2279 if(s4u2self_impersonated_client) 2280 _kdc_free_ent(context, s4u2self_impersonated_client); 2281 2282 if (tp && tp != cp) 2283 krb5_free_principal(context, tp); 2284 if (cp) 2285 krb5_free_principal(context, cp); 2286 if (dp) 2287 krb5_free_principal(context, dp); 2288 if (sp) 2289 krb5_free_principal(context, sp); 2290 if (krbtgt_principal) 2291 krb5_free_principal(context, krbtgt_principal); 2292 if (ref_realm) 2293 free(ref_realm); 2294 free_METHOD_DATA(&enc_pa_data); 2295 2296 free_EncTicketPart(&adtkt); 2297 2298 return ret; 2299} 2300 2301/* 2302 * 2303 */ 2304 2305krb5_error_code 2306_kdc_tgs_rep(kdc_request_t r, 2307 krb5_data *data, 2308 const char *from, 2309 struct sockaddr *from_addr, 2310 size_t max_reply_size) 2311{ 2312 AuthorizationData *auth_data = NULL; 2313 krb5_error_code ret; 2314 const PA_DATA *tgs_req, *pa; 2315 int i; 2316 krb5_ticket *ticket = NULL; 2317 2318 time_t *csec = NULL; 2319 int *cusec = NULL; 2320 2321 if(r->req.padata == NULL){ 2322 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */ 2323 kdc_log(r->context, r->config, 0, 2324 "TGS-REQ from %s without PA-DATA", from); 2325 goto out; 2326 } 2327 2328 i = 0; 2329 pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST_ARMOR); 2330 if (pa) { 2331 kdc_log(r->context, r->config, 10, "Got TGS FAST armor inside TGS-REQ pa-data ?"); 2332 ret = KRB5KRB_ERR_GENERIC; 2333 goto out; 2334 } 2335 2336 i = 0; 2337 tgs_req = _kdc_find_padata(&r->req, &i, KRB5_PADATA_TGS_REQ); 2338 if (tgs_req == NULL) { 2339 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; 2340 kdc_log(r->context, r->config, 0, 2341 "TGS-REQ from %s without PA-TGS-REQ", from); 2342 goto out; 2343 } 2344 2345 /* 2346 * 2347 */ 2348 2349 ret = tgs_parse_request(r, 2350 &r->req.req_body, 2351 tgs_req, 2352 &ticket, 2353 from, from_addr, 2354 &csec, &cusec, 2355 &auth_data); 2356 if (ret == HDB_ERR_NOT_FOUND_HERE) { 2357 /* kdc_log() is called in tgs_parse_request() */ 2358 goto out; 2359 } 2360 if (ret) { 2361 kdc_log(r->context, r->config, 0, 2362 "Failed parsing TGS-REQ from %s", from); 2363 goto out; 2364 } 2365 2366 /* 2367 * 2368 */ 2369 2370 ret = _kdc_fast_strengthen_reply_key(r); 2371 if (ret) 2372 goto out; 2373 2374 /* 2375 * 2376 */ 2377 ret = tgs_build_reply(r, 2378 &r->req, 2379 &r->req.req_body, 2380 r->server, 2381 r->server_enctype, 2382 ticket, 2383 data, 2384 from, 2385 &auth_data, 2386 from_addr); 2387 if (ret) { 2388 kdc_log(r->context, r->config, 0, 2389 "Failed building TGS-REP to %s", from); 2390 goto out; 2391 } 2392 2393 if (max_reply_size && data->length > max_reply_size) { 2394 krb5_data_free(data); 2395 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; 2396 r->e_text = "Reply packet too large"; 2397 } 2398 2399out: 2400 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ 2401 METHOD_DATA error_method = { 0, NULL }; 2402 2403 kdc_log(r->context, r->config, 10, "tgs-req: sending error: %d to client", ret); 2404 ret = _kdc_fast_mk_error(r->context, r, 2405 &error_method, 2406 NULL, 2407 NULL, 2408 ret, r->e_text, 2409 NULL, NULL, 2410 csec, cusec, 2411 data); 2412 free_METHOD_DATA(&error_method); 2413 } 2414 free(csec); 2415 free(cusec); 2416 2417 krb5_free_keyblock_contents(r->context, &r->reply_key); 2418 krb5_free_keyblock_contents(r->context, &r->strengthen_key); 2419 2420 if (ticket) 2421 krb5_free_ticket(r->context, ticket); 2422 2423 if(r->server_princ) 2424 krb5_free_principal(r->context, r->server_princ); 2425 if(r->server_name) 2426 free(r->server_name); 2427 if(r->server) 2428 _kdc_free_ent(r->context, r->server); 2429 2430 if (r->armor_crypto) { 2431 krb5_crypto_destroy(r->context, r->armor_crypto); 2432 r->armor_crypto = NULL; 2433 } 2434 2435 free_KDCFastState(&r->fast); 2436 2437 if (auth_data) { 2438 free_AuthorizationData(auth_data); 2439 free(auth_data); 2440 } 2441 2442 return ret; 2443} 2444