Properly terminate ifdef conditional in krb5-types.h
[heimdal.git] / lib / krb5 / ticket.c
blob0b63ee026db74e43e32ce54e380510a24e5fb6d0
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 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 * Get the flags from the Kerberos ticket
170 * @param context Kerberos context
171 * @param ticket Kerberos ticket
173 * @return ticket flags
175 * @ingroup krb5_ticket
177 KRB5_LIB_FUNCTION unsigned long KRB5_LIB_CALL
178 krb5_ticket_get_flags(krb5_context context,
179 const krb5_ticket *ticket)
181 return TicketFlags2int(ticket->ticket.flags);
184 static int
185 find_type_in_ad(krb5_context context,
186 int type,
187 krb5_data *data,
188 krb5_boolean *found,
189 krb5_boolean failp,
190 krb5_keyblock *sessionkey,
191 const AuthorizationData *ad,
192 int level)
194 krb5_error_code ret = 0;
195 size_t i;
197 if (level > 9) {
198 ret = ENOENT; /* XXX */
199 krb5_set_error_message(context, ret,
200 N_("Authorization data nested deeper "
201 "then %d levels, stop searching", ""),
202 level);
203 goto out;
207 * Only copy out the element the first time we get to it, we need
208 * to run over the whole authorization data fields to check if
209 * there are any container clases we need to care about.
211 for (i = 0; i < ad->len; i++) {
212 if (!*found && ad->val[i].ad_type == type) {
213 ret = der_copy_octet_string(&ad->val[i].ad_data, data);
214 if (ret) {
215 krb5_set_error_message(context, ret,
216 N_("malloc: out of memory", ""));
217 goto out;
219 *found = TRUE;
220 continue;
222 switch (ad->val[i].ad_type) {
223 case KRB5_AUTHDATA_IF_RELEVANT: {
224 AuthorizationData child;
225 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
226 ad->val[i].ad_data.length,
227 &child,
228 NULL);
229 if (ret) {
230 krb5_set_error_message(context, ret,
231 N_("Failed to decode "
232 "IF_RELEVANT with %d", ""),
233 (int)ret);
234 goto out;
236 ret = find_type_in_ad(context, type, data, found, FALSE,
237 sessionkey, &child, level + 1);
238 free_AuthorizationData(&child);
239 if (ret)
240 goto out;
241 break;
243 #if 0 /* XXX test */
244 case KRB5_AUTHDATA_KDC_ISSUED: {
245 AD_KDCIssued child;
247 ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
248 ad->val[i].ad_data.length,
249 &child,
250 NULL);
251 if (ret) {
252 krb5_set_error_message(context, ret,
253 N_("Failed to decode "
254 "AD_KDCIssued with %d", ""),
255 ret);
256 goto out;
258 if (failp) {
259 krb5_boolean valid;
260 krb5_data buf;
261 size_t len;
263 ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
264 &child.elements, &len, ret);
265 if (ret) {
266 free_AD_KDCIssued(&child);
267 krb5_clear_error_message(context);
268 goto out;
270 if(buf.length != len)
271 krb5_abortx(context, "internal error in ASN.1 encoder");
273 ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
274 &child.ad_checksum, &valid);
275 krb5_data_free(&buf);
276 if (ret) {
277 free_AD_KDCIssued(&child);
278 goto out;
280 if (!valid) {
281 krb5_clear_error_message(context);
282 ret = ENOENT;
283 free_AD_KDCIssued(&child);
284 goto out;
287 ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
288 &child.elements, level + 1);
289 free_AD_KDCIssued(&child);
290 if (ret)
291 goto out;
292 break;
294 #endif
295 case KRB5_AUTHDATA_AND_OR:
296 if (!failp)
297 break;
298 ret = ENOENT; /* XXX */
299 krb5_set_error_message(context, ret,
300 N_("Authorization data contains "
301 "AND-OR element that is unknown to the "
302 "application", ""));
303 goto out;
304 default:
305 if (!failp)
306 break;
307 ret = ENOENT; /* XXX */
308 krb5_set_error_message(context, ret,
309 N_("Authorization data contains "
310 "unknown type (%d) ", ""),
311 ad->val[i].ad_type);
312 goto out;
315 out:
316 if (ret) {
317 if (*found) {
318 krb5_data_free(data);
319 *found = 0;
322 return ret;
325 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
326 _krb5_get_ad(krb5_context context,
327 const AuthorizationData *ad,
328 krb5_keyblock *sessionkey,
329 int type,
330 krb5_data *data)
332 krb5_boolean found = FALSE;
333 krb5_error_code ret;
335 krb5_data_zero(data);
337 if (ad == NULL) {
338 krb5_set_error_message(context, ENOENT,
339 N_("No authorization data", ""));
340 return ENOENT; /* XXX */
343 ret = find_type_in_ad(context, type, data, &found, TRUE, sessionkey, ad, 0);
344 if (ret)
345 return ret;
346 if (!found) {
347 krb5_set_error_message(context, ENOENT,
348 N_("Have no authorization data of type %d", ""),
349 type);
350 return ENOENT; /* XXX */
352 return 0;
357 * Extract the authorization data type of type from the ticket. Store
358 * the field in data. This function is to use for kerberos
359 * applications.
361 * @param context a Kerberos 5 context
362 * @param ticket Kerberos ticket
363 * @param type type to fetch
364 * @param data returned data, free with krb5_data_free()
366 * @ingroup krb5
369 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
370 krb5_ticket_get_authorization_data_type(krb5_context context,
371 krb5_ticket *ticket,
372 int type,
373 krb5_data *data)
375 AuthorizationData *ad;
376 krb5_error_code ret;
377 krb5_boolean found = FALSE;
379 krb5_data_zero(data);
381 ad = ticket->ticket.authorization_data;
382 if (ticket->ticket.authorization_data == NULL) {
383 krb5_set_error_message(context, ENOENT,
384 N_("Ticket have not authorization data", ""));
385 return ENOENT; /* XXX */
388 ret = find_type_in_ad(context, type, data, &found, TRUE,
389 &ticket->ticket.key, ad, 0);
390 if (ret)
391 return ret;
392 if (!found) {
393 krb5_set_error_message(context, ENOENT,
394 N_("Ticket have not "
395 "authorization data of type %d", ""),
396 type);
397 return ENOENT; /* XXX */
399 return 0;
402 static krb5_error_code
403 check_server_referral(krb5_context context,
404 krb5_kdc_rep *rep,
405 unsigned flags,
406 krb5_const_principal requested,
407 krb5_const_principal returned,
408 krb5_keyblock * key)
410 krb5_error_code ret;
411 PA_ServerReferralData ref;
412 krb5_crypto session;
413 EncryptedData ed;
414 size_t len;
415 krb5_data data;
416 PA_DATA *pa;
417 int i = 0, cmp;
419 if (rep->kdc_rep.padata == NULL)
420 goto noreferral;
422 pa = krb5_find_padata(rep->kdc_rep.padata->val,
423 rep->kdc_rep.padata->len,
424 KRB5_PADATA_SERVER_REFERRAL, &i);
425 if (pa == NULL)
426 goto noreferral;
428 memset(&ed, 0, sizeof(ed));
429 memset(&ref, 0, sizeof(ref));
431 ret = decode_EncryptedData(pa->padata_value.data,
432 pa->padata_value.length,
433 &ed, &len);
434 if (ret)
435 return ret;
436 if (len != pa->padata_value.length) {
437 free_EncryptedData(&ed);
438 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
439 N_("Referral EncryptedData wrong for realm %s",
440 "realm"), requested->realm);
441 return KRB5KRB_AP_ERR_MODIFIED;
444 ret = krb5_crypto_init(context, key, 0, &session);
445 if (ret) {
446 free_EncryptedData(&ed);
447 return ret;
450 ret = krb5_decrypt_EncryptedData(context, session,
451 KRB5_KU_PA_SERVER_REFERRAL,
452 &ed, &data);
453 free_EncryptedData(&ed);
454 krb5_crypto_destroy(context, session);
455 if (ret)
456 return ret;
458 ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
459 if (ret) {
460 krb5_data_free(&data);
461 return ret;
463 krb5_data_free(&data);
465 if (strcmp(requested->realm, returned->realm) != 0) {
466 free_PA_ServerReferralData(&ref);
467 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
468 N_("server ref realm mismatch, "
469 "requested realm %s got back %s", ""),
470 requested->realm, returned->realm);
471 return KRB5KRB_AP_ERR_MODIFIED;
474 if (krb5_principal_is_krbtgt(context, returned)) {
475 const char *realm = returned->name.name_string.val[1];
477 if (ref.referred_realm == NULL
478 || strcmp(*ref.referred_realm, realm) != 0)
480 free_PA_ServerReferralData(&ref);
481 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
482 N_("tgt returned with wrong ref", ""));
483 return KRB5KRB_AP_ERR_MODIFIED;
485 } else if (krb5_principal_compare(context, returned, requested) == 0) {
486 free_PA_ServerReferralData(&ref);
487 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
488 N_("req princ no same as returned", ""));
489 return KRB5KRB_AP_ERR_MODIFIED;
492 if (ref.requested_principal_name) {
493 cmp = _krb5_principal_compare_PrincipalName(context,
494 requested,
495 ref.requested_principal_name);
496 if (!cmp) {
497 free_PA_ServerReferralData(&ref);
498 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
499 N_("referred principal not same "
500 "as requested", ""));
501 return KRB5KRB_AP_ERR_MODIFIED;
503 } else if (flags & EXTRACT_TICKET_AS_REQ) {
504 free_PA_ServerReferralData(&ref);
505 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
506 N_("Requested principal missing on AS-REQ", ""));
507 return KRB5KRB_AP_ERR_MODIFIED;
510 free_PA_ServerReferralData(&ref);
512 return ret;
513 noreferral:
515 * Expect excact match or that we got a krbtgt
517 if (krb5_principal_compare(context, requested, returned) != TRUE &&
518 (krb5_realm_compare(context, requested, returned) != TRUE &&
519 krb5_principal_is_krbtgt(context, returned) != TRUE))
521 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
522 N_("Not same server principal returned "
523 "as requested", ""));
524 return KRB5KRB_AP_ERR_MODIFIED;
526 return 0;
531 * Verify referral data
535 static krb5_error_code
536 check_client_referral(krb5_context context,
537 krb5_kdc_rep *rep,
538 krb5_const_principal requested,
539 krb5_const_principal mapped,
540 krb5_keyblock const * key)
542 krb5_error_code ret;
543 PA_ClientCanonicalized canon;
544 krb5_crypto crypto;
545 krb5_data data;
546 PA_DATA *pa;
547 size_t len;
548 int i = 0;
550 if (rep->kdc_rep.padata == NULL)
551 goto noreferral;
553 pa = krb5_find_padata(rep->kdc_rep.padata->val,
554 rep->kdc_rep.padata->len,
555 KRB5_PADATA_CLIENT_CANONICALIZED, &i);
556 if (pa == NULL)
557 goto noreferral;
559 ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
560 pa->padata_value.length,
561 &canon, &len);
562 if (ret) {
563 krb5_set_error_message(context, ret,
564 N_("Failed to decode ClientCanonicalized "
565 "from realm %s", ""), requested->realm);
566 return ret;
569 ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
570 &canon.names, &len, ret);
571 if (ret) {
572 free_PA_ClientCanonicalized(&canon);
573 return ret;
575 if (data.length != len)
576 krb5_abortx(context, "internal asn.1 error");
578 ret = krb5_crypto_init(context, key, 0, &crypto);
579 if (ret) {
580 free(data.data);
581 free_PA_ClientCanonicalized(&canon);
582 return ret;
585 ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
586 data.data, data.length,
587 &canon.canon_checksum);
588 krb5_crypto_destroy(context, crypto);
589 free(data.data);
590 if (ret) {
591 krb5_set_error_message(context, ret,
592 N_("Failed to verify client canonicalized "
593 "data from realm %s", ""),
594 requested->realm);
595 free_PA_ClientCanonicalized(&canon);
596 return ret;
599 if (!_krb5_principal_compare_PrincipalName(context,
600 requested,
601 &canon.names.requested_name))
603 free_PA_ClientCanonicalized(&canon);
604 krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
605 N_("Requested name doesn't match"
606 " in client referral", ""));
607 return KRB5_PRINC_NOMATCH;
609 if (!_krb5_principal_compare_PrincipalName(context,
610 mapped,
611 &canon.names.mapped_name))
613 free_PA_ClientCanonicalized(&canon);
614 krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
615 N_("Mapped name doesn't match"
616 " in client referral", ""));
617 return KRB5_PRINC_NOMATCH;
620 return 0;
622 noreferral:
623 if (krb5_principal_compare(context, requested, mapped) == FALSE &&
624 !rep->enc_part.flags.enc_pa_rep)
626 krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
627 N_("Not same client principal returned "
628 "as requested", ""));
629 return KRB5KRB_AP_ERR_MODIFIED;
631 return 0;
635 static krb5_error_code KRB5_CALLCONV
636 decrypt_tkt (krb5_context context,
637 krb5_keyblock *key,
638 krb5_key_usage usage,
639 krb5_const_pointer decrypt_arg,
640 krb5_kdc_rep *dec_rep)
642 krb5_error_code ret;
643 krb5_data data;
644 size_t size;
645 krb5_crypto crypto;
647 ret = krb5_crypto_init(context, key, 0, &crypto);
648 if (ret)
649 return ret;
651 ret = krb5_decrypt_EncryptedData (context,
652 crypto,
653 usage,
654 &dec_rep->kdc_rep.enc_part,
655 &data);
656 krb5_crypto_destroy(context, crypto);
658 if (ret)
659 return ret;
661 ret = decode_EncASRepPart(data.data,
662 data.length,
663 &dec_rep->enc_part,
664 &size);
665 if (ret)
666 ret = decode_EncTGSRepPart(data.data,
667 data.length,
668 &dec_rep->enc_part,
669 &size);
670 krb5_data_free (&data);
671 if (ret) {
672 krb5_set_error_message(context, ret,
673 N_("Failed to decode encpart in ticket", ""));
674 return ret;
676 return 0;
679 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
680 _krb5_extract_ticket(krb5_context context,
681 krb5_kdc_rep *rep,
682 krb5_creds *creds,
683 krb5_keyblock *key,
684 krb5_const_pointer keyseed,
685 krb5_key_usage key_usage,
686 krb5_addresses *addrs,
687 unsigned nonce,
688 unsigned flags,
689 krb5_data *request,
690 krb5_decrypt_proc decrypt_proc,
691 krb5_const_pointer decryptarg)
693 krb5_error_code ret;
694 krb5_principal tmp_principal;
695 size_t len = 0;
696 time_t tmp_time;
697 krb5_timestamp sec_now;
699 /* decrypt */
701 if (decrypt_proc == NULL)
702 decrypt_proc = decrypt_tkt;
704 ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
705 if (ret)
706 goto out;
708 if (rep->enc_part.flags.enc_pa_rep && request) {
709 krb5_crypto crypto = NULL;
710 Checksum cksum;
711 PA_DATA *pa = NULL;
712 int idx = 0;
714 _krb5_debug(context, 5, "processing enc-ap-rep");
716 if (rep->enc_part.encrypted_pa_data == NULL ||
717 (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val,
718 rep->enc_part.encrypted_pa_data->len,
719 KRB5_PADATA_REQ_ENC_PA_REP,
720 &idx)) == NULL)
722 _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing");
723 ret = KRB5KRB_AP_ERR_MODIFIED;
724 goto out;
727 ret = krb5_crypto_init(context, key, 0, &crypto);
728 if (ret)
729 goto out;
731 ret = decode_Checksum(pa->padata_value.data,
732 pa->padata_value.length,
733 &cksum, NULL);
734 if (ret) {
735 krb5_crypto_destroy(context, crypto);
736 goto out;
739 ret = krb5_verify_checksum(context, crypto,
740 KRB5_KU_AS_REQ,
741 request->data, request->length,
742 &cksum);
743 krb5_crypto_destroy(context, crypto);
744 free_Checksum(&cksum);
745 _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in");
746 if (ret)
747 goto out;
750 /* save session key */
752 creds->session.keyvalue.length = 0;
753 creds->session.keyvalue.data = NULL;
754 creds->session.keytype = rep->enc_part.key.keytype;
755 ret = krb5_data_copy (&creds->session.keyvalue,
756 rep->enc_part.key.keyvalue.data,
757 rep->enc_part.key.keyvalue.length);
758 if (ret) {
759 krb5_clear_error_message(context);
760 goto out;
763 /* compare client and save */
764 ret = _krb5_principalname2krb5_principal(context,
765 &tmp_principal,
766 rep->kdc_rep.cname,
767 rep->kdc_rep.crealm);
768 if (ret)
769 goto out;
771 /* check client referral and save principal */
772 /* anonymous here ? */
773 if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
774 ret = check_client_referral(context, rep,
775 creds->client,
776 tmp_principal,
777 &creds->session);
778 if (ret) {
779 krb5_free_principal (context, tmp_principal);
780 goto out;
783 krb5_free_principal (context, creds->client);
784 creds->client = tmp_principal;
786 /* check server referral and save principal */
787 ret = _krb5_principalname2krb5_principal (context,
788 &tmp_principal,
789 rep->kdc_rep.ticket.sname,
790 rep->kdc_rep.ticket.realm);
791 if (ret)
792 goto out;
793 if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
794 ret = check_server_referral(context,
795 rep,
796 flags,
797 creds->server,
798 tmp_principal,
799 &creds->session);
800 if (ret) {
801 krb5_free_principal (context, tmp_principal);
802 goto out;
805 krb5_free_principal(context, creds->server);
806 creds->server = tmp_principal;
808 /* verify names */
809 if(flags & EXTRACT_TICKET_MATCH_REALM){
810 const char *srealm = krb5_principal_get_realm(context, creds->server);
811 const char *crealm = krb5_principal_get_realm(context, creds->client);
813 if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
814 strcmp(rep->enc_part.srealm, crealm) != 0)
816 ret = KRB5KRB_AP_ERR_MODIFIED;
817 krb5_clear_error_message(context);
818 goto out;
822 /* compare nonces */
824 if (nonce != (unsigned)rep->enc_part.nonce) {
825 ret = KRB5KRB_AP_ERR_MODIFIED;
826 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
827 goto out;
830 /* set kdc-offset */
832 krb5_timeofday (context, &sec_now);
833 if (rep->enc_part.flags.initial
834 && (flags & EXTRACT_TICKET_TIMESYNC)
835 && context->kdc_sec_offset == 0
836 && krb5_config_get_bool (context, NULL,
837 "libdefaults",
838 "kdc_timesync",
839 NULL)) {
840 context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
841 krb5_timeofday (context, &sec_now);
844 /* check all times */
846 if (rep->enc_part.starttime) {
847 tmp_time = *rep->enc_part.starttime;
848 } else
849 tmp_time = rep->enc_part.authtime;
851 if (creds->times.starttime == 0
852 && abs(tmp_time - sec_now) > context->max_skew) {
853 ret = KRB5KRB_AP_ERR_SKEW;
854 krb5_set_error_message (context, ret,
855 N_("time skew (%d) larger than max (%d)", ""),
856 abs(tmp_time - sec_now),
857 (int)context->max_skew);
858 goto out;
861 if (creds->times.starttime != 0
862 && tmp_time != creds->times.starttime) {
863 krb5_clear_error_message (context);
864 ret = KRB5KRB_AP_ERR_MODIFIED;
865 goto out;
868 creds->times.starttime = tmp_time;
870 if (rep->enc_part.renew_till) {
871 tmp_time = *rep->enc_part.renew_till;
872 } else
873 tmp_time = 0;
875 if (creds->times.renew_till != 0
876 && tmp_time > creds->times.renew_till) {
877 krb5_clear_error_message (context);
878 ret = KRB5KRB_AP_ERR_MODIFIED;
879 goto out;
882 creds->times.renew_till = tmp_time;
884 creds->times.authtime = rep->enc_part.authtime;
886 if (creds->times.endtime != 0
887 && rep->enc_part.endtime > creds->times.endtime) {
888 krb5_clear_error_message (context);
889 ret = KRB5KRB_AP_ERR_MODIFIED;
890 goto out;
893 creds->times.endtime = rep->enc_part.endtime;
895 if(rep->enc_part.caddr)
896 krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
897 else if(addrs)
898 krb5_copy_addresses (context, addrs, &creds->addresses);
899 else {
900 creds->addresses.len = 0;
901 creds->addresses.val = NULL;
903 creds->flags.b = rep->enc_part.flags;
905 creds->authdata.len = 0;
906 creds->authdata.val = NULL;
908 /* extract ticket */
909 ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
910 &rep->kdc_rep.ticket, &len, ret);
911 if(ret)
912 goto out;
913 if (creds->ticket.length != len)
914 krb5_abortx(context, "internal error in ASN.1 encoder");
915 creds->second_ticket.length = 0;
916 creds->second_ticket.data = NULL;
919 out:
920 memset (rep->enc_part.key.keyvalue.data, 0,
921 rep->enc_part.key.keyvalue.length);
922 return ret;