s4:torture: Adapt KDC canon test to Heimdal upstream changes
[Samba.git] / source4 / heimdal / lib / krb5 / ticket.c
blob11e4e84963b2d48835ded9a55b00dcb8e820b80a
1 /*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
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
10 * are met:
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
33 * SUCH DAMAGE.
36 #include "krb5_locl.h"
38 /**
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().
47 * @ingroup krb5
50 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
51 krb5_free_ticket(krb5_context context,
52 krb5_ticket *ticket)
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;
61 /**
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().
71 * @ingroup krb5
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)
79 krb5_error_code ret;
80 krb5_ticket *tmp;
82 *to = NULL;
83 tmp = malloc(sizeof(*tmp));
84 if (tmp == NULL)
85 return krb5_enomem(context);
86 if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){
87 free(tmp);
88 return ret;
90 ret = krb5_copy_principal(context, from->client, &tmp->client);
91 if(ret){
92 free_EncTicketPart(&tmp->ticket);
93 free(tmp);
94 return ret;
96 ret = krb5_copy_principal(context, from->server, &tmp->server);
97 if(ret){
98 krb5_free_principal(context, tmp->client);
99 free_EncTicketPart(&tmp->ticket);
100 free(tmp);
101 return ret;
103 *to = tmp;
104 return 0;
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().
117 * @ingroup krb5
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().
138 * @ingroup krb5
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
157 * @ingroup krb5
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
174 * @ingroup krb5
177 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
178 krb5_ticket_get_times(krb5_context context,
179 const krb5_ticket *ticket,
180 krb5_times *t)
182 t->authtime = ticket->ticket.authtime;
183 t->starttime = ticket->ticket.starttime ? *ticket->ticket.starttime :
184 t->authtime;
185 t->endtime = ticket->ticket.endtime;
186 t->renew_till = ticket->ticket.renew_till ? *ticket->ticket.renew_till :
187 t->endtime;
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);
207 static int
208 find_type_in_ad(krb5_context context,
209 int type,
210 krb5_data *data,
211 krb5_boolean *found,
212 krb5_boolean failp,
213 krb5_keyblock *sessionkey,
214 const AuthorizationData *ad,
215 int level)
217 krb5_error_code ret = 0;
218 size_t i;
220 if (level > 9) {
221 ret = ENOENT; /* XXX */
222 krb5_set_error_message(context, ret,
223 N_("Authorization data nested deeper "
224 "then %d levels, stop searching", ""),
225 level);
226 goto out;
230 * Only copy out the element the first time we get to it, we need
231 * to run over the whole authorization data fields to check if
232 * there are any container clases we need to care about.
234 for (i = 0; i < ad->len; i++) {
235 if (!*found && ad->val[i].ad_type == type) {
236 ret = der_copy_octet_string(&ad->val[i].ad_data, data);
237 if (ret) {
238 krb5_set_error_message(context, ret,
239 N_("malloc: out of memory", ""));
240 goto out;
242 *found = TRUE;
243 continue;
245 switch (ad->val[i].ad_type) {
246 case KRB5_AUTHDATA_IF_RELEVANT: {
247 AuthorizationData child;
248 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
249 ad->val[i].ad_data.length,
250 &child,
251 NULL);
252 if (ret) {
253 krb5_set_error_message(context, ret,
254 N_("Failed to decode "
255 "IF_RELEVANT with %d", ""),
256 (int)ret);
257 goto out;
259 ret = find_type_in_ad(context, type, data, found, FALSE,
260 sessionkey, &child, level + 1);
261 free_AuthorizationData(&child);
262 if (ret)
263 goto out;
264 break;
266 #if 0 /* XXX test */
267 case KRB5_AUTHDATA_KDC_ISSUED: {
268 AD_KDCIssued child;
270 ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
271 ad->val[i].ad_data.length,
272 &child,
273 NULL);
274 if (ret) {
275 krb5_set_error_message(context, ret,
276 N_("Failed to decode "
277 "AD_KDCIssued with %d", ""),
278 ret);
279 goto out;
281 if (failp) {
282 krb5_boolean valid;
283 krb5_data buf;
284 size_t len;
286 ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
287 &child.elements, &len, ret);
288 if (ret) {
289 free_AD_KDCIssued(&child);
290 krb5_clear_error_message(context);
291 goto out;
293 if(buf.length != len)
294 krb5_abortx(context, "internal error in ASN.1 encoder");
296 ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
297 &child.ad_checksum, &valid);
298 krb5_data_free(&buf);
299 if (ret) {
300 free_AD_KDCIssued(&child);
301 goto out;
303 if (!valid) {
304 krb5_clear_error_message(context);
305 ret = ENOENT;
306 free_AD_KDCIssued(&child);
307 goto out;
310 ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
311 &child.elements, level + 1);
312 free_AD_KDCIssued(&child);
313 if (ret)
314 goto out;
315 break;
317 #endif
318 case KRB5_AUTHDATA_AND_OR:
319 if (!failp)
320 break;
321 ret = ENOENT; /* XXX */
322 krb5_set_error_message(context, ret,
323 N_("Authorization data contains "
324 "AND-OR element that is unknown to the "
325 "application", ""));
326 goto out;
327 default:
328 if (!failp)
329 break;
330 ret = ENOENT; /* XXX */
331 krb5_set_error_message(context, ret,
332 N_("Authorization data contains "
333 "unknown type (%d) ", ""),
334 ad->val[i].ad_type);
335 goto out;
338 out:
339 if (ret) {
340 if (*found) {
341 krb5_data_free(data);
342 *found = 0;
345 return ret;
348 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
349 _krb5_get_ad(krb5_context context,
350 const AuthorizationData *ad,
351 krb5_keyblock *sessionkey,
352 int type,
353 krb5_data *data)
355 krb5_boolean found = FALSE;
356 krb5_error_code ret;
358 krb5_data_zero(data);
360 if (ad == NULL) {
361 krb5_set_error_message(context, ENOENT,
362 N_("No authorization data", ""));
363 return ENOENT; /* XXX */
366 ret = find_type_in_ad(context, type, data, &found, TRUE, sessionkey, ad, 0);
367 if (ret)
368 return ret;
369 if (!found) {
370 krb5_set_error_message(context, ENOENT,
371 N_("Have no authorization data of type %d", ""),
372 type);
373 return ENOENT; /* XXX */
375 return 0;
380 * Extract the authorization data type of type from the ticket. Store
381 * the field in data. This function is to use for kerberos
382 * applications.
384 * @param context a Kerberos 5 context
385 * @param ticket Kerberos ticket
386 * @param type type to fetch
387 * @param data returned data, free with krb5_data_free()
389 * @ingroup krb5
392 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
393 krb5_ticket_get_authorization_data_type(krb5_context context,
394 krb5_ticket *ticket,
395 int type,
396 krb5_data *data)
398 AuthorizationData *ad;
399 krb5_error_code ret;
400 krb5_boolean found = FALSE;
402 krb5_data_zero(data);
404 ad = ticket->ticket.authorization_data;
405 if (ticket->ticket.authorization_data == NULL) {
406 krb5_set_error_message(context, ENOENT,
407 N_("Ticket has no authorization data", ""));
408 return ENOENT; /* XXX */
411 ret = find_type_in_ad(context, type, data, &found, TRUE,
412 &ticket->ticket.key, ad, 0);
413 if (ret)
414 return ret;
415 if (!found) {
416 krb5_set_error_message(context, ENOENT,
417 N_("Ticket has no "
418 "authorization data of type %d", ""),
419 type);
420 return ENOENT; /* XXX */
422 return 0;
425 static krb5_error_code
426 check_server_referral(krb5_context context,
427 krb5_kdc_rep *rep,
428 unsigned flags,
429 krb5_const_principal requested,
430 krb5_const_principal returned,
431 krb5_keyblock * key)
433 krb5_error_code ret;
434 PA_ServerReferralData ref;
435 krb5_crypto session;
436 EncryptedData ed;
437 size_t len;
438 krb5_data data;
439 PA_DATA *pa;
440 int i = 0, cmp;
442 if (rep->kdc_rep.padata == NULL)
443 goto noreferral;
445 pa = krb5_find_padata(rep->kdc_rep.padata->val,
446 rep->kdc_rep.padata->len,
447 KRB5_PADATA_SERVER_REFERRAL, &i);
448 if (pa == NULL)
449 goto noreferral;
451 memset(&ed, 0, sizeof(ed));
452 memset(&ref, 0, sizeof(ref));
454 ret = decode_EncryptedData(pa->padata_value.data,
455 pa->padata_value.length,
456 &ed, &len);
457 if (ret)
458 return ret;
459 if (len != pa->padata_value.length) {
460 free_EncryptedData(&ed);
461 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
462 N_("Referral EncryptedData wrong for realm %s",
463 "realm"), requested->realm);
464 return KRB5KRB_AP_ERR_MODIFIED;
467 ret = krb5_crypto_init(context, key, 0, &session);
468 if (ret) {
469 free_EncryptedData(&ed);
470 return ret;
473 ret = krb5_decrypt_EncryptedData(context, session,
474 KRB5_KU_PA_SERVER_REFERRAL,
475 &ed, &data);
476 free_EncryptedData(&ed);
477 krb5_crypto_destroy(context, session);
478 if (ret)
479 return ret;
481 ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
482 if (ret) {
483 krb5_data_free(&data);
484 return ret;
486 krb5_data_free(&data);
488 if (strcmp(requested->realm, returned->realm) != 0) {
489 free_PA_ServerReferralData(&ref);
490 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
491 N_("server ref realm mismatch, "
492 "requested realm %s got back %s", ""),
493 requested->realm, returned->realm);
494 return KRB5KRB_AP_ERR_MODIFIED;
497 if (krb5_principal_is_krbtgt(context, returned)) {
498 const char *realm = returned->name.name_string.val[1];
500 if (ref.referred_realm == NULL
501 || strcmp(*ref.referred_realm, realm) != 0)
503 free_PA_ServerReferralData(&ref);
504 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
505 N_("tgt returned with wrong ref", ""));
506 return KRB5KRB_AP_ERR_MODIFIED;
508 } else if (krb5_principal_compare(context, returned, requested) == 0) {
509 free_PA_ServerReferralData(&ref);
510 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
511 N_("req princ no same as returned", ""));
512 return KRB5KRB_AP_ERR_MODIFIED;
515 if (ref.requested_principal_name) {
516 cmp = _krb5_principal_compare_PrincipalName(context,
517 requested,
518 ref.requested_principal_name);
519 if (!cmp) {
520 free_PA_ServerReferralData(&ref);
521 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
522 N_("referred principal not same "
523 "as requested", ""));
524 return KRB5KRB_AP_ERR_MODIFIED;
526 } else if (flags & EXTRACT_TICKET_AS_REQ) {
527 free_PA_ServerReferralData(&ref);
528 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
529 N_("Requested principal missing on AS-REQ", ""));
530 return KRB5KRB_AP_ERR_MODIFIED;
533 free_PA_ServerReferralData(&ref);
535 return ret;
536 noreferral:
538 * Expect excact match or that we got a krbtgt
540 if (krb5_principal_compare(context, requested, returned) != TRUE &&
541 (krb5_realm_compare(context, requested, returned) != TRUE &&
542 krb5_principal_is_krbtgt(context, returned) != TRUE))
544 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
545 N_("Not same server principal returned "
546 "as requested", ""));
547 return KRB5KRB_AP_ERR_MODIFIED;
549 return 0;
553 * Verify KDC supported anonymous if requested
555 static krb5_error_code
556 check_client_anonymous(krb5_context context,
557 krb5_kdc_rep *rep,
558 krb5_const_principal requested,
559 krb5_const_principal mapped,
560 krb5_boolean is_tgs_rep)
562 int flags;
564 if (!rep->enc_part.flags.anonymous)
565 return KRB5KDC_ERR_BADOPTION;
568 * Here we must validate that the AS returned a ticket of the expected type
569 * for either a fully anonymous request, or authenticated request for an
570 * anonymous ticket. If this is a TGS request, we're done. Then if the
571 * 'requested' principal was anonymous, we'll check the 'mapped' principal
572 * accordingly (without enforcing the name type and perhaps the realm).
573 * Finally, if the 'requested' principal was not anonymous, well check
574 * that the 'mapped' principal has an anonymous name and type, in a
575 * non-anonymous realm. (Should we also be checking for a realm match
576 * between the request and the mapped name in this case?)
578 if (is_tgs_rep)
579 flags = KRB5_ANON_MATCH_ANY_NONT;
580 else if (krb5_principal_is_anonymous(context, requested,
581 KRB5_ANON_MATCH_ANY_NONT))
582 flags = KRB5_ANON_MATCH_UNAUTHENTICATED | KRB5_ANON_IGNORE_NAME_TYPE;
583 else
584 flags = KRB5_ANON_MATCH_AUTHENTICATED;
586 if (!krb5_principal_is_anonymous(context, mapped, flags))
587 return KRB5KRB_AP_ERR_MODIFIED;
589 return 0;
593 * Verify returned client principal name in anonymous/referral case
596 static krb5_error_code
597 check_client_mismatch(krb5_context context,
598 krb5_kdc_rep *rep,
599 krb5_const_principal requested,
600 krb5_const_principal mapped,
601 krb5_keyblock const * key)
603 if (rep->enc_part.flags.anonymous) {
604 if (!krb5_principal_is_anonymous(context, mapped,
605 KRB5_ANON_MATCH_ANY_NONT)) {
606 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
607 N_("Anonymous ticket does not contain anonymous "
608 "principal", ""));
609 return KRB5KRB_AP_ERR_MODIFIED;
611 } else {
612 if (krb5_principal_compare(context, requested, mapped) == FALSE &&
613 !rep->enc_part.flags.enc_pa_rep) {
614 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
615 N_("Not same client principal returned "
616 "as requested", ""));
617 return KRB5KRB_AP_ERR_MODIFIED;
621 return 0;
625 static krb5_error_code KRB5_CALLCONV
626 decrypt_tkt (krb5_context context,
627 krb5_keyblock *key,
628 krb5_key_usage usage,
629 krb5_const_pointer decrypt_arg,
630 krb5_kdc_rep *dec_rep)
632 krb5_error_code ret;
633 krb5_data data;
634 size_t size;
635 krb5_crypto crypto;
637 ret = krb5_crypto_init(context, key, 0, &crypto);
638 if (ret)
639 return ret;
641 ret = krb5_decrypt_EncryptedData (context,
642 crypto,
643 usage,
644 &dec_rep->kdc_rep.enc_part,
645 &data);
646 krb5_crypto_destroy(context, crypto);
648 if (ret)
649 return ret;
651 ret = decode_EncASRepPart(data.data,
652 data.length,
653 &dec_rep->enc_part,
654 &size);
655 if (ret)
656 ret = decode_EncTGSRepPart(data.data,
657 data.length,
658 &dec_rep->enc_part,
659 &size);
660 krb5_data_free (&data);
661 if (ret) {
662 krb5_set_error_message(context, ret,
663 N_("Failed to decode encpart in ticket", ""));
664 return ret;
666 return 0;
669 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
670 _krb5_extract_ticket(krb5_context context,
671 krb5_kdc_rep *rep,
672 krb5_creds *creds,
673 krb5_keyblock *key,
674 krb5_const_pointer keyseed,
675 krb5_key_usage key_usage,
676 krb5_addresses *addrs,
677 unsigned nonce,
678 unsigned flags,
679 krb5_data *request,
680 krb5_decrypt_proc decrypt_proc,
681 krb5_const_pointer decryptarg)
683 krb5_error_code ret;
684 krb5_principal tmp_principal;
685 size_t len = 0;
686 time_t tmp_time;
687 krb5_timestamp sec_now;
689 /* decrypt */
691 if (decrypt_proc == NULL)
692 decrypt_proc = decrypt_tkt;
694 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
695 if (ret)
696 goto out;
698 if (rep->enc_part.flags.enc_pa_rep && request) {
699 krb5_crypto crypto = NULL;
700 Checksum cksum;
701 PA_DATA *pa = NULL;
702 int idx = 0;
704 _krb5_debug(context, 5, "processing enc-ap-rep");
706 if (rep->enc_part.encrypted_pa_data == NULL ||
707 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val,
708 rep->enc_part.encrypted_pa_data->len,
709 KRB5_PADATA_REQ_ENC_PA_REP,
710 &idx)) == NULL)
712 _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
713 ret = KRB5KRB_AP_ERR_MODIFIED;
714 goto out;
717 ret = krb5_crypto_init(context, key, 0, &crypto);
718 if (ret)
719 goto out;
721 ret = decode_Checksum(pa->padata_value.data,
722 pa->padata_value.length,
723 &cksum, NULL);
724 if (ret) {
725 krb5_crypto_destroy(context, crypto);
726 goto out;
729 ret = krb5_verify_checksum(context, crypto,
730 KRB5_KU_AS_REQ,
731 request->data, request->length,
732 &cksum);
733 krb5_crypto_destroy(context, crypto);
734 free_Checksum(&cksum);
735 _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in");
736 if (ret)
737 goto out;
740 /* save session key */
742 creds->session.keyvalue.length = 0;
743 creds->session.keyvalue.data = NULL;
744 creds->session.keytype = rep->enc_part.key.keytype;
745 ret = krb5_data_copy (&creds->session.keyvalue,
746 rep->enc_part.key.keyvalue.data,
747 rep->enc_part.key.keyvalue.length);
748 if (ret) {
749 krb5_clear_error_message(context);
750 goto out;
753 /* compare client and save */
754 ret = _krb5_principalname2krb5_principal(context,
755 &tmp_principal,
756 rep->kdc_rep.cname,
757 rep->kdc_rep.crealm);
758 if (ret)
759 goto out;
761 /* check KDC supported anonymous if it was requested */
762 if (flags & EXTRACT_TICKET_MATCH_ANON) {
763 ret = check_client_anonymous(context,rep,
764 creds->client,
765 tmp_principal,
766 request == NULL); /* is TGS */
767 if (ret) {
768 krb5_free_principal(context, tmp_principal);
769 goto out;
773 /* check client referral and save principal */
774 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
775 ret = check_client_mismatch(context, rep,
776 creds->client,
777 tmp_principal,
778 &creds->session);
779 if (ret) {
780 krb5_free_principal (context, tmp_principal);
781 goto out;
784 krb5_free_principal (context, creds->client);
785 creds->client = tmp_principal;
787 /* check server referral and save principal */
788 ret = _krb5_principalname2krb5_principal (context,
789 &tmp_principal,
790 rep->enc_part.sname,
791 rep->enc_part.srealm);
792 if (ret)
793 goto out;
794 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
795 ret = check_server_referral(context,
796 rep,
797 flags,
798 creds->server,
799 tmp_principal,
800 &creds->session);
801 if (ret) {
802 krb5_free_principal (context, tmp_principal);
803 goto out;
806 krb5_free_principal(context, creds->server);
807 creds->server = tmp_principal;
809 /* verify names */
810 if(flags & EXTRACT_TICKET_MATCH_REALM){
811 const char *srealm = krb5_principal_get_realm(context, creds->server);
812 const char *crealm = krb5_principal_get_realm(context, creds->client);
814 if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
815 strcmp(rep->enc_part.srealm, crealm) != 0)
817 ret = KRB5KRB_AP_ERR_MODIFIED;
818 krb5_clear_error_message(context);
819 goto out;
823 /* compare nonces */
825 if (nonce != (unsigned)rep->enc_part.nonce) {
826 ret = KRB5KRB_AP_ERR_MODIFIED;
827 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
828 goto out;
831 /* set kdc-offset */
833 krb5_timeofday (context, &sec_now);
834 if (rep->enc_part.flags.initial
835 && (flags & EXTRACT_TICKET_TIMESYNC)
836 && context->kdc_sec_offset == 0
837 && krb5_config_get_bool (context, NULL,
838 "libdefaults",
839 "kdc_timesync",
840 NULL)) {
841 context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
842 krb5_timeofday (context, &sec_now);
845 /* check all times */
847 if (rep->enc_part.starttime) {
848 tmp_time = *rep->enc_part.starttime;
849 } else
850 tmp_time = rep->enc_part.authtime;
852 if (creds->times.starttime == 0
853 && krb5_time_abs(tmp_time, sec_now) > context->max_skew) {
854 ret = KRB5KRB_AP_ERR_SKEW;
855 krb5_set_error_message (context, ret,
856 N_("time skew (%ld) larger than max (%ld)", ""),
857 krb5_time_abs(tmp_time, sec_now),
858 (long)context->max_skew);
859 goto out;
862 if (creds->times.starttime != 0
863 && tmp_time != creds->times.starttime) {
864 krb5_clear_error_message (context);
865 ret = KRB5KRB_AP_ERR_MODIFIED;
866 goto out;
869 creds->times.starttime = tmp_time;
871 if (rep->enc_part.renew_till) {
872 tmp_time = *rep->enc_part.renew_till;
873 } else
874 tmp_time = 0;
876 if (creds->times.renew_till != 0
877 && tmp_time > creds->times.renew_till) {
878 krb5_clear_error_message (context);
879 ret = KRB5KRB_AP_ERR_MODIFIED;
880 goto out;
883 creds->times.renew_till = tmp_time;
885 creds->times.authtime = rep->enc_part.authtime;
887 if (creds->times.endtime != 0
888 && rep->enc_part.endtime > creds->times.endtime) {
889 krb5_clear_error_message (context);
890 ret = KRB5KRB_AP_ERR_MODIFIED;
891 goto out;
894 creds->times.endtime = rep->enc_part.endtime;
896 if(rep->enc_part.caddr)
897 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
898 else if(addrs)
899 krb5_copy_addresses (context, addrs, &creds->addresses);
900 else {
901 creds->addresses.len = 0;
902 creds->addresses.val = NULL;
904 creds->flags.b = rep->enc_part.flags;
906 creds->authdata.len = 0;
907 creds->authdata.val = NULL;
909 /* extract ticket */
910 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
911 &rep->kdc_rep.ticket, &len, ret);
912 if(ret)
913 goto out;
914 if (creds->ticket.length != len)
915 krb5_abortx(context, "internal error in ASN.1 encoder");
916 creds->second_ticket.length = 0;
917 creds->second_ticket.data = NULL;
920 out:
921 memset (rep->enc_part.key.keyvalue.data, 0,
922 rep->enc_part.key.keyvalue.length);
923 return ret;