2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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
36 #include "krb5_locl.h"
39 * Free ticket and content
41 * @param context a Kerberos 5 context
42 * @param ticket ticket to free
44 * @return Returns 0 to indicate success. Otherwise an kerberos et
45 * error code is returned, see krb5_get_error_message().
50 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
51 krb5_free_ticket(krb5_context context
,
54 free_EncTicketPart(&ticket
->ticket
);
55 krb5_free_principal(context
, ticket
->client
);
56 krb5_free_principal(context
, ticket
->server
);
62 * Copy ticket and content
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()
68 * @return Returns 0 to indicate success. Otherwise an kerberos et
69 * error code is returned, see krb5_get_error_message().
74 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
75 krb5_copy_ticket(krb5_context context
,
76 const krb5_ticket
*from
,
83 tmp
= malloc(sizeof(*tmp
));
85 return krb5_enomem(context
);
86 if((ret
= copy_EncTicketPart(&from
->ticket
, &tmp
->ticket
))){
90 ret
= krb5_copy_principal(context
, from
->client
, &tmp
->client
);
92 free_EncTicketPart(&tmp
->ticket
);
96 ret
= krb5_copy_principal(context
, from
->server
, &tmp
->server
);
98 krb5_free_principal(context
, tmp
->client
);
99 free_EncTicketPart(&tmp
->ticket
);
108 * Return client principal in ticket
110 * @param context a Kerberos 5 context
111 * @param ticket ticket to copy
112 * @param client client principal, free with krb5_free_principal()
114 * @return Returns 0 to indicate success. Otherwise an kerberos et
115 * error code is returned, see krb5_get_error_message().
120 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
121 krb5_ticket_get_client(krb5_context context
,
122 const krb5_ticket
*ticket
,
123 krb5_principal
*client
)
125 return krb5_copy_principal(context
, ticket
->client
, client
);
129 * Return server principal in ticket
131 * @param context a Kerberos 5 context
132 * @param ticket ticket to copy
133 * @param server server principal, free with krb5_free_principal()
135 * @return Returns 0 to indicate success. Otherwise an kerberos et
136 * error code is returned, see krb5_get_error_message().
141 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
142 krb5_ticket_get_server(krb5_context context
,
143 const krb5_ticket
*ticket
,
144 krb5_principal
*server
)
146 return krb5_copy_principal(context
, ticket
->server
, server
);
150 * Return end time of a ticket
152 * @param context a Kerberos 5 context
153 * @param ticket ticket to copy
155 * @return end time of ticket
160 KRB5_LIB_FUNCTION
time_t KRB5_LIB_CALL
161 krb5_ticket_get_endtime(krb5_context context
,
162 const krb5_ticket
*ticket
)
164 return ticket
->ticket
.endtime
;
168 * Return authentication, start, end, and renew limit times of a ticket
170 * @param context a Kerberos 5 context
171 * @param ticket ticket to copy
172 * @param t pointer to krb5_times structure
177 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
178 krb5_ticket_get_times(krb5_context context
,
179 const krb5_ticket
*ticket
,
182 t
->authtime
= ticket
->ticket
.authtime
;
183 t
->starttime
= ticket
->ticket
.starttime
? *ticket
->ticket
.starttime
:
185 t
->endtime
= ticket
->ticket
.endtime
;
186 t
->renew_till
= ticket
->ticket
.renew_till
? *ticket
->ticket
.renew_till
:
191 * Get the flags from the Kerberos ticket
193 * @param context Kerberos context
194 * @param ticket Kerberos ticket
196 * @return ticket flags
198 * @ingroup krb5_ticket
200 KRB5_LIB_FUNCTION
unsigned long KRB5_LIB_CALL
201 krb5_ticket_get_flags(krb5_context context
,
202 const krb5_ticket
*ticket
)
204 return TicketFlags2int(ticket
->ticket
.flags
);
208 * Find an authz-data element in the given `ad'. If `failp', then validate any
209 * containing AD-KDC-ISSUED's keyed checksum with the `sessionkey' (if given).
211 * All AD-KDC-ISSUED will be validated (if requested) even when `type' is
212 * `KRB5_AUTHDATA_KDC_ISSUED'.
214 * Only the first matching element will be output (via `data').
216 * Note that all AD-KDC-ISSUEDs found while traversing the authz-data will be
217 * validated, though only the first one will be returned.
219 * XXX We really need a better interface though. First, forget AD-AND-OR --
220 * just remove it. Second, probably forget AD-KDC-ISSUED, but still, between
221 * that, the PAC, and the CAMMAC, we need an interface that can:
223 * a) take the derived keys instead of the service key or the session key,
224 * b) can indicate whether the element was marked critical,
225 * c) can indicate whether the element was authenticated to the KDC,
226 * d) can iterate over all the instances found (if more than one is found).
228 * Also, we need to know here if the authz-data is from a Ticket or from an
229 * Authenticator -- if the latter then we must refuse to find AD-KDC-ISSUED /
230 * PAC / CAMMAC or anything of the sort, ever.
233 find_type_in_ad(krb5_context context
,
235 krb5_data
*data
, /* optional */
237 krb5_boolean failp
, /* validate AD-KDC-ISSUED */
238 krb5_keyblock
*sessionkey
, /* ticket session key */
239 const AuthorizationData
*ad
,
242 krb5_error_code ret
= 0;
246 ret
= ENOENT
; /* XXX */
247 krb5_set_error_message(context
, ret
,
248 N_("Authorization data nested deeper "
249 "then %d levels, stop searching", ""),
255 * Only copy out the element the first time we get to it, we need
256 * to run over the whole authorization data fields to check if
257 * there are any container clases we need to care about.
259 for (i
= 0; i
< ad
->len
; i
++) {
260 if (!*found
&& ad
->val
[i
].ad_type
== type
) {
262 ret
= der_copy_octet_string(&ad
->val
[i
].ad_data
, data
);
264 krb5_set_error_message(context
, ret
,
265 N_("malloc: out of memory", ""));
270 if (type
!= KRB5_AUTHDATA_KDC_ISSUED
||
271 !failp
|| !sessionkey
|| !sessionkey
->keyvalue
.length
)
273 /* else go on to validate the AD-KDC-ISSUED's keyed checksum */
275 switch (ad
->val
[i
].ad_type
) {
276 case KRB5_AUTHDATA_IF_RELEVANT
: {
277 AuthorizationData child
;
278 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
279 ad
->val
[i
].ad_data
.length
,
283 krb5_set_error_message(context
, ret
,
284 N_("Failed to decode "
285 "IF_RELEVANT with %d", ""),
289 ret
= find_type_in_ad(context
, type
, data
, found
, FALSE
,
290 sessionkey
, &child
, level
+ 1);
291 free_AuthorizationData(&child
);
296 case KRB5_AUTHDATA_KDC_ISSUED
: {
299 ret
= decode_AD_KDCIssued(ad
->val
[i
].ad_data
.data
,
300 ad
->val
[i
].ad_data
.length
,
304 krb5_set_error_message(context
, ret
,
305 N_("Failed to decode "
306 "AD_KDCIssued with %d", ""),
310 if (failp
&& sessionkey
&& sessionkey
->keyvalue
.length
) {
315 ASN1_MALLOC_ENCODE(AuthorizationData
, buf
.data
, buf
.length
,
316 &child
.elements
, &len
, ret
);
318 free_AD_KDCIssued(&child
);
319 krb5_clear_error_message(context
);
322 if(buf
.length
!= len
)
323 krb5_abortx(context
, "internal error in ASN.1 encoder");
325 ret
= krb5_c_verify_checksum(context
, sessionkey
, 19, &buf
,
326 &child
.ad_checksum
, &valid
);
327 krb5_data_free(&buf
);
329 free_AD_KDCIssued(&child
);
333 krb5_clear_error_message(context
);
335 free_AD_KDCIssued(&child
);
339 krb5_clear_error_message(context
);
341 free_AD_KDCIssued(&child
);
344 ret
= find_type_in_ad(context
, type
, data
, found
, failp
, sessionkey
,
345 &child
.elements
, level
+ 1);
346 free_AD_KDCIssued(&child
);
351 case KRB5_AUTHDATA_AND_OR
:
354 ret
= ENOENT
; /* XXX */
355 krb5_set_error_message(context
, ret
,
356 N_("Authorization data contains "
357 "AND-OR element that is unknown to the "
363 ret
= ENOENT
; /* XXX */
364 krb5_set_error_message(context
, ret
,
365 N_("Authorization data contains "
366 "unknown type (%d) ", ""),
375 krb5_data_free(data
);
382 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
383 _krb5_get_ad(krb5_context context
,
384 const AuthorizationData
*ad
,
385 krb5_keyblock
*sessionkey
,
389 krb5_boolean found
= FALSE
;
393 krb5_data_zero(data
);
396 krb5_set_error_message(context
, ENOENT
,
397 N_("No authorization data", ""));
398 return ENOENT
; /* XXX */
401 ret
= find_type_in_ad(context
, type
, data
, &found
, TRUE
, sessionkey
, ad
, 0);
405 krb5_set_error_message(context
, ENOENT
,
406 N_("Have no authorization data of type %d", ""),
408 return ENOENT
; /* XXX */
415 * Extract the authorization data type of type from the ticket. Store
416 * the field in data. This function is to use for kerberos
419 * @param context a Kerberos 5 context
420 * @param ticket Kerberos ticket
421 * @param type type to fetch
422 * @param data returned data, free with krb5_data_free()
427 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
428 krb5_ticket_get_authorization_data_type(krb5_context context
,
433 AuthorizationData
*ad
;
435 krb5_boolean found
= FALSE
;
438 krb5_data_zero(data
);
440 ad
= ticket
->ticket
.authorization_data
;
441 if (ticket
->ticket
.authorization_data
== NULL
) {
442 krb5_set_error_message(context
, ENOENT
,
443 N_("Ticket has no authorization data", ""));
444 return ENOENT
; /* XXX */
447 ret
= find_type_in_ad(context
, type
, data
, &found
, TRUE
,
448 &ticket
->ticket
.key
, ad
, 0);
452 krb5_set_error_message(context
, ENOENT
,
454 "authorization data of type %d", ""),
456 return ENOENT
; /* XXX */
461 static krb5_error_code
462 check_server_referral(krb5_context context
,
465 krb5_const_principal requested
,
466 krb5_const_principal returned
,
470 PA_ServerReferralData ref
;
478 if (rep
->kdc_rep
.padata
== NULL
)
481 pa
= krb5_find_padata(rep
->kdc_rep
.padata
->val
,
482 rep
->kdc_rep
.padata
->len
,
483 KRB5_PADATA_SERVER_REFERRAL
, &i
);
487 memset(&ed
, 0, sizeof(ed
));
488 memset(&ref
, 0, sizeof(ref
));
490 ret
= decode_EncryptedData(pa
->padata_value
.data
,
491 pa
->padata_value
.length
,
495 if (len
!= pa
->padata_value
.length
) {
496 free_EncryptedData(&ed
);
497 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
498 N_("Referral EncryptedData wrong for realm %s",
499 "realm"), requested
->realm
);
500 return KRB5KRB_AP_ERR_MODIFIED
;
503 ret
= krb5_crypto_init(context
, key
, 0, &session
);
505 free_EncryptedData(&ed
);
509 ret
= krb5_decrypt_EncryptedData(context
, session
,
510 KRB5_KU_PA_SERVER_REFERRAL
,
512 free_EncryptedData(&ed
);
513 krb5_crypto_destroy(context
, session
);
517 ret
= decode_PA_ServerReferralData(data
.data
, data
.length
, &ref
, &len
);
519 krb5_data_free(&data
);
522 krb5_data_free(&data
);
524 if (strcmp(requested
->realm
, returned
->realm
) != 0) {
525 free_PA_ServerReferralData(&ref
);
526 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
527 N_("server ref realm mismatch, "
528 "requested realm %s got back %s", ""),
529 requested
->realm
, returned
->realm
);
530 return KRB5KRB_AP_ERR_MODIFIED
;
533 if (krb5_principal_is_krbtgt(context
, returned
)) {
534 const char *realm
= returned
->name
.name_string
.val
[1];
536 if (ref
.referred_realm
== NULL
537 || strcmp(*ref
.referred_realm
, realm
) != 0)
539 free_PA_ServerReferralData(&ref
);
540 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
541 N_("tgt returned with wrong ref", ""));
542 return KRB5KRB_AP_ERR_MODIFIED
;
544 } else if (krb5_principal_compare(context
, returned
, requested
) == 0) {
545 free_PA_ServerReferralData(&ref
);
546 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
547 N_("req princ no same as returned", ""));
548 return KRB5KRB_AP_ERR_MODIFIED
;
551 if (ref
.requested_principal_name
) {
552 cmp
= _krb5_principal_compare_PrincipalName(context
,
554 ref
.requested_principal_name
);
556 free_PA_ServerReferralData(&ref
);
557 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
558 N_("referred principal not same "
559 "as requested", ""));
560 return KRB5KRB_AP_ERR_MODIFIED
;
562 } else if (flags
& EXTRACT_TICKET_AS_REQ
) {
563 free_PA_ServerReferralData(&ref
);
564 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
565 N_("Requested principal missing on AS-REQ", ""));
566 return KRB5KRB_AP_ERR_MODIFIED
;
569 free_PA_ServerReferralData(&ref
);
574 * Expect excact match or that we got a krbtgt
576 if (krb5_principal_compare(context
, requested
, returned
) != TRUE
&&
577 (krb5_realm_compare(context
, requested
, returned
) != TRUE
&&
578 krb5_principal_is_krbtgt(context
, returned
) != TRUE
))
580 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
581 N_("Not same server principal returned "
582 "as requested", ""));
583 return KRB5KRB_AP_ERR_MODIFIED
;
589 * Verify KDC supported anonymous if requested
591 static krb5_error_code
592 check_client_anonymous(krb5_context context
,
594 krb5_const_principal requested
,
595 krb5_const_principal mapped
,
596 krb5_boolean is_tgs_rep
)
600 if (!rep
->enc_part
.flags
.anonymous
)
601 return KRB5KDC_ERR_BADOPTION
;
604 * Here we must validate that the AS returned a ticket of the expected type
605 * for either a fully anonymous request, or authenticated request for an
606 * anonymous ticket. If this is a TGS request, we're done. Then if the
607 * 'requested' principal was anonymous, we'll check the 'mapped' principal
608 * accordingly (without enforcing the name type and perhaps the realm).
609 * Finally, if the 'requested' principal was not anonymous, well check
610 * that the 'mapped' principal has an anonymous name and type, in a
611 * non-anonymous realm. (Should we also be checking for a realm match
612 * between the request and the mapped name in this case?)
615 flags
= KRB5_ANON_MATCH_ANY_NONT
;
616 else if (krb5_principal_is_anonymous(context
, requested
,
617 KRB5_ANON_MATCH_ANY_NONT
))
618 flags
= KRB5_ANON_MATCH_UNAUTHENTICATED
| KRB5_ANON_IGNORE_NAME_TYPE
;
620 flags
= KRB5_ANON_MATCH_AUTHENTICATED
;
622 if (!krb5_principal_is_anonymous(context
, mapped
, flags
))
623 return KRB5KRB_AP_ERR_MODIFIED
;
629 * Verify returned client principal name in anonymous/referral case
632 static krb5_error_code
633 check_client_mismatch(krb5_context context
,
635 krb5_const_principal requested
,
636 krb5_const_principal mapped
,
637 krb5_keyblock
const * key
)
639 if (rep
->enc_part
.flags
.anonymous
) {
640 if (!krb5_principal_is_anonymous(context
, mapped
,
641 KRB5_ANON_MATCH_ANY_NONT
)) {
642 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
643 N_("Anonymous ticket does not contain anonymous "
645 return KRB5KRB_AP_ERR_MODIFIED
;
648 if (krb5_principal_compare(context
, requested
, mapped
) == FALSE
&&
649 !rep
->enc_part
.flags
.enc_pa_rep
) {
650 krb5_set_error_message(context
, KRB5KRB_AP_ERR_MODIFIED
,
651 N_("Not same client principal returned "
652 "as requested", ""));
653 return KRB5KRB_AP_ERR_MODIFIED
;
661 static krb5_error_code KRB5_CALLCONV
662 decrypt_tkt (krb5_context context
,
664 krb5_key_usage usage
,
665 krb5_const_pointer decrypt_arg
,
666 krb5_kdc_rep
*dec_rep
)
673 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
677 ret
= krb5_decrypt_EncryptedData (context
,
680 &dec_rep
->kdc_rep
.enc_part
,
682 krb5_crypto_destroy(context
, crypto
);
687 ret
= decode_EncASRepPart(data
.data
,
692 ret
= decode_EncTGSRepPart(data
.data
,
696 krb5_data_free (&data
);
698 krb5_set_error_message(context
, ret
,
699 N_("Failed to decode encpart in ticket", ""));
705 KRB5_LIB_FUNCTION
int KRB5_LIB_CALL
706 _krb5_extract_ticket(krb5_context context
,
710 krb5_const_pointer keyseed
,
711 krb5_key_usage key_usage
,
712 krb5_addresses
*addrs
,
716 krb5_decrypt_proc decrypt_proc
,
717 krb5_const_pointer decryptarg
)
720 krb5_principal tmp_principal
;
723 krb5_timestamp sec_now
;
727 if (decrypt_proc
== NULL
)
728 decrypt_proc
= decrypt_tkt
;
730 ret
= (*decrypt_proc
)(context
, key
, key_usage
, decryptarg
, rep
);
734 if (rep
->enc_part
.flags
.enc_pa_rep
&& request
) {
735 krb5_crypto crypto
= NULL
;
740 _krb5_debug(context
, 5, "processing enc-ap-rep");
742 if (rep
->enc_part
.encrypted_pa_data
== NULL
||
743 (pa
= krb5_find_padata(rep
->enc_part
.encrypted_pa_data
->val
,
744 rep
->enc_part
.encrypted_pa_data
->len
,
745 KRB5_PADATA_REQ_ENC_PA_REP
,
748 _krb5_debug(context
, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
749 ret
= KRB5KRB_AP_ERR_MODIFIED
;
753 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
757 ret
= decode_Checksum(pa
->padata_value
.data
,
758 pa
->padata_value
.length
,
761 krb5_crypto_destroy(context
, crypto
);
765 ret
= krb5_verify_checksum(context
, crypto
,
767 request
->data
, request
->length
,
769 krb5_crypto_destroy(context
, crypto
);
770 free_Checksum(&cksum
);
771 _krb5_debug(context
, 5, "enc-ap-rep: %svalid", (ret
== 0) ? "" : "in");
776 /* save session key */
778 creds
->session
.keyvalue
.length
= 0;
779 creds
->session
.keyvalue
.data
= NULL
;
780 creds
->session
.keytype
= rep
->enc_part
.key
.keytype
;
781 ret
= krb5_data_copy (&creds
->session
.keyvalue
,
782 rep
->enc_part
.key
.keyvalue
.data
,
783 rep
->enc_part
.key
.keyvalue
.length
);
785 krb5_clear_error_message(context
);
789 /* compare client and save */
790 ret
= _krb5_principalname2krb5_principal(context
,
793 rep
->kdc_rep
.crealm
);
797 /* check KDC supported anonymous if it was requested */
798 if (flags
& EXTRACT_TICKET_MATCH_ANON
) {
799 ret
= check_client_anonymous(context
,rep
,
802 request
== NULL
); /* is TGS */
804 krb5_free_principal(context
, tmp_principal
);
809 /* check client referral and save principal */
810 if((flags
& EXTRACT_TICKET_ALLOW_CNAME_MISMATCH
) == 0) {
811 ret
= check_client_mismatch(context
, rep
,
816 krb5_free_principal (context
, tmp_principal
);
820 krb5_free_principal (context
, creds
->client
);
821 creds
->client
= tmp_principal
;
823 /* check server referral and save principal */
824 ret
= _krb5_kdcrep2krb5_principal(context
, &tmp_principal
, &rep
->enc_part
);
828 tmp_principal
->nameattrs
->peer_realm
=
829 calloc(1, sizeof(tmp_principal
->nameattrs
->peer_realm
[0]));
830 if (tmp_principal
->nameattrs
->peer_realm
== NULL
) {
831 ret
= krb5_enomem(context
);
834 ret
= copy_Realm(&creds
->client
->realm
, tmp_principal
->nameattrs
->peer_realm
);
837 if((flags
& EXTRACT_TICKET_ALLOW_SERVER_MISMATCH
) == 0){
838 ret
= check_server_referral(context
,
845 krb5_free_principal (context
, tmp_principal
);
849 krb5_free_principal(context
, creds
->server
);
850 creds
->server
= tmp_principal
;
853 if(flags
& EXTRACT_TICKET_MATCH_REALM
){
854 const char *srealm
= krb5_principal_get_realm(context
, creds
->server
);
855 const char *crealm
= krb5_principal_get_realm(context
, creds
->client
);
857 if (strcmp(rep
->enc_part
.srealm
, srealm
) != 0 ||
858 strcmp(rep
->enc_part
.srealm
, crealm
) != 0)
860 ret
= KRB5KRB_AP_ERR_MODIFIED
;
861 krb5_clear_error_message(context
);
868 if (nonce
!= (unsigned)rep
->enc_part
.nonce
) {
869 ret
= KRB5KRB_AP_ERR_MODIFIED
;
870 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
876 krb5_timeofday (context
, &sec_now
);
877 if (rep
->enc_part
.flags
.initial
878 && (flags
& EXTRACT_TICKET_TIMESYNC
)
879 && context
->kdc_sec_offset
== 0
880 && krb5_config_get_bool (context
, NULL
,
884 context
->kdc_sec_offset
= rep
->enc_part
.authtime
- sec_now
;
885 krb5_timeofday (context
, &sec_now
);
888 /* check all times */
890 if (rep
->enc_part
.starttime
) {
891 tmp_time
= *rep
->enc_part
.starttime
;
893 tmp_time
= rep
->enc_part
.authtime
;
895 if (creds
->times
.starttime
== 0
896 && krb5_time_abs(tmp_time
, sec_now
) > context
->max_skew
) {
897 ret
= KRB5KRB_AP_ERR_SKEW
;
898 krb5_set_error_message (context
, ret
,
899 N_("time skew (%ld) larger than max (%ld)", ""),
900 (long)krb5_time_abs(tmp_time
, sec_now
),
901 (long)context
->max_skew
);
905 if (creds
->times
.starttime
!= 0
906 && tmp_time
!= creds
->times
.starttime
) {
907 krb5_clear_error_message (context
);
908 ret
= KRB5KRB_AP_ERR_MODIFIED
;
912 creds
->times
.starttime
= tmp_time
;
914 if (rep
->enc_part
.renew_till
) {
915 tmp_time
= *rep
->enc_part
.renew_till
;
919 if (creds
->times
.renew_till
!= 0
920 && tmp_time
> creds
->times
.renew_till
) {
921 krb5_clear_error_message (context
);
922 ret
= KRB5KRB_AP_ERR_MODIFIED
;
926 creds
->times
.renew_till
= tmp_time
;
928 creds
->times
.authtime
= rep
->enc_part
.authtime
;
930 if (creds
->times
.endtime
!= 0
931 && rep
->enc_part
.endtime
> creds
->times
.endtime
) {
932 krb5_clear_error_message (context
);
933 ret
= KRB5KRB_AP_ERR_MODIFIED
;
937 creds
->times
.endtime
= rep
->enc_part
.endtime
;
939 if(rep
->enc_part
.caddr
)
940 krb5_copy_addresses (context
, rep
->enc_part
.caddr
, &creds
->addresses
);
942 krb5_copy_addresses (context
, addrs
, &creds
->addresses
);
944 creds
->addresses
.len
= 0;
945 creds
->addresses
.val
= NULL
;
947 creds
->flags
.b
= rep
->enc_part
.flags
;
949 creds
->authdata
.len
= 0;
950 creds
->authdata
.val
= NULL
;
953 ASN1_MALLOC_ENCODE(Ticket
, creds
->ticket
.data
, creds
->ticket
.length
,
954 &rep
->kdc_rep
.ticket
, &len
, ret
);
957 if (creds
->ticket
.length
!= len
)
958 krb5_abortx(context
, "internal error in ASN.1 encoder");
959 creds
->second_ticket
.length
= 0;
960 creds
->second_ticket
.data
= NULL
;
964 memset (rep
->enc_part
.key
.keyvalue
.data
, 0,
965 rep
->enc_part
.key
.keyvalue
.length
);