1/* 2 * Copyright (c) 1997 - 2001 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 "krb5_locl.h" 37 38/** 39 * Free ticket and content 40 * 41 * @param context a Kerberos 5 context 42 * @param ticket ticket to free 43 * 44 * @return Returns 0 to indicate success. Otherwise an kerberos et 45 * error code is returned, see krb5_get_error_message(). 46 * 47 * @ingroup krb5 48 */ 49 50KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 51krb5_free_ticket(krb5_context context, 52 krb5_ticket *ticket) 53{ 54 free_EncTicketPart(&ticket->ticket); 55 krb5_free_principal(context, ticket->client); 56 krb5_free_principal(context, ticket->server); 57 free(ticket); 58 return 0; 59} 60 61/** 62 * Copy ticket and content 63 * 64 * @param context a Kerberos 5 context 65 * @param from ticket to copy 66 * @param to new copy of ticket, free with krb5_free_ticket() 67 * 68 * @return Returns 0 to indicate success. Otherwise an kerberos et 69 * error code is returned, see krb5_get_error_message(). 70 * 71 * @ingroup krb5 72 */ 73 74KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 75krb5_copy_ticket(krb5_context context, 76 const krb5_ticket *from, 77 krb5_ticket **to) 78{ 79 krb5_error_code ret; 80 krb5_ticket *tmp; 81 82 *to = NULL; 83 tmp = malloc(sizeof(*tmp)); 84 if(tmp == NULL) { 85 krb5_set_error_message(context, ENOMEM, 86 N_("malloc: out of memory", "")); 87 return ENOMEM; 88 } 89 if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){ 90 free(tmp); 91 return ret; 92 } 93 ret = krb5_copy_principal(context, from->client, &tmp->client); 94 if(ret){ 95 free_EncTicketPart(&tmp->ticket); 96 free(tmp); 97 return ret; 98 } 99 ret = krb5_copy_principal(context, from->server, &tmp->server); 100 if(ret){ 101 krb5_free_principal(context, tmp->client); 102 free_EncTicketPart(&tmp->ticket); 103 free(tmp); 104 return ret; 105 } 106 *to = tmp; 107 return 0; 108} 109 110/** 111 * Return client principal in ticket 112 * 113 * @param context a Kerberos 5 context 114 * @param ticket ticket to copy 115 * @param client client principal, free with krb5_free_principal() 116 * 117 * @return Returns 0 to indicate success. Otherwise an kerberos et 118 * error code is returned, see krb5_get_error_message(). 119 * 120 * @ingroup krb5 121 */ 122 123KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 124krb5_ticket_get_client(krb5_context context, 125 const krb5_ticket *ticket, 126 krb5_principal *client) 127{ 128 return krb5_copy_principal(context, ticket->client, client); 129} 130 131/** 132 * Return server principal in ticket 133 * 134 * @param context a Kerberos 5 context 135 * @param ticket ticket to copy 136 * @param server server principal, free with krb5_free_principal() 137 * 138 * @return Returns 0 to indicate success. Otherwise an kerberos et 139 * error code is returned, see krb5_get_error_message(). 140 * 141 * @ingroup krb5 142 */ 143 144KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 145krb5_ticket_get_server(krb5_context context, 146 const krb5_ticket *ticket, 147 krb5_principal *server) 148{ 149 return krb5_copy_principal(context, ticket->server, server); 150} 151 152/** 153 * Return end time of ticket 154 * 155 * @param context a Kerberos 5 context 156 * @param ticket ticket to copy 157 * 158 * @return end time of ticket 159 * 160 * @ingroup krb5 161 */ 162 163KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL 164krb5_ticket_get_endtime(krb5_context context, 165 const krb5_ticket *ticket) 166{ 167 return ticket->ticket.endtime; 168} 169 170/** 171 * Get the flags from the Kerberos ticket 172 * 173 * @param context Kerberos context 174 * @param ticket Kerberos ticket 175 * 176 * @return ticket flags 177 * 178 * @ingroup krb5_ticket 179 */ 180KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL 181krb5_ticket_get_flags(krb5_context context, 182 const krb5_ticket *ticket) 183{ 184 return TicketFlags2int(ticket->ticket.flags); 185} 186 187static int 188find_type_in_ad(krb5_context context, 189 int type, 190 krb5_data *data, 191 krb5_boolean *found, 192 krb5_boolean failp, 193 krb5_keyblock *sessionkey, 194 const AuthorizationData *ad, 195 int level) 196{ 197 krb5_error_code ret = 0; 198 size_t i; 199 200 if (level > 9) { 201 ret = ENOENT; /* XXX */ 202 krb5_set_error_message(context, ret, 203 N_("Authorization data nested deeper " 204 "then %d levels, stop searching", ""), 205 level); 206 goto out; 207 } 208 209 /* 210 * Only copy out the element the first time we get to it, we need 211 * to run over the whole authorization data fields to check if 212 * there are any container clases we need to care about. 213 */ 214 for (i = 0; i < ad->len; i++) { 215 if (!*found && ad->val[i].ad_type == type) { 216 ret = der_copy_octet_string(&ad->val[i].ad_data, data); 217 if (ret) { 218 krb5_set_error_message(context, ret, 219 N_("malloc: out of memory", "")); 220 goto out; 221 } 222 *found = TRUE; 223 continue; 224 } 225 switch (ad->val[i].ad_type) { 226 case KRB5_AUTHDATA_IF_RELEVANT: { 227 AuthorizationData child; 228 ret = decode_AuthorizationData(ad->val[i].ad_data.data, 229 ad->val[i].ad_data.length, 230 &child, 231 NULL); 232 if (ret) { 233 krb5_set_error_message(context, ret, 234 N_("Failed to decode " 235 "IF_RELEVANT with %d", ""), 236 (int)ret); 237 goto out; 238 } 239 ret = find_type_in_ad(context, type, data, found, FALSE, 240 sessionkey, &child, level + 1); 241 free_AuthorizationData(&child); 242 if (ret) 243 goto out; 244 break; 245 } 246#if 0 /* XXX test */ 247 case KRB5_AUTHDATA_KDC_ISSUED: { 248 AD_KDCIssued child; 249 250 ret = decode_AD_KDCIssued(ad->val[i].ad_data.data, 251 ad->val[i].ad_data.length, 252 &child, 253 NULL); 254 if (ret) { 255 krb5_set_error_message(context, ret, 256 N_("Failed to decode " 257 "AD_KDCIssued with %d", ""), 258 ret); 259 goto out; 260 } 261 if (failp) { 262 krb5_boolean valid; 263 krb5_data buf; 264 size_t len; 265 266 ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length, 267 &child.elements, &len, ret); 268 if (ret) { 269 free_AD_KDCIssued(&child); 270 krb5_clear_error_message(context); 271 goto out; 272 } 273 if(buf.length != len) 274 krb5_abortx(context, "internal error in ASN.1 encoder"); 275 276 ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf, 277 &child.ad_checksum, &valid); 278 krb5_data_free(&buf); 279 if (ret) { 280 free_AD_KDCIssued(&child); 281 goto out; 282 } 283 if (!valid) { 284 krb5_clear_error_message(context); 285 ret = ENOENT; 286 free_AD_KDCIssued(&child); 287 goto out; 288 } 289 } 290 ret = find_type_in_ad(context, type, data, found, failp, sessionkey, 291 &child.elements, level + 1); 292 free_AD_KDCIssued(&child); 293 if (ret) 294 goto out; 295 break; 296 } 297#endif 298 case KRB5_AUTHDATA_AND_OR: 299 if (!failp) 300 break; 301 ret = ENOENT; /* XXX */ 302 krb5_set_error_message(context, ret, 303 N_("Authorization data contains " 304 "AND-OR element that is unknown to the " 305 "application", "")); 306 goto out; 307 default: 308 if (!failp) 309 break; 310 ret = ENOENT; /* XXX */ 311 krb5_set_error_message(context, ret, 312 N_("Authorization data contains " 313 "unknown type (%d) ", ""), 314 ad->val[i].ad_type); 315 goto out; 316 } 317 } 318out: 319 if (ret) { 320 if (*found) { 321 krb5_data_free(data); 322 *found = 0; 323 } 324 } 325 return ret; 326} 327 328KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 329_krb5_get_ad(krb5_context context, 330 const AuthorizationData *ad, 331 krb5_keyblock *sessionkey, 332 int type, 333 krb5_data *data) 334{ 335 krb5_boolean found = FALSE; 336 krb5_error_code ret; 337 338 krb5_data_zero(data); 339 340 if (ad == NULL) { 341 krb5_set_error_message(context, ENOENT, 342 N_("No authorization data", "")); 343 return ENOENT; /* XXX */ 344 } 345 346 ret = find_type_in_ad(context, type, data, &found, TRUE, sessionkey, ad, 0); 347 if (ret) 348 return ret; 349 if (!found) { 350 krb5_set_error_message(context, ENOENT, 351 N_("Have no authorization data of type %d", ""), 352 type); 353 return ENOENT; /* XXX */ 354 } 355 return 0; 356} 357 358/** 359 * Extract the authorization data type of type from the ticket. Store 360 * the field in data. This function is to use for kerberos 361 * applications. 362 * 363 * @param context a Kerberos 5 context 364 * @param ticket Kerberos ticket 365 * @param type type to fetch 366 * @param data returned data, free with krb5_data_free() 367 * 368 * @ingroup krb5 369 */ 370 371KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 372krb5_ticket_get_authorization_data_type(krb5_context context, 373 krb5_ticket *ticket, 374 int type, 375 krb5_data *data) 376{ 377 AuthorizationData *ad; 378 krb5_error_code ret; 379 krb5_boolean found = FALSE; 380 381 krb5_data_zero(data); 382 383 ad = ticket->ticket.authorization_data; 384 if (ticket->ticket.authorization_data == NULL) { 385 krb5_set_error_message(context, ENOENT, 386 N_("Ticket have not authorization data", "")); 387 return ENOENT; /* XXX */ 388 } 389 390 ret = find_type_in_ad(context, type, data, &found, TRUE, 391 &ticket->ticket.key, ad, 0); 392 if (ret) 393 return ret; 394 if (!found) { 395 krb5_set_error_message(context, ENOENT, 396 N_("Ticket have not " 397 "authorization data of type %d", ""), 398 type); 399 return ENOENT; /* XXX */ 400 } 401 return 0; 402} 403 404static krb5_error_code 405check_server_referral(krb5_context context, 406 krb5_kdc_rep *rep, 407 unsigned flags, 408 krb5_const_principal requested, 409 krb5_const_principal returned, 410 krb5_keyblock * key) 411{ 412 krb5_error_code ret; 413 PA_ServerReferralData ref; 414 krb5_crypto session; 415 EncryptedData ed; 416 size_t len; 417 krb5_data data; 418 PA_DATA *pa; 419 int i = 0, cmp; 420 421 if (rep->kdc_rep.padata == NULL) 422 goto noreferral; 423 424 pa = krb5_find_padata(rep->kdc_rep.padata->val, 425 rep->kdc_rep.padata->len, 426 KRB5_PADATA_SERVER_REFERRAL, &i); 427 if (pa == NULL) 428 goto noreferral; 429 430 memset(&ed, 0, sizeof(ed)); 431 memset(&ref, 0, sizeof(ref)); 432 433 ret = decode_EncryptedData(pa->padata_value.data, 434 pa->padata_value.length, 435 &ed, &len); 436 if (ret) 437 return ret; 438 if (len != pa->padata_value.length) { 439 free_EncryptedData(&ed); 440 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 441 N_("Referral EncryptedData wrong for realm %s", 442 "realm"), requested->realm); 443 return KRB5KRB_AP_ERR_MODIFIED; 444 } 445 446 ret = krb5_crypto_init(context, key, 0, &session); 447 if (ret) { 448 free_EncryptedData(&ed); 449 return ret; 450 } 451 452 ret = krb5_decrypt_EncryptedData(context, session, 453 KRB5_KU_PA_SERVER_REFERRAL, 454 &ed, &data); 455 free_EncryptedData(&ed); 456 krb5_crypto_destroy(context, session); 457 if (ret) 458 return ret; 459 460 ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); 461 if (ret) { 462 krb5_data_free(&data); 463 return ret; 464 } 465 krb5_data_free(&data); 466 467 if (strcmp(requested->realm, returned->realm) != 0) { 468 free_PA_ServerReferralData(&ref); 469 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 470 N_("server ref realm mismatch, " 471 "requested realm %s got back %s", ""), 472 requested->realm, returned->realm); 473 return KRB5KRB_AP_ERR_MODIFIED; 474 } 475 476 if (krb5_principal_is_krbtgt(context, returned)) { 477 const char *realm = returned->name.name_string.val[1]; 478 479 if (ref.referred_realm == NULL 480 || strcmp(*ref.referred_realm, realm) != 0) 481 { 482 free_PA_ServerReferralData(&ref); 483 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 484 N_("tgt returned with wrong ref", "")); 485 return KRB5KRB_AP_ERR_MODIFIED; 486 } 487 } else if (krb5_principal_compare(context, returned, requested) == 0) { 488 free_PA_ServerReferralData(&ref); 489 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 490 N_("req princ no same as returned", "")); 491 return KRB5KRB_AP_ERR_MODIFIED; 492 } 493 494 if (ref.requested_principal_name) { 495 cmp = _krb5_principal_compare_PrincipalName(context, 496 requested, 497 ref.requested_principal_name); 498 if (!cmp) { 499 free_PA_ServerReferralData(&ref); 500 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 501 N_("referred principal not same " 502 "as requested", "")); 503 return KRB5KRB_AP_ERR_MODIFIED; 504 } 505 } else if (flags & EXTRACT_TICKET_AS_REQ) { 506 free_PA_ServerReferralData(&ref); 507 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 508 N_("Requested principal missing on AS-REQ", "")); 509 return KRB5KRB_AP_ERR_MODIFIED; 510 } 511 512 free_PA_ServerReferralData(&ref); 513 514 return ret; 515noreferral: 516 /* 517 * Expect excact match or that we got a krbtgt 518 */ 519 if (krb5_principal_compare(context, requested, returned) != TRUE && 520 (krb5_realm_compare(context, requested, returned) != TRUE && 521 krb5_principal_is_krbtgt(context, returned) != TRUE)) 522 { 523 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 524 N_("Not same server principal returned " 525 "as requested", "")); 526 return KRB5KRB_AP_ERR_MODIFIED; 527 } 528 return 0; 529} 530 531 532/* 533 * Verify referral data 534 */ 535 536 537static krb5_error_code 538check_client_referral(krb5_context context, 539 krb5_kdc_rep *rep, 540 krb5_const_principal requested, 541 krb5_const_principal mapped, 542 krb5_keyblock const * key) 543{ 544 krb5_error_code ret; 545 PA_ClientCanonicalized canon; 546 krb5_crypto crypto; 547 krb5_data data; 548 PA_DATA *pa; 549 size_t len; 550 int i = 0; 551 552 if (rep->kdc_rep.padata == NULL) 553 goto noreferral; 554 555 pa = krb5_find_padata(rep->kdc_rep.padata->val, 556 rep->kdc_rep.padata->len, 557 KRB5_PADATA_CLIENT_CANONICALIZED, &i); 558 if (pa == NULL) 559 goto noreferral; 560 561 ret = decode_PA_ClientCanonicalized(pa->padata_value.data, 562 pa->padata_value.length, 563 &canon, &len); 564 if (ret) { 565 krb5_set_error_message(context, ret, 566 N_("Failed to decode ClientCanonicalized " 567 "from realm %s", ""), requested->realm); 568 return ret; 569 } 570 571 ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, 572 &canon.names, &len, ret); 573 if (ret) { 574 free_PA_ClientCanonicalized(&canon); 575 return ret; 576 } 577 if (data.length != len) 578 krb5_abortx(context, "internal asn.1 error"); 579 580 ret = krb5_crypto_init(context, key, 0, &crypto); 581 if (ret) { 582 free(data.data); 583 free_PA_ClientCanonicalized(&canon); 584 return ret; 585 } 586 587 ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, 588 data.data, data.length, 589 &canon.canon_checksum); 590 krb5_crypto_destroy(context, crypto); 591 free(data.data); 592 if (ret) { 593 krb5_set_error_message(context, ret, 594 N_("Failed to verify client canonicalized " 595 "data from realm %s", ""), 596 requested->realm); 597 free_PA_ClientCanonicalized(&canon); 598 return ret; 599 } 600 601 if (!_krb5_principal_compare_PrincipalName(context, 602 requested, 603 &canon.names.requested_name)) 604 { 605 free_PA_ClientCanonicalized(&canon); 606 krb5_set_error_message(context, KRB5_PRINC_NOMATCH, 607 N_("Requested name doesn't match" 608 " in client referral", "")); 609 return KRB5_PRINC_NOMATCH; 610 } 611 if (!_krb5_principal_compare_PrincipalName(context, 612 mapped, 613 &canon.names.mapped_name)) 614 { 615 free_PA_ClientCanonicalized(&canon); 616 krb5_set_error_message(context, KRB5_PRINC_NOMATCH, 617 N_("Mapped name doesn't match" 618 " in client referral", "")); 619 return KRB5_PRINC_NOMATCH; 620 } 621 622 return 0; 623 624noreferral: 625 if (krb5_principal_compare(context, requested, mapped) == FALSE && 626 !rep->enc_part.flags.enc_pa_rep) 627 { 628 char *mname = NULL; 629 krb5_unparse_name(context, mapped, &mname); 630 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 631 N_("Not same client principal returned (%s)" 632 "as requested", ""), 633 mname ? mname : "<unknown name>"); 634 krb5_xfree(mname); 635 return KRB5KRB_AP_ERR_MODIFIED; 636 } 637 return 0; 638} 639 640 641static krb5_error_code KRB5_CALLCONV 642decrypt_tkt (krb5_context context, 643 krb5_keyblock *key, 644 krb5_key_usage usage, 645 krb5_const_pointer decrypt_arg, 646 krb5_kdc_rep *dec_rep) 647{ 648 krb5_error_code ret; 649 krb5_data data; 650 size_t size; 651 krb5_crypto crypto; 652 653 ret = krb5_crypto_init(context, key, 0, &crypto); 654 if (ret) 655 return ret; 656 657 ret = krb5_decrypt_EncryptedData (context, 658 crypto, 659 usage, 660 &dec_rep->kdc_rep.enc_part, 661 &data); 662 krb5_crypto_destroy(context, crypto); 663 664 if (ret) 665 return ret; 666 667 ret = decode_EncASRepPart(data.data, 668 data.length, 669 &dec_rep->enc_part, 670 &size); 671 if (ret) 672 ret = decode_EncTGSRepPart(data.data, 673 data.length, 674 &dec_rep->enc_part, 675 &size); 676 krb5_data_free (&data); 677 if (ret) { 678 krb5_set_error_message(context, ret, 679 N_("Failed to decode encpart in ticket", "")); 680 return ret; 681 } 682 return 0; 683} 684 685int 686_krb5_extract_ticket(krb5_context context, 687 krb5_kdc_rep *rep, 688 krb5_creds *creds, 689 krb5_keyblock *key, 690 krb5_key_usage key_usage, 691 krb5_addresses *addrs, 692 unsigned nonce, 693 unsigned flags, 694 krb5_data *request, 695 krb5_decrypt_proc decrypt_proc, 696 krb5_const_pointer decryptarg) 697{ 698 krb5_error_code ret; 699 krb5_principal tmp_principal; 700 size_t len = 0; 701 time_t tmp_time; 702 krb5_timestamp sec_now; 703 704 /* decrypt */ 705 706 if (decrypt_proc == NULL) 707 decrypt_proc = decrypt_tkt; 708 709 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); 710 if (ret) 711 goto out; 712 713 if (rep->enc_part.flags.enc_pa_rep && request && (flags & EXTRACT_TICKET_REQUIRE_ENC_PA)) { 714 krb5_crypto crypto = NULL; 715 Checksum cksum; 716 PA_DATA *pa = NULL; 717 int idx = 0; 718 719 _krb5_debugx(context, 5, "processing enc-ap-rep"); 720 721 if (rep->enc_part.encrypted_pa_data == NULL || 722 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val, 723 rep->enc_part.encrypted_pa_data->len, 724 KRB5_PADATA_REQ_ENC_PA_REP, 725 &idx)) == NULL) 726 { 727 _krb5_debugx(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing"); 728 ret = KRB5KRB_AP_ERR_MODIFIED; 729 goto out; 730 } 731 732 ret = krb5_crypto_init(context, key, 0, &crypto); 733 if (ret) 734 goto out; 735 736 ret = decode_Checksum(pa->padata_value.data, 737 pa->padata_value.length, 738 &cksum, NULL); 739 if (ret) { 740 krb5_crypto_destroy(context, crypto); 741 goto out; 742 } 743 744 ret = krb5_verify_checksum(context, crypto, 745 KRB5_KU_AS_REQ, 746 request->data, request->length, 747 &cksum); 748 krb5_crypto_destroy(context, crypto); 749 free_Checksum(&cksum); 750 _krb5_debug(context, 5, ret, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in"); 751 if (ret) 752 goto out; 753 } 754 755 /* save session key */ 756 757 creds->session.keyvalue.length = 0; 758 creds->session.keyvalue.data = NULL; 759 creds->session.keytype = rep->enc_part.key.keytype; 760 ret = krb5_data_copy (&creds->session.keyvalue, 761 rep->enc_part.key.keyvalue.data, 762 rep->enc_part.key.keyvalue.length); 763 if (ret) { 764 krb5_clear_error_message(context); 765 goto out; 766 } 767 768 /* compare client and save */ 769 ret = _krb5_principalname2krb5_principal(context, 770 &tmp_principal, 771 rep->kdc_rep.cname, 772 rep->kdc_rep.crealm); 773 if (ret) 774 goto out; 775 776 /* check client referral and save principal */ 777 /* anonymous here ? */ 778 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { 779 ret = check_client_referral(context, rep, 780 creds->client, 781 tmp_principal, 782 &creds->session); 783 if (ret) { 784 krb5_free_principal (context, tmp_principal); 785 goto out; 786 } 787 } 788 krb5_free_principal (context, creds->client); 789 creds->client = tmp_principal; 790 791 /* check server referral and save principal */ 792 ret = _krb5_principalname2krb5_principal (context, 793 &tmp_principal, 794 rep->kdc_rep.ticket.sname, 795 rep->kdc_rep.ticket.realm); 796 if (ret) 797 goto out; 798 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ 799 ret = check_server_referral(context, 800 rep, 801 flags, 802 creds->server, 803 tmp_principal, 804 &creds->session); 805 if (ret) { 806 krb5_free_principal (context, tmp_principal); 807 goto out; 808 } 809 } 810 krb5_free_principal(context, creds->server); 811 creds->server = tmp_principal; 812 813 /* verify names */ 814 if(flags & EXTRACT_TICKET_MATCH_REALM){ 815 const char *srealm = krb5_principal_get_realm(context, creds->server); 816 const char *crealm = krb5_principal_get_realm(context, creds->client); 817 818 if (strcmp(rep->enc_part.srealm, srealm) != 0 || 819 strcmp(rep->enc_part.srealm, crealm) != 0) 820 { 821 ret = KRB5KRB_AP_ERR_MODIFIED; 822 krb5_set_error_message(context, ret, "server realm (%s) doesn't match client's (%s)", 823 srealm, crealm); 824 krb5_clear_error_message(context); 825 goto out; 826 } 827 } 828 829 /* compare nonces */ 830 831 if (nonce != (unsigned)rep->enc_part.nonce) { 832 ret = KRB5KRB_AP_ERR_MODIFIED; 833 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 834 goto out; 835 } 836 837 /* set kdc-offset */ 838 839 krb5_timeofday (context, &sec_now); 840 if (rep->enc_part.flags.initial 841 && (flags & EXTRACT_TICKET_TIMESYNC) 842 && context->kdc_sec_offset == 0 843 && krb5_config_get_bool (context, NULL, 844 "libdefaults", 845 "kdc_timesync", 846 NULL)) { 847 context->kdc_sec_offset = (int32_t)(rep->enc_part.authtime - sec_now); 848 krb5_timeofday (context, &sec_now); 849 } 850 851 /* check all times */ 852 853 if (rep->enc_part.starttime) { 854 tmp_time = *rep->enc_part.starttime; 855 } else 856 tmp_time = rep->enc_part.authtime; 857 858 if (creds->times.starttime == 0 859 && krb5_time_abs(tmp_time, sec_now) > context->max_skew) { 860 ret = KRB5KRB_AP_ERR_SKEW; 861 krb5_set_error_message (context, ret, 862 N_("time skew (%ld) larger than max (%d)", ""), 863 (long)krb5_time_abs(tmp_time, sec_now), 864 (int)context->max_skew); 865 goto out; 866 } 867 868 if (creds->times.starttime != 0 869 && tmp_time != creds->times.starttime) { 870 krb5_clear_error_message (context); 871 krb5_set_error_message(context, ret, "startime is not the requested startime"); 872 ret = KRB5KRB_AP_ERR_MODIFIED; 873 goto out; 874 } 875 876 creds->times.starttime = tmp_time; 877 878 if (rep->enc_part.renew_till) { 879 tmp_time = *rep->enc_part.renew_till; 880 } else 881 tmp_time = 0; 882 883 if (creds->times.renew_till != 0 884 && tmp_time > creds->times.renew_till) { 885 krb5_clear_error_message (context); 886 krb5_set_error_message(context, ret, "renewtime is past the requested renewtime"); 887 ret = KRB5KRB_AP_ERR_MODIFIED; 888 goto out; 889 } 890 891 creds->times.renew_till = tmp_time; 892 893 creds->times.authtime = rep->enc_part.authtime; 894 895 if (creds->times.endtime != 0 896 && rep->enc_part.endtime > creds->times.endtime) { 897 krb5_clear_error_message (context); 898 ret = KRB5KRB_AP_ERR_MODIFIED; 899 krb5_set_error_message(context, ret, "endtime is past the requested endtime"); 900 goto out; 901 } 902 903 creds->times.endtime = rep->enc_part.endtime; 904 905 if(rep->enc_part.caddr) 906 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); 907 else if(addrs) 908 krb5_copy_addresses (context, addrs, &creds->addresses); 909 else { 910 creds->addresses.len = 0; 911 creds->addresses.val = NULL; 912 } 913 creds->flags.b = rep->enc_part.flags; 914 915 creds->authdata.len = 0; 916 creds->authdata.val = NULL; 917 918 /* extract ticket */ 919 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, 920 &rep->kdc_rep.ticket, &len, ret); 921 if(ret) 922 goto out; 923 if (creds->ticket.length != len) 924 krb5_abortx(context, "internal error in ASN.1 encoder"); 925 creds->second_ticket.length = 0; 926 creds->second_ticket.data = NULL; 927 928 929out: 930 if (ret) 931 _krb5_debugx(context, 5, "_krb5_extract_ticket failed with %d", ret); 932 933 memset (rep->enc_part.key.keyvalue.data, 0, 934 rep->enc_part.key.keyvalue.length); 935 return ret; 936} 937