1/* $NetBSD: ticket.c,v 1.6 2023/06/19 21:41:45 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38#include "krb5_locl.h" 39 40/** 41 * Free ticket and content 42 * 43 * @param context a Kerberos 5 context 44 * @param ticket ticket to free 45 * 46 * @return Returns 0 to indicate success. Otherwise an kerberos et 47 * error code is returned, see krb5_get_error_message(). 48 * 49 * @ingroup krb5 50 */ 51 52KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 53krb5_free_ticket(krb5_context context, 54 krb5_ticket *ticket) 55{ 56 free_EncTicketPart(&ticket->ticket); 57 krb5_free_principal(context, ticket->client); 58 krb5_free_principal(context, ticket->server); 59 free(ticket); 60 return 0; 61} 62 63/** 64 * Copy ticket and content 65 * 66 * @param context a Kerberos 5 context 67 * @param from ticket to copy 68 * @param to new copy of ticket, free with krb5_free_ticket() 69 * 70 * @return Returns 0 to indicate success. Otherwise an kerberos et 71 * error code is returned, see krb5_get_error_message(). 72 * 73 * @ingroup krb5 74 */ 75 76KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 77krb5_copy_ticket(krb5_context context, 78 const krb5_ticket *from, 79 krb5_ticket **to) 80{ 81 krb5_error_code ret; 82 krb5_ticket *tmp; 83 84 *to = NULL; 85 tmp = malloc(sizeof(*tmp)); 86 if (tmp == NULL) 87 return krb5_enomem(context); 88 if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){ 89 free(tmp); 90 return ret; 91 } 92 ret = krb5_copy_principal(context, from->client, &tmp->client); 93 if(ret){ 94 free_EncTicketPart(&tmp->ticket); 95 free(tmp); 96 return ret; 97 } 98 ret = krb5_copy_principal(context, from->server, &tmp->server); 99 if(ret){ 100 krb5_free_principal(context, tmp->client); 101 free_EncTicketPart(&tmp->ticket); 102 free(tmp); 103 return ret; 104 } 105 *to = tmp; 106 return 0; 107} 108 109/** 110 * Return client principal in ticket 111 * 112 * @param context a Kerberos 5 context 113 * @param ticket ticket to copy 114 * @param client client principal, free with krb5_free_principal() 115 * 116 * @return Returns 0 to indicate success. Otherwise an kerberos et 117 * error code is returned, see krb5_get_error_message(). 118 * 119 * @ingroup krb5 120 */ 121 122KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 123krb5_ticket_get_client(krb5_context context, 124 const krb5_ticket *ticket, 125 krb5_principal *client) 126{ 127 return krb5_copy_principal(context, ticket->client, client); 128} 129 130/** 131 * Return server principal in ticket 132 * 133 * @param context a Kerberos 5 context 134 * @param ticket ticket to copy 135 * @param server server principal, free with krb5_free_principal() 136 * 137 * @return Returns 0 to indicate success. Otherwise an kerberos et 138 * error code is returned, see krb5_get_error_message(). 139 * 140 * @ingroup krb5 141 */ 142 143KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 144krb5_ticket_get_server(krb5_context context, 145 const krb5_ticket *ticket, 146 krb5_principal *server) 147{ 148 return krb5_copy_principal(context, ticket->server, server); 149} 150 151/** 152 * Return end time of ticket 153 * 154 * @param context a Kerberos 5 context 155 * @param ticket ticket to copy 156 * 157 * @return end time of ticket 158 * 159 * @ingroup krb5 160 */ 161 162KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL 163krb5_ticket_get_endtime(krb5_context context, 164 const krb5_ticket *ticket) 165{ 166 return ticket->ticket.endtime; 167} 168 169/** 170 * Get the flags from the Kerberos ticket 171 * 172 * @param context Kerberos context 173 * @param ticket Kerberos ticket 174 * 175 * @return ticket flags 176 * 177 * @ingroup krb5_ticket 178 */ 179KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL 180krb5_ticket_get_flags(krb5_context context, 181 const krb5_ticket *ticket) 182{ 183 return TicketFlags2int(ticket->ticket.flags); 184} 185 186static int 187find_type_in_ad(krb5_context context, 188 int type, 189 krb5_data *data, 190 krb5_boolean *found, 191 krb5_boolean failp, 192 krb5_keyblock *sessionkey, 193 const AuthorizationData *ad, 194 int level) 195{ 196 krb5_error_code ret = 0; 197 size_t i; 198 199 if (level > 9) { 200 ret = ENOENT; /* XXX */ 201 krb5_set_error_message(context, ret, 202 N_("Authorization data nested deeper " 203 "then %d levels, stop searching", ""), 204 level); 205 goto out; 206 } 207 208 /* 209 * Only copy out the element the first time we get to it, we need 210 * to run over the whole authorization data fields to check if 211 * there are any container clases we need to care about. 212 */ 213 for (i = 0; i < ad->len; i++) { 214 if (!*found && ad->val[i].ad_type == type) { 215 ret = der_copy_octet_string(&ad->val[i].ad_data, data); 216 if (ret) { 217 krb5_set_error_message(context, ret, 218 N_("malloc: out of memory", "")); 219 goto out; 220 } 221 *found = TRUE; 222 continue; 223 } 224 switch (ad->val[i].ad_type) { 225 case KRB5_AUTHDATA_IF_RELEVANT: { 226 AuthorizationData child; 227 ret = decode_AuthorizationData(ad->val[i].ad_data.data, 228 ad->val[i].ad_data.length, 229 &child, 230 NULL); 231 if (ret) { 232 krb5_set_error_message(context, ret, 233 N_("Failed to decode " 234 "IF_RELEVANT with %d", ""), 235 (int)ret); 236 goto out; 237 } 238 ret = find_type_in_ad(context, type, data, found, FALSE, 239 sessionkey, &child, level + 1); 240 free_AuthorizationData(&child); 241 if (ret) 242 goto out; 243 break; 244 } 245#if 0 /* XXX test */ 246 case KRB5_AUTHDATA_KDC_ISSUED: { 247 AD_KDCIssued child; 248 249 ret = decode_AD_KDCIssued(ad->val[i].ad_data.data, 250 ad->val[i].ad_data.length, 251 &child, 252 NULL); 253 if (ret) { 254 krb5_set_error_message(context, ret, 255 N_("Failed to decode " 256 "AD_KDCIssued with %d", ""), 257 ret); 258 goto out; 259 } 260 if (failp) { 261 krb5_boolean valid; 262 krb5_data buf; 263 size_t len; 264 265 ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length, 266 &child.elements, &len, ret); 267 if (ret) { 268 free_AD_KDCIssued(&child); 269 krb5_clear_error_message(context); 270 goto out; 271 } 272 if(buf.length != len) 273 krb5_abortx(context, "internal error in ASN.1 encoder"); 274 275 ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf, 276 &child.ad_checksum, &valid); 277 krb5_data_free(&buf); 278 if (ret) { 279 free_AD_KDCIssued(&child); 280 goto out; 281 } 282 if (!valid) { 283 krb5_clear_error_message(context); 284 ret = ENOENT; 285 free_AD_KDCIssued(&child); 286 goto out; 287 } 288 } 289 ret = find_type_in_ad(context, type, data, found, failp, sessionkey, 290 &child.elements, level + 1); 291 free_AD_KDCIssued(&child); 292 if (ret) 293 goto out; 294 break; 295 } 296#endif 297 case KRB5_AUTHDATA_AND_OR: 298 if (!failp) 299 break; 300 ret = ENOENT; /* XXX */ 301 krb5_set_error_message(context, ret, 302 N_("Authorization data contains " 303 "AND-OR element that is unknown to the " 304 "application", "")); 305 goto out; 306 default: 307 if (!failp) 308 break; 309 ret = ENOENT; /* XXX */ 310 krb5_set_error_message(context, ret, 311 N_("Authorization data contains " 312 "unknown type (%d) ", ""), 313 ad->val[i].ad_type); 314 goto out; 315 } 316 } 317out: 318 if (ret) { 319 if (*found) { 320 krb5_data_free(data); 321 *found = 0; 322 } 323 } 324 return ret; 325} 326 327KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 328_krb5_get_ad(krb5_context context, 329 const AuthorizationData *ad, 330 krb5_keyblock *sessionkey, 331 int type, 332 krb5_data *data) 333{ 334 krb5_boolean found = FALSE; 335 krb5_error_code ret; 336 337 krb5_data_zero(data); 338 339 if (ad == NULL) { 340 krb5_set_error_message(context, ENOENT, 341 N_("No authorization data", "")); 342 return ENOENT; /* XXX */ 343 } 344 345 ret = find_type_in_ad(context, type, data, &found, TRUE, sessionkey, ad, 0); 346 if (ret) 347 return ret; 348 if (!found) { 349 krb5_set_error_message(context, ENOENT, 350 N_("Have no authorization data of type %d", ""), 351 type); 352 return ENOENT; /* XXX */ 353 } 354 return 0; 355} 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 * Verify KDC supported anonymous if requested 533 */ 534static krb5_error_code 535check_client_anonymous(krb5_context context, 536 krb5_kdc_rep *rep, 537 krb5_const_principal requested, 538 krb5_const_principal mapped, 539 krb5_boolean is_tgs_rep) 540{ 541 int flags; 542 543 if (!rep->enc_part.flags.anonymous) 544 return KRB5KDC_ERR_BADOPTION; 545 546 /* 547 * Here we must validate that the AS returned a ticket of the expected type 548 * for either a fully anonymous request, or authenticated request for an 549 * anonymous ticket. If this is a TGS request, we're done. Then if the 550 * 'requested' principal was anonymous, we'll check the 'mapped' principal 551 * accordingly (without enforcing the name type and perhaps the realm). 552 * Finally, if the 'requested' principal was not anonymous, well check 553 * that the 'mapped' principal has an anonymous name and type, in a 554 * non-anonymous realm. (Should we also be checking for a realm match 555 * between the request and the mapped name in this case?) 556 */ 557 if (is_tgs_rep) 558 flags = KRB5_ANON_MATCH_ANY_NONT; 559 else if (krb5_principal_is_anonymous(context, requested, 560 KRB5_ANON_MATCH_ANY_NONT)) 561 flags = KRB5_ANON_MATCH_UNAUTHENTICATED | KRB5_ANON_IGNORE_NAME_TYPE; 562 else 563 flags = KRB5_ANON_MATCH_AUTHENTICATED; 564 565 if (!krb5_principal_is_anonymous(context, mapped, flags)) 566 return KRB5KRB_AP_ERR_MODIFIED; 567 568 return 0; 569} 570 571/* 572 * Verify returned client principal name in anonymous/referral case 573 */ 574 575static krb5_error_code 576check_client_mismatch(krb5_context context, 577 krb5_kdc_rep *rep, 578 krb5_const_principal requested, 579 krb5_const_principal mapped, 580 krb5_keyblock const * key) 581{ 582 if (rep->enc_part.flags.anonymous) { 583 if (!krb5_principal_is_anonymous(context, mapped, 584 KRB5_ANON_MATCH_ANY_NONT)) { 585 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 586 N_("Anonymous ticket does not contain anonymous " 587 "principal", "")); 588 return KRB5KRB_AP_ERR_MODIFIED; 589 } 590 } else { 591 if (krb5_principal_compare(context, requested, mapped) == FALSE && 592 !rep->enc_part.flags.enc_pa_rep) { 593 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 594 N_("Not same client principal returned " 595 "as requested", "")); 596 return KRB5KRB_AP_ERR_MODIFIED; 597 } 598 } 599 600 return 0; 601} 602 603 604static krb5_error_code KRB5_CALLCONV 605decrypt_tkt (krb5_context context, 606 krb5_keyblock *key, 607 krb5_key_usage usage, 608 krb5_const_pointer decrypt_arg, 609 krb5_kdc_rep *dec_rep) 610{ 611 krb5_error_code ret; 612 krb5_data data; 613 size_t size; 614 krb5_crypto crypto; 615 616 ret = krb5_crypto_init(context, key, 0, &crypto); 617 if (ret) 618 return ret; 619 620 ret = krb5_decrypt_EncryptedData (context, 621 crypto, 622 usage, 623 &dec_rep->kdc_rep.enc_part, 624 &data); 625 krb5_crypto_destroy(context, crypto); 626 627 if (ret) 628 return ret; 629 630 ret = decode_EncASRepPart(data.data, 631 data.length, 632 &dec_rep->enc_part, 633 &size); 634 if (ret) 635 ret = decode_EncTGSRepPart(data.data, 636 data.length, 637 &dec_rep->enc_part, 638 &size); 639 krb5_data_free (&data); 640 if (ret) { 641 krb5_set_error_message(context, ret, 642 N_("Failed to decode encpart in ticket", "")); 643 return ret; 644 } 645 return 0; 646} 647 648KRB5_LIB_FUNCTION int KRB5_LIB_CALL 649_krb5_extract_ticket(krb5_context context, 650 krb5_kdc_rep *rep, 651 krb5_creds *creds, 652 krb5_keyblock *key, 653 krb5_const_pointer keyseed, 654 krb5_key_usage key_usage, 655 krb5_addresses *addrs, 656 unsigned nonce, 657 unsigned flags, 658 krb5_data *request, 659 krb5_decrypt_proc decrypt_proc, 660 krb5_const_pointer decryptarg) 661{ 662 krb5_error_code ret; 663 krb5_principal tmp_principal; 664 size_t len = 0; 665 time_t tmp_time; 666 krb5_timestamp sec_now; 667 668 /* decrypt */ 669 670 if (decrypt_proc == NULL) 671 decrypt_proc = decrypt_tkt; 672 673 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); 674 if (ret) 675 goto out; 676 677 if (rep->enc_part.flags.enc_pa_rep && request) { 678 krb5_crypto crypto = NULL; 679 Checksum cksum; 680 PA_DATA *pa = NULL; 681 int idx = 0; 682 683 _krb5_debug(context, 5, "processing enc-ap-rep"); 684 685 if (rep->enc_part.encrypted_pa_data == NULL || 686 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val, 687 rep->enc_part.encrypted_pa_data->len, 688 KRB5_PADATA_REQ_ENC_PA_REP, 689 &idx)) == NULL) 690 { 691 _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing"); 692 ret = KRB5KRB_AP_ERR_MODIFIED; 693 goto out; 694 } 695 696 ret = krb5_crypto_init(context, key, 0, &crypto); 697 if (ret) 698 goto out; 699 700 ret = decode_Checksum(pa->padata_value.data, 701 pa->padata_value.length, 702 &cksum, NULL); 703 if (ret) { 704 krb5_crypto_destroy(context, crypto); 705 goto out; 706 } 707 708 ret = krb5_verify_checksum(context, crypto, 709 KRB5_KU_AS_REQ, 710 request->data, request->length, 711 &cksum); 712 krb5_crypto_destroy(context, crypto); 713 free_Checksum(&cksum); 714 _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in"); 715 if (ret) 716 goto out; 717 } 718 719 /* save session key */ 720 721 creds->session.keyvalue.length = 0; 722 creds->session.keyvalue.data = NULL; 723 creds->session.keytype = rep->enc_part.key.keytype; 724 ret = krb5_data_copy (&creds->session.keyvalue, 725 rep->enc_part.key.keyvalue.data, 726 rep->enc_part.key.keyvalue.length); 727 if (ret) { 728 krb5_clear_error_message(context); 729 goto out; 730 } 731 732 /* compare client and save */ 733 ret = _krb5_principalname2krb5_principal(context, 734 &tmp_principal, 735 rep->kdc_rep.cname, 736 rep->kdc_rep.crealm); 737 if (ret) 738 goto out; 739 740 /* check KDC supported anonymous if it was requested */ 741 if (flags & EXTRACT_TICKET_MATCH_ANON) { 742 ret = check_client_anonymous(context,rep, 743 creds->client, 744 tmp_principal, 745 request == NULL); /* is TGS */ 746 if (ret) { 747 krb5_free_principal(context, tmp_principal); 748 goto out; 749 } 750 } 751 752 /* check client referral and save principal */ 753 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { 754 ret = check_client_mismatch(context, rep, 755 creds->client, 756 tmp_principal, 757 &creds->session); 758 if (ret) { 759 krb5_free_principal (context, tmp_principal); 760 goto out; 761 } 762 } 763 krb5_free_principal (context, creds->client); 764 creds->client = tmp_principal; 765 766 /* check server referral and save principal */ 767 ret = _krb5_principalname2krb5_principal (context, 768 &tmp_principal, 769 rep->enc_part.sname, 770 rep->enc_part.srealm); 771 if (ret) 772 goto out; 773 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ 774 ret = check_server_referral(context, 775 rep, 776 flags, 777 creds->server, 778 tmp_principal, 779 &creds->session); 780 if (ret) { 781 krb5_free_principal (context, tmp_principal); 782 goto out; 783 } 784 } 785 krb5_free_principal(context, creds->server); 786 creds->server = tmp_principal; 787 788 /* verify names */ 789 if(flags & EXTRACT_TICKET_MATCH_REALM){ 790 const char *srealm = krb5_principal_get_realm(context, creds->server); 791 const char *crealm = krb5_principal_get_realm(context, creds->client); 792 793 if (strcmp(rep->enc_part.srealm, srealm) != 0 || 794 strcmp(rep->enc_part.srealm, crealm) != 0) 795 { 796 ret = KRB5KRB_AP_ERR_MODIFIED; 797 krb5_clear_error_message(context); 798 goto out; 799 } 800 } 801 802 /* compare nonces */ 803 804 if (nonce != (unsigned)rep->enc_part.nonce) { 805 ret = KRB5KRB_AP_ERR_MODIFIED; 806 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 807 goto out; 808 } 809 810 /* set kdc-offset */ 811 812 krb5_timeofday (context, &sec_now); 813 if (rep->enc_part.flags.initial 814 && (flags & EXTRACT_TICKET_TIMESYNC) 815 && context->kdc_sec_offset == 0 816 && krb5_config_get_bool (context, NULL, 817 "libdefaults", 818 "kdc_timesync", 819 NULL)) { 820 context->kdc_sec_offset = rep->enc_part.authtime - sec_now; 821 krb5_timeofday (context, &sec_now); 822 } 823 824 /* check all times */ 825 826 if (rep->enc_part.starttime) { 827 tmp_time = *rep->enc_part.starttime; 828 } else 829 tmp_time = rep->enc_part.authtime; 830 831 if (creds->times.starttime == 0 832 && labs(tmp_time - sec_now) > context->max_skew) { 833 ret = KRB5KRB_AP_ERR_SKEW; 834 krb5_set_error_message (context, ret, 835 N_("time skew (%ld) larger than max (%ld)", ""), 836 labs(tmp_time - sec_now), 837 (long)context->max_skew); 838 goto out; 839 } 840 841 if (creds->times.starttime != 0 842 && tmp_time != creds->times.starttime) { 843 krb5_clear_error_message (context); 844 ret = KRB5KRB_AP_ERR_MODIFIED; 845 goto out; 846 } 847 848 creds->times.starttime = tmp_time; 849 850 if (rep->enc_part.renew_till) { 851 tmp_time = *rep->enc_part.renew_till; 852 } else 853 tmp_time = 0; 854 855 if (creds->times.renew_till != 0 856 && tmp_time > creds->times.renew_till) { 857 krb5_clear_error_message (context); 858 ret = KRB5KRB_AP_ERR_MODIFIED; 859 goto out; 860 } 861 862 creds->times.renew_till = tmp_time; 863 864 creds->times.authtime = rep->enc_part.authtime; 865 866 if (creds->times.endtime != 0 867 && rep->enc_part.endtime > creds->times.endtime) { 868 krb5_clear_error_message (context); 869 ret = KRB5KRB_AP_ERR_MODIFIED; 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 memset (rep->enc_part.key.keyvalue.data, 0, 901 rep->enc_part.key.keyvalue.length); 902 return ret; 903} 904