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 50 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 51 krb5_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 74 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 75 krb5_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 123 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 124 krb5_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 144 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 145 krb5_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 163 KRB5_LIB_FUNCTION time_t KRB5_LIB_CALL 164 krb5_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 */ 180 KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL 181 krb5_ticket_get_flags(krb5_context context, 182 const krb5_ticket *ticket) 183 { 184 return TicketFlags2int(ticket->ticket.flags); 185 } 186 187 static int 188 find_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 } 318 out: 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 341 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 342 krb5_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 374 static krb5_error_code 375 check_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; 485 noreferral: 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 507 static krb5_error_code 508 check_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 594 noreferral: 595 if (krb5_principal_compare(context, requested, mapped) == FALSE) { 596 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, 597 N_("Not same client principal returned " 598 "as requested", "")); 599 return KRB5KRB_AP_ERR_MODIFIED; 600 } 601 return 0; 602 } 603 604 605 static krb5_error_code KRB5_CALLCONV 606 decrypt_tkt (krb5_context context, 607 krb5_keyblock *key, 608 krb5_key_usage usage, 609 krb5_const_pointer decrypt_arg, 610 krb5_kdc_rep *dec_rep) 611 { 612 krb5_error_code ret; 613 krb5_data data; 614 size_t size; 615 krb5_crypto crypto; 616 617 ret = krb5_crypto_init(context, key, 0, &crypto); 618 if (ret) 619 return ret; 620 621 ret = krb5_decrypt_EncryptedData (context, 622 crypto, 623 usage, 624 &dec_rep->kdc_rep.enc_part, 625 &data); 626 krb5_crypto_destroy(context, crypto); 627 628 if (ret) 629 return ret; 630 631 ret = decode_EncASRepPart(data.data, 632 data.length, 633 &dec_rep->enc_part, 634 &size); 635 if (ret) 636 ret = decode_EncTGSRepPart(data.data, 637 data.length, 638 &dec_rep->enc_part, 639 &size); 640 krb5_data_free (&data); 641 if (ret) { 642 krb5_set_error_message(context, ret, 643 N_("Failed to decode encpart in ticket", "")); 644 return ret; 645 } 646 return 0; 647 } 648 649 int 650 _krb5_extract_ticket(krb5_context context, 651 krb5_kdc_rep *rep, 652 krb5_creds *creds, 653 krb5_keyblock *key, 654 krb5_const_pointer keyseed, 655 krb5_key_usage key_usage, 656 krb5_addresses *addrs, 657 unsigned nonce, 658 unsigned flags, 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 /* save session key */ 678 679 creds->session.keyvalue.length = 0; 680 creds->session.keyvalue.data = NULL; 681 creds->session.keytype = rep->enc_part.key.keytype; 682 ret = krb5_data_copy (&creds->session.keyvalue, 683 rep->enc_part.key.keyvalue.data, 684 rep->enc_part.key.keyvalue.length); 685 if (ret) { 686 krb5_clear_error_message(context); 687 goto out; 688 } 689 690 /* compare client and save */ 691 ret = _krb5_principalname2krb5_principal (context, 692 &tmp_principal, 693 rep->kdc_rep.cname, 694 rep->kdc_rep.crealm); 695 if (ret) 696 goto out; 697 698 /* check client referral and save principal */ 699 /* anonymous here ? */ 700 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { 701 ret = check_client_referral(context, rep, 702 creds->client, 703 tmp_principal, 704 &creds->session); 705 if (ret) { 706 krb5_free_principal (context, tmp_principal); 707 goto out; 708 } 709 } 710 krb5_free_principal (context, creds->client); 711 creds->client = tmp_principal; 712 713 /* check server referral and save principal */ 714 ret = _krb5_principalname2krb5_principal (context, 715 &tmp_principal, 716 rep->enc_part.sname, 717 rep->enc_part.srealm); 718 if (ret) 719 goto out; 720 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ 721 ret = check_server_referral(context, 722 rep, 723 flags, 724 creds->server, 725 tmp_principal, 726 &creds->session); 727 if (ret) { 728 krb5_free_principal (context, tmp_principal); 729 goto out; 730 } 731 } 732 krb5_free_principal(context, creds->server); 733 creds->server = tmp_principal; 734 735 /* verify names */ 736 if(flags & EXTRACT_TICKET_MATCH_REALM){ 737 const char *srealm = krb5_principal_get_realm(context, creds->server); 738 const char *crealm = krb5_principal_get_realm(context, creds->client); 739 740 if (strcmp(rep->enc_part.srealm, srealm) != 0 || 741 strcmp(rep->enc_part.srealm, crealm) != 0) 742 { 743 ret = KRB5KRB_AP_ERR_MODIFIED; 744 krb5_clear_error_message(context); 745 goto out; 746 } 747 } 748 749 /* compare nonces */ 750 751 if (nonce != (unsigned)rep->enc_part.nonce) { 752 ret = KRB5KRB_AP_ERR_MODIFIED; 753 krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 754 goto out; 755 } 756 757 /* set kdc-offset */ 758 759 krb5_timeofday (context, &sec_now); 760 if (rep->enc_part.flags.initial 761 && (flags & EXTRACT_TICKET_TIMESYNC) 762 && context->kdc_sec_offset == 0 763 && krb5_config_get_bool (context, NULL, 764 "libdefaults", 765 "kdc_timesync", 766 NULL)) { 767 context->kdc_sec_offset = rep->enc_part.authtime - sec_now; 768 krb5_timeofday (context, &sec_now); 769 } 770 771 /* check all times */ 772 773 if (rep->enc_part.starttime) { 774 tmp_time = *rep->enc_part.starttime; 775 } else 776 tmp_time = rep->enc_part.authtime; 777 778 if (creds->times.starttime == 0 779 && abs(tmp_time - sec_now) > context->max_skew) { 780 ret = KRB5KRB_AP_ERR_SKEW; 781 krb5_set_error_message (context, ret, 782 N_("time skew (%d) larger than max (%d)", ""), 783 abs(tmp_time - sec_now), 784 (int)context->max_skew); 785 goto out; 786 } 787 788 if (creds->times.starttime != 0 789 && tmp_time != creds->times.starttime) { 790 krb5_clear_error_message (context); 791 ret = KRB5KRB_AP_ERR_MODIFIED; 792 goto out; 793 } 794 795 creds->times.starttime = tmp_time; 796 797 if (rep->enc_part.renew_till) { 798 tmp_time = *rep->enc_part.renew_till; 799 } else 800 tmp_time = 0; 801 802 if (creds->times.renew_till != 0 803 && tmp_time > creds->times.renew_till) { 804 krb5_clear_error_message (context); 805 ret = KRB5KRB_AP_ERR_MODIFIED; 806 goto out; 807 } 808 809 creds->times.renew_till = tmp_time; 810 811 creds->times.authtime = rep->enc_part.authtime; 812 813 if (creds->times.endtime != 0 814 && rep->enc_part.endtime > creds->times.endtime) { 815 krb5_clear_error_message (context); 816 ret = KRB5KRB_AP_ERR_MODIFIED; 817 goto out; 818 } 819 820 creds->times.endtime = rep->enc_part.endtime; 821 822 if(rep->enc_part.caddr) 823 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); 824 else if(addrs) 825 krb5_copy_addresses (context, addrs, &creds->addresses); 826 else { 827 creds->addresses.len = 0; 828 creds->addresses.val = NULL; 829 } 830 creds->flags.b = rep->enc_part.flags; 831 832 creds->authdata.len = 0; 833 creds->authdata.val = NULL; 834 835 /* extract ticket */ 836 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, 837 &rep->kdc_rep.ticket, &len, ret); 838 if(ret) 839 goto out; 840 if (creds->ticket.length != len) 841 krb5_abortx(context, "internal error in ASN.1 encoder"); 842 creds->second_ticket.length = 0; 843 creds->second_ticket.data = NULL; 844 845 846 out: 847 memset (rep->enc_part.key.keyvalue.data, 0, 848 rep->enc_part.key.keyvalue.length); 849 return ret; 850 } 851