1 /* $NetBSD: ticket.c,v 1.5 2019/12/15 22:50:50 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 52 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 53 krb5_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 76 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 77 krb5_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 122 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 123 krb5_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 143 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 144 krb5_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 162 KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL 163 krb5_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 */ 179 KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL 180 krb5_ticket_get_flags(krb5_context context, 181 const krb5_ticket *ticket) 182 { 183 return TicketFlags2int(ticket->ticket.flags); 184 } 185 186 static int 187 find_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 } 317 out: 318 if (ret) { 319 if (*found) { 320 krb5_data_free(data); 321 *found = 0; 322 } 323 } 324 return ret; 325 } 326 327 KRB5_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 371 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 372 krb5_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 404 static krb5_error_code 405 check_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; 515 noreferral: 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 */ 534 static krb5_error_code 535 check_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 if (is_tgs_rep) 547 flags = KRB5_ANON_MATCH_ANY; 548 else if (krb5_principal_is_anonymous(context, requested, KRB5_ANON_MATCH_ANY)) 549 flags = KRB5_ANON_MATCH_UNAUTHENTICATED; 550 else 551 flags = KRB5_ANON_MATCH_AUTHENTICATED; 552 553 if (!krb5_principal_is_anonymous(context, mapped, flags)) 554 return KRB5KRB_AP_ERR_MODIFIED; 555 556 return 0; 557 } 558 559 /* 560 * Verify returned client principal name in anonymous/referral case 561 */ 562 563 static krb5_error_code 564 check_client_mismatch(krb5_context context, 565 krb5_kdc_rep *rep, 566 krb5_const_principal requested, 567 krb5_const_principal mapped, 568 krb5_keyblock const * key) 569 { 570 if (rep->enc_part.flags.anonymous) { 571 if (!krb5_principal_is_anonymous(context, mapped, KRB5_ANON_MATCH_ANY)) { 572 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 573 N_("Anonymous ticket does not contain anonymous " 574 "principal", "")); 575 return KRB5KRB_AP_ERR_MODIFIED; 576 } 577 } else { 578 if (krb5_principal_compare(context, requested, mapped) == FALSE && 579 !rep->enc_part.flags.enc_pa_rep) { 580 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 581 N_("Not same client principal returned " 582 "as requested", "")); 583 return KRB5KRB_AP_ERR_MODIFIED; 584 } 585 } 586 587 return 0; 588 } 589 590 591 static krb5_error_code KRB5_CALLCONV 592 decrypt_tkt (krb5_context context, 593 krb5_keyblock *key, 594 krb5_key_usage usage, 595 krb5_const_pointer decrypt_arg, 596 krb5_kdc_rep *dec_rep) 597 { 598 krb5_error_code ret; 599 krb5_data data; 600 size_t size; 601 krb5_crypto crypto; 602 603 ret = krb5_crypto_init(context, key, 0, &crypto); 604 if (ret) 605 return ret; 606 607 ret = krb5_decrypt_EncryptedData (context, 608 crypto, 609 usage, 610 &dec_rep->kdc_rep.enc_part, 611 &data); 612 krb5_crypto_destroy(context, crypto); 613 614 if (ret) 615 return ret; 616 617 ret = decode_EncASRepPart(data.data, 618 data.length, 619 &dec_rep->enc_part, 620 &size); 621 if (ret) 622 ret = decode_EncTGSRepPart(data.data, 623 data.length, 624 &dec_rep->enc_part, 625 &size); 626 krb5_data_free (&data); 627 if (ret) { 628 krb5_set_error_message(context, ret, 629 N_("Failed to decode encpart in ticket", "")); 630 return ret; 631 } 632 return 0; 633 } 634 635 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 636 _krb5_extract_ticket(krb5_context context, 637 krb5_kdc_rep *rep, 638 krb5_creds *creds, 639 krb5_keyblock *key, 640 krb5_const_pointer keyseed, 641 krb5_key_usage key_usage, 642 krb5_addresses *addrs, 643 unsigned nonce, 644 unsigned flags, 645 krb5_data *request, 646 krb5_decrypt_proc decrypt_proc, 647 krb5_const_pointer decryptarg) 648 { 649 krb5_error_code ret; 650 krb5_principal tmp_principal; 651 size_t len = 0; 652 time_t tmp_time; 653 krb5_timestamp sec_now; 654 655 /* decrypt */ 656 657 if (decrypt_proc == NULL) 658 decrypt_proc = decrypt_tkt; 659 660 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); 661 if (ret) 662 goto out; 663 664 if (rep->enc_part.flags.enc_pa_rep && request) { 665 krb5_crypto crypto = NULL; 666 Checksum cksum; 667 PA_DATA *pa = NULL; 668 int idx = 0; 669 670 _krb5_debug(context, 5, "processing enc-ap-rep"); 671 672 if (rep->enc_part.encrypted_pa_data == NULL || 673 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val, 674 rep->enc_part.encrypted_pa_data->len, 675 KRB5_PADATA_REQ_ENC_PA_REP, 676 &idx)) == NULL) 677 { 678 _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing"); 679 ret = KRB5KRB_AP_ERR_MODIFIED; 680 goto out; 681 } 682 683 ret = krb5_crypto_init(context, key, 0, &crypto); 684 if (ret) 685 goto out; 686 687 ret = decode_Checksum(pa->padata_value.data, 688 pa->padata_value.length, 689 &cksum, NULL); 690 if (ret) { 691 krb5_crypto_destroy(context, crypto); 692 goto out; 693 } 694 695 ret = krb5_verify_checksum(context, crypto, 696 KRB5_KU_AS_REQ, 697 request->data, request->length, 698 &cksum); 699 krb5_crypto_destroy(context, crypto); 700 free_Checksum(&cksum); 701 _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in"); 702 if (ret) 703 goto out; 704 } 705 706 /* save session key */ 707 708 creds->session.keyvalue.length = 0; 709 creds->session.keyvalue.data = NULL; 710 creds->session.keytype = rep->enc_part.key.keytype; 711 ret = krb5_data_copy (&creds->session.keyvalue, 712 rep->enc_part.key.keyvalue.data, 713 rep->enc_part.key.keyvalue.length); 714 if (ret) { 715 krb5_clear_error_message(context); 716 goto out; 717 } 718 719 /* compare client and save */ 720 ret = _krb5_principalname2krb5_principal(context, 721 &tmp_principal, 722 rep->kdc_rep.cname, 723 rep->kdc_rep.crealm); 724 if (ret) 725 goto out; 726 727 /* check KDC supported anonymous if it was requested */ 728 if (flags & EXTRACT_TICKET_MATCH_ANON) { 729 ret = check_client_anonymous(context,rep, 730 creds->client, 731 tmp_principal, 732 request == NULL); /* is TGS */ 733 if (ret) { 734 krb5_free_principal(context, tmp_principal); 735 goto out; 736 } 737 } 738 739 /* check client referral and save principal */ 740 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { 741 ret = check_client_mismatch(context, rep, 742 creds->client, 743 tmp_principal, 744 &creds->session); 745 if (ret) { 746 krb5_free_principal (context, tmp_principal); 747 goto out; 748 } 749 } 750 krb5_free_principal (context, creds->client); 751 creds->client = tmp_principal; 752 753 /* check server referral and save principal */ 754 ret = _krb5_principalname2krb5_principal (context, 755 &tmp_principal, 756 rep->enc_part.sname, 757 rep->enc_part.srealm); 758 if (ret) 759 goto out; 760 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ 761 ret = check_server_referral(context, 762 rep, 763 flags, 764 creds->server, 765 tmp_principal, 766 &creds->session); 767 if (ret) { 768 krb5_free_principal (context, tmp_principal); 769 goto out; 770 } 771 } 772 krb5_free_principal(context, creds->server); 773 creds->server = tmp_principal; 774 775 /* verify names */ 776 if(flags & EXTRACT_TICKET_MATCH_REALM){ 777 const char *srealm = krb5_principal_get_realm(context, creds->server); 778 const char *crealm = krb5_principal_get_realm(context, creds->client); 779 780 if (strcmp(rep->enc_part.srealm, srealm) != 0 || 781 strcmp(rep->enc_part.srealm, crealm) != 0) 782 { 783 ret = KRB5KRB_AP_ERR_MODIFIED; 784 krb5_clear_error_message(context); 785 goto out; 786 } 787 } 788 789 /* compare nonces */ 790 791 if (nonce != (unsigned)rep->enc_part.nonce) { 792 ret = KRB5KRB_AP_ERR_MODIFIED; 793 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 794 goto out; 795 } 796 797 /* set kdc-offset */ 798 799 krb5_timeofday (context, &sec_now); 800 if (rep->enc_part.flags.initial 801 && (flags & EXTRACT_TICKET_TIMESYNC) 802 && context->kdc_sec_offset == 0 803 && krb5_config_get_bool (context, NULL, 804 "libdefaults", 805 "kdc_timesync", 806 NULL)) { 807 context->kdc_sec_offset = rep->enc_part.authtime - sec_now; 808 krb5_timeofday (context, &sec_now); 809 } 810 811 /* check all times */ 812 813 if (rep->enc_part.starttime) { 814 tmp_time = *rep->enc_part.starttime; 815 } else 816 tmp_time = rep->enc_part.authtime; 817 818 if (creds->times.starttime == 0 819 && labs(tmp_time - sec_now) > context->max_skew) { 820 ret = KRB5KRB_AP_ERR_SKEW; 821 krb5_set_error_message (context, ret, 822 N_("time skew (%ld) larger than max (%ld)", ""), 823 labs(tmp_time - sec_now), 824 (long)context->max_skew); 825 goto out; 826 } 827 828 if (creds->times.starttime != 0 829 && tmp_time != creds->times.starttime) { 830 krb5_clear_error_message (context); 831 ret = KRB5KRB_AP_ERR_MODIFIED; 832 goto out; 833 } 834 835 creds->times.starttime = tmp_time; 836 837 if (rep->enc_part.renew_till) { 838 tmp_time = *rep->enc_part.renew_till; 839 } else 840 tmp_time = 0; 841 842 if (creds->times.renew_till != 0 843 && tmp_time > creds->times.renew_till) { 844 krb5_clear_error_message (context); 845 ret = KRB5KRB_AP_ERR_MODIFIED; 846 goto out; 847 } 848 849 creds->times.renew_till = tmp_time; 850 851 creds->times.authtime = rep->enc_part.authtime; 852 853 if (creds->times.endtime != 0 854 && rep->enc_part.endtime > creds->times.endtime) { 855 krb5_clear_error_message (context); 856 ret = KRB5KRB_AP_ERR_MODIFIED; 857 goto out; 858 } 859 860 creds->times.endtime = rep->enc_part.endtime; 861 862 if(rep->enc_part.caddr) 863 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); 864 else if(addrs) 865 krb5_copy_addresses (context, addrs, &creds->addresses); 866 else { 867 creds->addresses.len = 0; 868 creds->addresses.val = NULL; 869 } 870 creds->flags.b = rep->enc_part.flags; 871 872 creds->authdata.len = 0; 873 creds->authdata.val = NULL; 874 875 /* extract ticket */ 876 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, 877 &rep->kdc_rep.ticket, &len, ret); 878 if(ret) 879 goto out; 880 if (creds->ticket.length != len) 881 krb5_abortx(context, "internal error in ASN.1 encoder"); 882 creds->second_ticket.length = 0; 883 creds->second_ticket.data = NULL; 884 885 886 out: 887 memset (rep->enc_part.key.keyvalue.data, 0, 888 rep->enc_part.key.keyvalue.length); 889 return ret; 890 } 891