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