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 328/** 329 * Extract the authorization data type of type from the ticket. Store 330 * the field in data. This function is to use for kerberos 331 * applications. 332 * 333 * @param context a Kerberos 5 context 334 * @param ticket Kerberos ticket 335 * @param type type to fetch 336 * @param data returned data, free with krb5_data_free() 337 * 338 * @ingroup krb5 339 */ 340 341KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 342krb5_ticket_get_authorization_data_type(krb5_context context, 343 krb5_ticket *ticket, 344 int type, 345 krb5_data *data) 346{ 347 AuthorizationData *ad; 348 krb5_error_code ret; 349 krb5_boolean found = FALSE; 350 351 krb5_data_zero(data); 352 353 ad = ticket->ticket.authorization_data; 354 if (ticket->ticket.authorization_data == NULL) { 355 krb5_set_error_message(context, ENOENT, 356 N_("Ticket have not authorization data", "")); 357 return ENOENT; /* XXX */ 358 } 359 360 ret = find_type_in_ad(context, type, data, &found, TRUE, 361 &ticket->ticket.key, ad, 0); 362 if (ret) 363 return ret; 364 if (!found) { 365 krb5_set_error_message(context, ENOENT, 366 N_("Ticket have not " 367 "authorization data of type %d", ""), 368 type); 369 return ENOENT; /* XXX */ 370 } 371 return 0; 372} 373 374static krb5_error_code 375check_server_referral(krb5_context context, 376 krb5_kdc_rep *rep, 377 unsigned flags, 378 krb5_const_principal requested, 379 krb5_const_principal returned, 380 krb5_keyblock * key) 381{ 382 krb5_error_code ret; 383 PA_ServerReferralData ref; 384 krb5_crypto session; 385 EncryptedData ed; 386 size_t len; 387 krb5_data data; 388 PA_DATA *pa; 389 int i = 0, cmp; 390 391 if (rep->kdc_rep.padata == NULL) 392 goto noreferral; 393 394 pa = krb5_find_padata(rep->kdc_rep.padata->val, 395 rep->kdc_rep.padata->len, 396 KRB5_PADATA_SERVER_REFERRAL, &i); 397 if (pa == NULL) 398 goto noreferral; 399 400 memset(&ed, 0, sizeof(ed)); 401 memset(&ref, 0, sizeof(ref)); 402 403 ret = decode_EncryptedData(pa->padata_value.data, 404 pa->padata_value.length, 405 &ed, &len); 406 if (ret) 407 return ret; 408 if (len != pa->padata_value.length) { 409 free_EncryptedData(&ed); 410 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 411 N_("Referral EncryptedData wrong for realm %s", 412 "realm"), requested->realm); 413 return KRB5KRB_AP_ERR_MODIFIED; 414 } 415 416 ret = krb5_crypto_init(context, key, 0, &session); 417 if (ret) { 418 free_EncryptedData(&ed); 419 return ret; 420 } 421 422 ret = krb5_decrypt_EncryptedData(context, session, 423 KRB5_KU_PA_SERVER_REFERRAL, 424 &ed, &data); 425 free_EncryptedData(&ed); 426 krb5_crypto_destroy(context, session); 427 if (ret) 428 return ret; 429 430 ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); 431 if (ret) { 432 krb5_data_free(&data); 433 return ret; 434 } 435 krb5_data_free(&data); 436 437 if (strcmp(requested->realm, returned->realm) != 0) { 438 free_PA_ServerReferralData(&ref); 439 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 440 N_("server ref realm mismatch, " 441 "requested realm %s got back %s", ""), 442 requested->realm, returned->realm); 443 return KRB5KRB_AP_ERR_MODIFIED; 444 } 445 446 if (krb5_principal_is_krbtgt(context, returned)) { 447 const char *realm = returned->name.name_string.val[1]; 448 449 if (ref.referred_realm == NULL 450 || strcmp(*ref.referred_realm, realm) != 0) 451 { 452 free_PA_ServerReferralData(&ref); 453 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 454 N_("tgt returned with wrong ref", "")); 455 return KRB5KRB_AP_ERR_MODIFIED; 456 } 457 } else if (krb5_principal_compare(context, returned, requested) == 0) { 458 free_PA_ServerReferralData(&ref); 459 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 460 N_("req princ no same as returned", "")); 461 return KRB5KRB_AP_ERR_MODIFIED; 462 } 463 464 if (ref.requested_principal_name) { 465 cmp = _krb5_principal_compare_PrincipalName(context, 466 requested, 467 ref.requested_principal_name); 468 if (!cmp) { 469 free_PA_ServerReferralData(&ref); 470 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 471 N_("referred principal not same " 472 "as requested", "")); 473 return KRB5KRB_AP_ERR_MODIFIED; 474 } 475 } else if (flags & EXTRACT_TICKET_AS_REQ) { 476 free_PA_ServerReferralData(&ref); 477 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 478 N_("Requested principal missing on AS-REQ", "")); 479 return KRB5KRB_AP_ERR_MODIFIED; 480 } 481 482 free_PA_ServerReferralData(&ref); 483 484 return ret; 485noreferral: 486 /* 487 * Expect excact match or that we got a krbtgt 488 */ 489 if (krb5_principal_compare(context, requested, returned) != TRUE && 490 (krb5_realm_compare(context, requested, returned) != TRUE && 491 krb5_principal_is_krbtgt(context, returned) != TRUE)) 492 { 493 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 494 N_("Not same server principal returned " 495 "as requested", "")); 496 return KRB5KRB_AP_ERR_MODIFIED; 497 } 498 return 0; 499} 500 501 502/* 503 * Verify referral data 504 */ 505 506 507static krb5_error_code 508check_client_referral(krb5_context context, 509 krb5_kdc_rep *rep, 510 krb5_const_principal requested, 511 krb5_const_principal mapped, 512 krb5_keyblock const * key) 513{ 514 krb5_error_code ret; 515 PA_ClientCanonicalized canon; 516 krb5_crypto crypto; 517 krb5_data data; 518 PA_DATA *pa; 519 size_t len; 520 int i = 0; 521 522 if (rep->kdc_rep.padata == NULL) 523 goto noreferral; 524 525 pa = krb5_find_padata(rep->kdc_rep.padata->val, 526 rep->kdc_rep.padata->len, 527 KRB5_PADATA_CLIENT_CANONICALIZED, &i); 528 if (pa == NULL) 529 goto noreferral; 530 531 ret = decode_PA_ClientCanonicalized(pa->padata_value.data, 532 pa->padata_value.length, 533 &canon, &len); 534 if (ret) { 535 krb5_set_error_message(context, ret, 536 N_("Failed to decode ClientCanonicalized " 537 "from realm %s", ""), requested->realm); 538 return ret; 539 } 540 541 ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, 542 &canon.names, &len, ret); 543 if (ret) { 544 free_PA_ClientCanonicalized(&canon); 545 return ret; 546 } 547 if (data.length != len) 548 krb5_abortx(context, "internal asn.1 error"); 549 550 ret = krb5_crypto_init(context, key, 0, &crypto); 551 if (ret) { 552 free(data.data); 553 free_PA_ClientCanonicalized(&canon); 554 return ret; 555 } 556 557 ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, 558 data.data, data.length, 559 &canon.canon_checksum); 560 krb5_crypto_destroy(context, crypto); 561 free(data.data); 562 if (ret) { 563 krb5_set_error_message(context, ret, 564 N_("Failed to verify client canonicalized " 565 "data from realm %s", ""), 566 requested->realm); 567 free_PA_ClientCanonicalized(&canon); 568 return ret; 569 } 570 571 if (!_krb5_principal_compare_PrincipalName(context, 572 requested, 573 &canon.names.requested_name)) 574 { 575 free_PA_ClientCanonicalized(&canon); 576 krb5_set_error_message(context, KRB5_PRINC_NOMATCH, 577 N_("Requested name doesn't match" 578 " in client referral", "")); 579 return KRB5_PRINC_NOMATCH; 580 } 581 if (!_krb5_principal_compare_PrincipalName(context, 582 mapped, 583 &canon.names.mapped_name)) 584 { 585 free_PA_ClientCanonicalized(&canon); 586 krb5_set_error_message(context, KRB5_PRINC_NOMATCH, 587 N_("Mapped name doesn't match" 588 " in client referral", "")); 589 return KRB5_PRINC_NOMATCH; 590 } 591 592 return 0; 593 594noreferral: 595 if (krb5_principal_compare(context, requested, mapped) == FALSE && 596 !rep->enc_part.flags.enc_pa_rep) 597 { 598 char *mname = NULL; 599 krb5_unparse_name(context, mapped, &mname); 600 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 601 N_("Not same client principal returned (%s)" 602 "as requested", ""), 603 mname ? mname : "<unknown name>"); 604 krb5_xfree(mname); 605 return KRB5KRB_AP_ERR_MODIFIED; 606 } 607 return 0; 608} 609 610 611static krb5_error_code KRB5_CALLCONV 612decrypt_tkt (krb5_context context, 613 krb5_keyblock *key, 614 krb5_key_usage usage, 615 krb5_const_pointer decrypt_arg, 616 krb5_kdc_rep *dec_rep) 617{ 618 krb5_error_code ret; 619 krb5_data data; 620 size_t size; 621 krb5_crypto crypto; 622 623 ret = krb5_crypto_init(context, key, 0, &crypto); 624 if (ret) 625 return ret; 626 627 ret = krb5_decrypt_EncryptedData (context, 628 crypto, 629 usage, 630 &dec_rep->kdc_rep.enc_part, 631 &data); 632 krb5_crypto_destroy(context, crypto); 633 634 if (ret) 635 return ret; 636 637 ret = decode_EncASRepPart(data.data, 638 data.length, 639 &dec_rep->enc_part, 640 &size); 641 if (ret) 642 ret = decode_EncTGSRepPart(data.data, 643 data.length, 644 &dec_rep->enc_part, 645 &size); 646 krb5_data_free (&data); 647 if (ret) { 648 krb5_set_error_message(context, ret, 649 N_("Failed to decode encpart in ticket", "")); 650 return ret; 651 } 652 return 0; 653} 654 655int 656_krb5_extract_ticket(krb5_context context, 657 krb5_kdc_rep *rep, 658 krb5_creds *creds, 659 krb5_keyblock *key, 660 krb5_key_usage key_usage, 661 krb5_addresses *addrs, 662 unsigned nonce, 663 unsigned flags, 664 krb5_data *request, 665 krb5_decrypt_proc decrypt_proc, 666 krb5_const_pointer decryptarg) 667{ 668 krb5_error_code ret; 669 krb5_principal tmp_principal; 670 size_t len = 0; 671 time_t tmp_time; 672 krb5_timestamp sec_now; 673 674 /* decrypt */ 675 676 if (decrypt_proc == NULL) 677 decrypt_proc = decrypt_tkt; 678 679 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); 680 if (ret) 681 goto out; 682 683 if (rep->enc_part.flags.enc_pa_rep && request && (flags & EXTRACT_TICKET_REQUIRE_ENC_PA)) { 684 krb5_crypto crypto = NULL; 685 Checksum cksum; 686 PA_DATA *pa = NULL; 687 int idx = 0; 688 689 _krb5_debugx(context, 5, "processing enc-ap-rep"); 690 691 if (rep->enc_part.encrypted_pa_data == NULL || 692 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val, 693 rep->enc_part.encrypted_pa_data->len, 694 KRB5_PADATA_REQ_ENC_PA_REP, 695 &idx)) == NULL) 696 { 697 _krb5_debugx(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing"); 698 ret = KRB5KRB_AP_ERR_MODIFIED; 699 goto out; 700 } 701 702 ret = krb5_crypto_init(context, key, 0, &crypto); 703 if (ret) 704 goto out; 705 706 ret = decode_Checksum(pa->padata_value.data, 707 pa->padata_value.length, 708 &cksum, NULL); 709 if (ret) { 710 krb5_crypto_destroy(context, crypto); 711 goto out; 712 } 713 714 ret = krb5_verify_checksum(context, crypto, 715 KRB5_KU_AS_REQ, 716 request->data, request->length, 717 &cksum); 718 krb5_crypto_destroy(context, crypto); 719 free_Checksum(&cksum); 720 _krb5_debug(context, 5, ret, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in"); 721 if (ret) 722 goto out; 723 } 724 725 /* save session key */ 726 727 creds->session.keyvalue.length = 0; 728 creds->session.keyvalue.data = NULL; 729 creds->session.keytype = rep->enc_part.key.keytype; 730 ret = krb5_data_copy (&creds->session.keyvalue, 731 rep->enc_part.key.keyvalue.data, 732 rep->enc_part.key.keyvalue.length); 733 if (ret) { 734 krb5_clear_error_message(context); 735 goto out; 736 } 737 738 /* compare client and save */ 739 ret = _krb5_principalname2krb5_principal(context, 740 &tmp_principal, 741 rep->kdc_rep.cname, 742 rep->kdc_rep.crealm); 743 if (ret) 744 goto out; 745 746 /* check client referral and save principal */ 747 /* anonymous here ? */ 748 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { 749 ret = check_client_referral(context, rep, 750 creds->client, 751 tmp_principal, 752 &creds->session); 753 if (ret) { 754 krb5_free_principal (context, tmp_principal); 755 goto out; 756 } 757 } 758 krb5_free_principal (context, creds->client); 759 creds->client = tmp_principal; 760 761 /* check server referral and save principal */ 762 ret = _krb5_principalname2krb5_principal (context, 763 &tmp_principal, 764 rep->kdc_rep.ticket.sname, 765 rep->kdc_rep.ticket.realm); 766 if (ret) 767 goto out; 768 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ 769 ret = check_server_referral(context, 770 rep, 771 flags, 772 creds->server, 773 tmp_principal, 774 &creds->session); 775 if (ret) { 776 krb5_free_principal (context, tmp_principal); 777 goto out; 778 } 779 } 780 krb5_free_principal(context, creds->server); 781 creds->server = tmp_principal; 782 783 /* verify names */ 784 if(flags & EXTRACT_TICKET_MATCH_REALM){ 785 const char *srealm = krb5_principal_get_realm(context, creds->server); 786 const char *crealm = krb5_principal_get_realm(context, creds->client); 787 788 if (strcmp(rep->enc_part.srealm, srealm) != 0 || 789 strcmp(rep->enc_part.srealm, crealm) != 0) 790 { 791 ret = KRB5KRB_AP_ERR_MODIFIED; 792 krb5_set_error_message(context, ret, "server realm (%s) doesn't match client's (%s)", 793 srealm, crealm); 794 krb5_clear_error_message(context); 795 goto out; 796 } 797 } 798 799 /* compare nonces */ 800 801 if (nonce != (unsigned)rep->enc_part.nonce) { 802 ret = KRB5KRB_AP_ERR_MODIFIED; 803 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 804 goto out; 805 } 806 807 /* set kdc-offset */ 808 809 krb5_timeofday (context, &sec_now); 810 if (rep->enc_part.flags.initial 811 && (flags & EXTRACT_TICKET_TIMESYNC) 812 && context->kdc_sec_offset == 0 813 && krb5_config_get_bool (context, NULL, 814 "libdefaults", 815 "kdc_timesync", 816 NULL)) { 817 context->kdc_sec_offset = (int32_t)(rep->enc_part.authtime - sec_now); 818 krb5_timeofday (context, &sec_now); 819 } 820 821 /* check all times */ 822 823 if (rep->enc_part.starttime) { 824 tmp_time = *rep->enc_part.starttime; 825 } else 826 tmp_time = rep->enc_part.authtime; 827 828 if (creds->times.starttime == 0 829 && krb5_time_abs(tmp_time, sec_now) > context->max_skew) { 830 ret = KRB5KRB_AP_ERR_SKEW; 831 krb5_set_error_message (context, ret, 832 N_("time skew (%ld) larger than max (%d)", ""), 833 (long)krb5_time_abs(tmp_time, sec_now), 834 (int)context->max_skew); 835 goto out; 836 } 837 838 if (creds->times.starttime != 0 839 && tmp_time != creds->times.starttime) { 840 krb5_clear_error_message (context); 841 krb5_set_error_message(context, ret, "startime is not the requested startime"); 842 ret = KRB5KRB_AP_ERR_MODIFIED; 843 goto out; 844 } 845 846 creds->times.starttime = tmp_time; 847 848 if (rep->enc_part.renew_till) { 849 tmp_time = *rep->enc_part.renew_till; 850 } else 851 tmp_time = 0; 852 853 if (creds->times.renew_till != 0 854 && tmp_time > creds->times.renew_till) { 855 krb5_clear_error_message (context); 856 krb5_set_error_message(context, ret, "renewtime is past the requested renewtime"); 857 ret = KRB5KRB_AP_ERR_MODIFIED; 858 goto out; 859 } 860 861 creds->times.renew_till = tmp_time; 862 863 creds->times.authtime = rep->enc_part.authtime; 864 865 if (creds->times.endtime != 0 866 && rep->enc_part.endtime > creds->times.endtime) { 867 krb5_clear_error_message (context); 868 ret = KRB5KRB_AP_ERR_MODIFIED; 869 krb5_set_error_message(context, ret, "endtime is past the requested endtime"); 870 goto out; 871 } 872 873 creds->times.endtime = rep->enc_part.endtime; 874 875 if(rep->enc_part.caddr) 876 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); 877 else if(addrs) 878 krb5_copy_addresses (context, addrs, &creds->addresses); 879 else { 880 creds->addresses.len = 0; 881 creds->addresses.val = NULL; 882 } 883 creds->flags.b = rep->enc_part.flags; 884 885 creds->authdata.len = 0; 886 creds->authdata.val = NULL; 887 888 /* extract ticket */ 889 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, 890 &rep->kdc_rep.ticket, &len, ret); 891 if(ret) 892 goto out; 893 if (creds->ticket.length != len) 894 krb5_abortx(context, "internal error in ASN.1 encoder"); 895 creds->second_ticket.length = 0; 896 creds->second_ticket.data = NULL; 897 898 899out: 900 if (ret) 901 _krb5_debugx(context, 5, "_krb5_extract_ticket failed with %d", ret); 902 903 memset (rep->enc_part.key.keyvalue.data, 0, 904 rep->enc_part.key.keyvalue.length); 905 return ret; 906} 907