1 /* $NetBSD: ticket.c,v 1.1.1.2 2014/04/24 12:45:51 pettai 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
krb5_free_ticket(krb5_context context,krb5_ticket * ticket)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
krb5_copy_ticket(krb5_context context,const krb5_ticket * from,krb5_ticket ** to)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
krb5_ticket_get_client(krb5_context context,const krb5_ticket * ticket,krb5_principal * client)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
krb5_ticket_get_server(krb5_context context,const krb5_ticket * ticket,krb5_principal * server)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
krb5_ticket_get_endtime(krb5_context context,const krb5_ticket * ticket)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
krb5_ticket_get_flags(krb5_context context,const krb5_ticket * ticket)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
find_type_in_ad(krb5_context context,int type,krb5_data * data,krb5_boolean * found,krb5_boolean failp,krb5_keyblock * sessionkey,const AuthorizationData * ad,int level)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 size_t 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
krb5_ticket_get_authorization_data_type(krb5_context context,krb5_ticket * ticket,int type,krb5_data * data)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
check_server_referral(krb5_context context,krb5_kdc_rep * rep,unsigned flags,krb5_const_principal requested,krb5_const_principal returned,krb5_keyblock * key)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
check_client_referral(krb5_context context,krb5_kdc_rep * rep,krb5_const_principal requested,krb5_const_principal mapped,krb5_keyblock const * key)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
decrypt_tkt(krb5_context context,krb5_keyblock * key,krb5_key_usage usage,krb5_const_pointer decrypt_arg,krb5_kdc_rep * dec_rep)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
_krb5_extract_ticket(krb5_context context,krb5_kdc_rep * rep,krb5_creds * creds,krb5_keyblock * key,krb5_const_pointer keyseed,krb5_key_usage key_usage,krb5_addresses * addrs,unsigned nonce,unsigned flags,krb5_decrypt_proc decrypt_proc,krb5_const_pointer decryptarg)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 = 0;
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 != (unsigned)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