• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/heimdal/lib/krb5/
1/*
2 * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "krb5_locl.h"
35
36krb5_error_code KRB5_LIB_FUNCTION
37krb5_free_ticket(krb5_context context,
38		 krb5_ticket *ticket)
39{
40    free_EncTicketPart(&ticket->ticket);
41    krb5_free_principal(context, ticket->client);
42    krb5_free_principal(context, ticket->server);
43    free(ticket);
44    return 0;
45}
46
47krb5_error_code KRB5_LIB_FUNCTION
48krb5_copy_ticket(krb5_context context,
49		 const krb5_ticket *from,
50		 krb5_ticket **to)
51{
52    krb5_error_code ret;
53    krb5_ticket *tmp;
54
55    *to = NULL;
56    tmp = malloc(sizeof(*tmp));
57    if(tmp == NULL) {
58	krb5_set_error_message(context, ENOMEM,
59			       N_("malloc: out of memory", ""));
60	return ENOMEM;
61    }
62    if((ret = copy_EncTicketPart(&from->ticket, &tmp->ticket))){
63	free(tmp);
64	return ret;
65    }
66    ret = krb5_copy_principal(context, from->client, &tmp->client);
67    if(ret){
68	free_EncTicketPart(&tmp->ticket);
69	free(tmp);
70	return ret;
71    }
72    ret = krb5_copy_principal(context, from->server, &tmp->server);
73    if(ret){
74	krb5_free_principal(context, tmp->client);
75	free_EncTicketPart(&tmp->ticket);
76	free(tmp);
77	return ret;
78    }
79    *to = tmp;
80    return 0;
81}
82
83krb5_error_code KRB5_LIB_FUNCTION
84krb5_ticket_get_client(krb5_context context,
85		       const krb5_ticket *ticket,
86		       krb5_principal *client)
87{
88    return krb5_copy_principal(context, ticket->client, client);
89}
90
91krb5_error_code KRB5_LIB_FUNCTION
92krb5_ticket_get_server(krb5_context context,
93		       const krb5_ticket *ticket,
94		       krb5_principal *server)
95{
96    return krb5_copy_principal(context, ticket->server, server);
97}
98
99time_t KRB5_LIB_FUNCTION
100krb5_ticket_get_endtime(krb5_context context,
101			const krb5_ticket *ticket)
102{
103    return ticket->ticket.endtime;
104}
105
106/**
107 * Get the flags from the Kerberos ticket
108 *
109 * @param context Kerberos context
110 * @param ticket Kerberos ticket
111 *
112 * @return ticket flags
113 *
114 * @ingroup krb5_ticket
115 */
116unsigned long
117krb5_ticket_get_flags(krb5_context context,
118		      const krb5_ticket *ticket)
119{
120    return TicketFlags2int(ticket->ticket.flags);
121}
122
123static int
124find_type_in_ad(krb5_context context,
125		int type,
126		krb5_data *data,
127		krb5_boolean *found,
128		krb5_boolean failp,
129		krb5_keyblock *sessionkey,
130		const AuthorizationData *ad,
131		int level)
132{
133    krb5_error_code ret = 0;
134    int i;
135
136    if (level > 9) {
137	ret = ENOENT; /* XXX */
138	krb5_set_error_message(context, ret,
139			       N_("Authorization data nested deeper "
140				  "then %d levels, stop searching", ""),
141			       level);
142	goto out;
143    }
144
145    /*
146     * Only copy out the element the first time we get to it, we need
147     * to run over the whole authorization data fields to check if
148     * there are any container clases we need to care about.
149     */
150    for (i = 0; i < ad->len; i++) {
151	if (!*found && ad->val[i].ad_type == type) {
152	    ret = der_copy_octet_string(&ad->val[i].ad_data, data);
153	    if (ret) {
154		krb5_set_error_message(context, ret,
155				       N_("malloc: out of memory", ""));
156		goto out;
157	    }
158	    *found = TRUE;
159	    continue;
160	}
161	switch (ad->val[i].ad_type) {
162	case KRB5_AUTHDATA_IF_RELEVANT: {
163	    AuthorizationData child;
164	    ret = decode_AuthorizationData(ad->val[i].ad_data.data,
165					   ad->val[i].ad_data.length,
166					   &child,
167					   NULL);
168	    if (ret) {
169		krb5_set_error_message(context, ret,
170				       N_("Failed to decode "
171					  "IF_RELEVANT with %d", ""),
172				       (int)ret);
173		goto out;
174	    }
175	    ret = find_type_in_ad(context, type, data, found, FALSE,
176				  sessionkey, &child, level + 1);
177	    free_AuthorizationData(&child);
178	    if (ret)
179		goto out;
180	    break;
181	}
182#if 0 /* XXX test */
183	case KRB5_AUTHDATA_KDC_ISSUED: {
184	    AD_KDCIssued child;
185
186	    ret = decode_AD_KDCIssued(ad->val[i].ad_data.data,
187				      ad->val[i].ad_data.length,
188				      &child,
189				      NULL);
190	    if (ret) {
191		krb5_set_error_message(context, ret,
192				       N_("Failed to decode "
193					  "AD_KDCIssued with %d", ""),
194				       ret);
195		goto out;
196	    }
197	    if (failp) {
198		krb5_boolean valid;
199		krb5_data buf;
200		size_t len;
201
202		ASN1_MALLOC_ENCODE(AuthorizationData, buf.data, buf.length,
203				   &child.elements, &len, ret);
204		if (ret) {
205		    free_AD_KDCIssued(&child);
206		    krb5_clear_error_message(context);
207		    goto out;
208		}
209		if(buf.length != len)
210		    krb5_abortx(context, "internal error in ASN.1 encoder");
211
212		ret = krb5_c_verify_checksum(context, sessionkey, 19, &buf,
213					     &child.ad_checksum, &valid);
214		krb5_data_free(&buf);
215		if (ret) {
216		    free_AD_KDCIssued(&child);
217		    goto out;
218		}
219		if (!valid) {
220		    krb5_clear_error_message(context);
221		    ret = ENOENT;
222		    free_AD_KDCIssued(&child);
223		    goto out;
224		}
225	    }
226	    ret = find_type_in_ad(context, type, data, found, failp, sessionkey,
227				  &child.elements, level + 1);
228	    free_AD_KDCIssued(&child);
229	    if (ret)
230		goto out;
231	    break;
232	}
233#endif
234	case KRB5_AUTHDATA_AND_OR:
235	    if (!failp)
236		break;
237	    ret = ENOENT; /* XXX */
238	    krb5_set_error_message(context, ret,
239				   N_("Authorization data contains "
240				      "AND-OR element that is unknown to the "
241				      "application", ""));
242	    goto out;
243	default:
244	    if (!failp)
245		break;
246	    ret = ENOENT; /* XXX */
247	    krb5_set_error_message(context, ret,
248				   N_("Authorization data contains "
249				      "unknown type (%d) ", ""),
250				   ad->val[i].ad_type);
251	    goto out;
252	}
253    }
254out:
255    if (ret) {
256	if (*found) {
257	    krb5_data_free(data);
258	    *found = 0;
259	}
260    }
261    return ret;
262}
263
264/*
265 * Extract the authorization data type of `type' from the
266 * 'ticket'. Store the field in `data'. This function is to use for
267 * kerberos applications.
268 */
269
270krb5_error_code KRB5_LIB_FUNCTION
271krb5_ticket_get_authorization_data_type(krb5_context context,
272					krb5_ticket *ticket,
273					int type,
274					krb5_data *data)
275{
276    AuthorizationData *ad;
277    krb5_error_code ret;
278    krb5_boolean found = FALSE;
279
280    krb5_data_zero(data);
281
282    ad = ticket->ticket.authorization_data;
283    if (ticket->ticket.authorization_data == NULL) {
284	krb5_set_error_message(context, ENOENT,
285			       N_("Ticket have not authorization data", ""));
286	return ENOENT; /* XXX */
287    }
288
289    ret = find_type_in_ad(context, type, data, &found, TRUE,
290			  &ticket->ticket.key, ad, 0);
291    if (ret)
292	return ret;
293    if (!found) {
294	krb5_set_error_message(context, ENOENT,
295			       N_("Ticket have not "
296				  "authorization data of type %d", ""),
297			       type);
298	return ENOENT; /* XXX */
299    }
300    return 0;
301}
302
303static krb5_error_code
304check_server_referral(krb5_context context,
305		      krb5_kdc_rep *rep,
306		      unsigned flags,
307		      krb5_const_principal requested,
308		      krb5_const_principal returned,
309		      krb5_keyblock * key)
310{
311    krb5_error_code ret;
312    PA_ServerReferralData ref;
313    krb5_crypto session;
314    EncryptedData ed;
315    size_t len;
316    krb5_data data;
317    PA_DATA *pa;
318    int i = 0, cmp;
319
320    if (rep->kdc_rep.padata == NULL)
321	goto noreferral;
322
323    pa = krb5_find_padata(rep->kdc_rep.padata->val,
324			  rep->kdc_rep.padata->len,
325			  KRB5_PADATA_SERVER_REFERRAL, &i);
326    if (pa == NULL)
327	goto noreferral;
328
329    memset(&ed, 0, sizeof(ed));
330    memset(&ref, 0, sizeof(ref));
331
332    ret = decode_EncryptedData(pa->padata_value.data,
333			       pa->padata_value.length,
334			       &ed, &len);
335    if (ret)
336	return ret;
337    if (len != pa->padata_value.length) {
338	free_EncryptedData(&ed);
339	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
340			       N_("Referral EncryptedData wrong for realm %s",
341				  "realm"), requested->realm);
342	return KRB5KRB_AP_ERR_MODIFIED;
343    }
344
345    ret = krb5_crypto_init(context, key, 0, &session);
346    if (ret) {
347	free_EncryptedData(&ed);
348	return ret;
349    }
350
351    ret = krb5_decrypt_EncryptedData(context, session,
352				     KRB5_KU_PA_SERVER_REFERRAL,
353				     &ed, &data);
354    free_EncryptedData(&ed);
355    krb5_crypto_destroy(context, session);
356    if (ret)
357	return ret;
358
359    ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
360    if (ret) {
361	krb5_data_free(&data);
362	return ret;
363    }
364    krb5_data_free(&data);
365
366    if (strcmp(requested->realm, returned->realm) != 0) {
367	free_PA_ServerReferralData(&ref);
368	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
369			       N_("server ref realm mismatch, "
370				  "requested realm %s got back %s", ""),
371			       requested->realm, returned->realm);
372	return KRB5KRB_AP_ERR_MODIFIED;
373    }
374
375    if (returned->name.name_string.len == 2 &&
376	strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0)
377    {
378	const char *realm = returned->name.name_string.val[1];
379
380	if (ref.referred_realm == NULL
381	    || strcmp(*ref.referred_realm, realm) != 0)
382	{
383	    free_PA_ServerReferralData(&ref);
384	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
385				   N_("tgt returned with wrong ref", ""));
386	    return KRB5KRB_AP_ERR_MODIFIED;
387	}
388    } else if (krb5_principal_compare(context, returned, requested) == 0) {
389	free_PA_ServerReferralData(&ref);
390	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
391			       N_("req princ no same as returned", ""));
392	return KRB5KRB_AP_ERR_MODIFIED;
393    }
394
395    if (ref.requested_principal_name) {
396	cmp = _krb5_principal_compare_PrincipalName(context,
397						    requested,
398						    ref.requested_principal_name);
399	if (!cmp) {
400	    free_PA_ServerReferralData(&ref);
401	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
402				   N_("referred principal not same "
403				      "as requested", ""));
404	    return KRB5KRB_AP_ERR_MODIFIED;
405	}
406    } else if (flags & EXTRACT_TICKET_AS_REQ) {
407	free_PA_ServerReferralData(&ref);
408	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
409			       N_("Requested principal missing on AS-REQ", ""));
410	return KRB5KRB_AP_ERR_MODIFIED;
411    }
412
413    free_PA_ServerReferralData(&ref);
414
415    return ret;
416noreferral:
417    if (krb5_principal_compare(context, requested, returned) == FALSE) {
418	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
419			       N_("Not same server principal returned "
420				  "as requested", ""));
421	return KRB5KRB_AP_ERR_MODIFIED;
422    }
423    return 0;
424}
425
426
427/*
428 * Verify referral data
429 */
430
431
432static krb5_error_code
433check_client_referral(krb5_context context,
434		      krb5_kdc_rep *rep,
435		      krb5_const_principal requested,
436		      krb5_const_principal mapped,
437		      krb5_keyblock const * key)
438{
439    krb5_error_code ret;
440    PA_ClientCanonicalized canon;
441    krb5_crypto crypto;
442    krb5_data data;
443    PA_DATA *pa;
444    size_t len;
445    int i = 0;
446
447    if (rep->kdc_rep.padata == NULL)
448	goto noreferral;
449
450    pa = krb5_find_padata(rep->kdc_rep.padata->val,
451			  rep->kdc_rep.padata->len,
452			  KRB5_PADATA_CLIENT_CANONICALIZED, &i);
453    if (pa == NULL)
454	goto noreferral;
455
456    ret = decode_PA_ClientCanonicalized(pa->padata_value.data,
457					pa->padata_value.length,
458					&canon, &len);
459    if (ret) {
460	krb5_set_error_message(context, ret,
461			       N_("Failed to decode ClientCanonicalized "
462				  "from realm %s", ""), requested->realm);
463	return ret;
464    }
465
466    ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length,
467		       &canon.names, &len, ret);
468    if (ret) {
469	free_PA_ClientCanonicalized(&canon);
470	return ret;
471    }
472    if (data.length != len)
473	krb5_abortx(context, "internal asn.1 error");
474
475    ret = krb5_crypto_init(context, key, 0, &crypto);
476    if (ret) {
477	free(data.data);
478	free_PA_ClientCanonicalized(&canon);
479	return ret;
480    }
481
482    ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES,
483			       data.data, data.length,
484			       &canon.canon_checksum);
485    krb5_crypto_destroy(context, crypto);
486    free(data.data);
487    if (ret) {
488	krb5_set_error_message(context, ret,
489			       N_("Failed to verify client canonicalized "
490				  "data from realm %s", ""),
491			       requested->realm);
492	free_PA_ClientCanonicalized(&canon);
493	return ret;
494    }
495
496    if (!_krb5_principal_compare_PrincipalName(context,
497					       requested,
498					       &canon.names.requested_name))
499    {
500	free_PA_ClientCanonicalized(&canon);
501	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
502			       N_("Requested name doesn't match"
503				  " in client referral", ""));
504	return KRB5_PRINC_NOMATCH;
505    }
506    if (!_krb5_principal_compare_PrincipalName(context,
507					       mapped,
508					       &canon.names.mapped_name))
509    {
510	free_PA_ClientCanonicalized(&canon);
511	krb5_set_error_message(context, KRB5_PRINC_NOMATCH,
512			       N_("Mapped name doesn't match"
513				  " in client referral", ""));
514	return KRB5_PRINC_NOMATCH;
515    }
516
517    return 0;
518
519noreferral:
520    if (krb5_principal_compare(context, requested, mapped) == FALSE) {
521	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
522			       N_("Not same client principal returned "
523				  "as requested", ""));
524	return KRB5KRB_AP_ERR_MODIFIED;
525    }
526    return 0;
527}
528
529
530static krb5_error_code
531decrypt_tkt (krb5_context context,
532	     krb5_keyblock *key,
533	     krb5_key_usage usage,
534	     krb5_const_pointer decrypt_arg,
535	     krb5_kdc_rep *dec_rep)
536{
537    krb5_error_code ret;
538    krb5_data data;
539    size_t size;
540    krb5_crypto crypto;
541
542    ret = krb5_crypto_init(context, key, 0, &crypto);
543    if (ret)
544	return ret;
545
546    ret = krb5_decrypt_EncryptedData (context,
547				      crypto,
548				      usage,
549				      &dec_rep->kdc_rep.enc_part,
550				      &data);
551    krb5_crypto_destroy(context, crypto);
552
553    if (ret)
554	return ret;
555
556    ret = decode_EncASRepPart(data.data,
557			      data.length,
558			      &dec_rep->enc_part,
559			      &size);
560    if (ret)
561	ret = decode_EncTGSRepPart(data.data,
562				   data.length,
563				   &dec_rep->enc_part,
564				   &size);
565    krb5_data_free (&data);
566    if (ret) {
567        krb5_set_error_message(context, ret,
568			       N_("Failed to decode encpart in ticket", ""));
569	return ret;
570    }
571    return 0;
572}
573
574int
575_krb5_extract_ticket(krb5_context context,
576		     krb5_kdc_rep *rep,
577		     krb5_creds *creds,
578		     krb5_keyblock *key,
579		     krb5_const_pointer keyseed,
580		     krb5_key_usage key_usage,
581		     krb5_addresses *addrs,
582		     unsigned nonce,
583		     unsigned flags,
584		     krb5_decrypt_proc decrypt_proc,
585		     krb5_const_pointer decryptarg)
586{
587    krb5_error_code ret;
588    krb5_principal tmp_principal;
589    size_t len;
590    time_t tmp_time;
591    krb5_timestamp sec_now;
592
593    /* decrypt */
594
595    if (decrypt_proc == NULL)
596	decrypt_proc = decrypt_tkt;
597
598    ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep);
599    if (ret)
600	goto out;
601
602    /* save session key */
603
604    creds->session.keyvalue.length = 0;
605    creds->session.keyvalue.data   = NULL;
606    creds->session.keytype = rep->enc_part.key.keytype;
607    ret = krb5_data_copy (&creds->session.keyvalue,
608			  rep->enc_part.key.keyvalue.data,
609			  rep->enc_part.key.keyvalue.length);
610    if (ret) {
611	krb5_clear_error_message(context);
612	goto out;
613    }
614
615    /*
616     * HACK:
617     * this is really a ugly hack, to support using the Netbios Domain Name
618     * as realm against windows KDC's, they always return the full realm
619     * based on the DNS Name.
620     */
621    flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
622    flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
623
624    /* compare client and save */
625    ret = _krb5_principalname2krb5_principal (context,
626					      &tmp_principal,
627					      rep->kdc_rep.cname,
628					      rep->kdc_rep.crealm);
629    if (ret)
630	goto out;
631
632    /* check client referral and save principal */
633    /* anonymous here ? */
634    if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) {
635	ret = check_client_referral(context, rep,
636				    creds->client,
637				    tmp_principal,
638				    &creds->session);
639	if (ret) {
640	    krb5_free_principal (context, tmp_principal);
641	    goto out;
642	}
643    }
644    krb5_free_principal (context, creds->client);
645    creds->client = tmp_principal;
646
647    /* check server referral and save principal */
648    ret = _krb5_principalname2krb5_principal (context,
649					      &tmp_principal,
650					      rep->kdc_rep.ticket.sname,
651					      rep->kdc_rep.ticket.realm);
652    if (ret)
653	goto out;
654    if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){
655	ret = check_server_referral(context,
656				    rep,
657				    flags,
658				    creds->server,
659				    tmp_principal,
660				    &creds->session);
661	if (ret) {
662	    krb5_free_principal (context, tmp_principal);
663	    goto out;
664	}
665    }
666    krb5_free_principal(context, creds->server);
667    creds->server = tmp_principal;
668
669    /* verify names */
670    if(flags & EXTRACT_TICKET_MATCH_REALM){
671	const char *srealm = krb5_principal_get_realm(context, creds->server);
672	const char *crealm = krb5_principal_get_realm(context, creds->client);
673
674	if (strcmp(rep->enc_part.srealm, srealm) != 0 ||
675	    strcmp(rep->enc_part.srealm, crealm) != 0)
676	{
677	    ret = KRB5KRB_AP_ERR_MODIFIED;
678	    krb5_clear_error_message(context);
679	    goto out;
680	}
681    }
682
683    /* compare nonces */
684
685    if (nonce != rep->enc_part.nonce) {
686	ret = KRB5KRB_AP_ERR_MODIFIED;
687	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
688	goto out;
689    }
690
691    /* set kdc-offset */
692
693    krb5_timeofday (context, &sec_now);
694    if (rep->enc_part.flags.initial
695	&& context->kdc_sec_offset == 0
696	&& krb5_config_get_bool (context, NULL,
697				 "libdefaults",
698				 "kdc_timesync",
699				 NULL)) {
700	context->kdc_sec_offset = rep->enc_part.authtime - sec_now;
701	krb5_timeofday (context, &sec_now);
702    }
703
704    /* check all times */
705
706    if (rep->enc_part.starttime) {
707	tmp_time = *rep->enc_part.starttime;
708    } else
709	tmp_time = rep->enc_part.authtime;
710
711    if (creds->times.starttime == 0
712	&& abs(tmp_time - sec_now) > context->max_skew) {
713	ret = KRB5KRB_AP_ERR_SKEW;
714	krb5_set_error_message (context, ret,
715				N_("time skew (%d) larger than max (%d)", ""),
716			       abs(tmp_time - sec_now),
717			       (int)context->max_skew);
718	goto out;
719    }
720
721    if (creds->times.starttime != 0
722	&& tmp_time != creds->times.starttime) {
723	krb5_clear_error_message (context);
724	ret = KRB5KRB_AP_ERR_MODIFIED;
725	goto out;
726    }
727
728    creds->times.starttime = tmp_time;
729
730    if (rep->enc_part.renew_till) {
731	tmp_time = *rep->enc_part.renew_till;
732    } else
733	tmp_time = 0;
734
735    if (creds->times.renew_till != 0
736	&& tmp_time > creds->times.renew_till) {
737	krb5_clear_error_message (context);
738	ret = KRB5KRB_AP_ERR_MODIFIED;
739	goto out;
740    }
741
742    creds->times.renew_till = tmp_time;
743
744    creds->times.authtime = rep->enc_part.authtime;
745
746    if (creds->times.endtime != 0
747	&& rep->enc_part.endtime > creds->times.endtime) {
748	krb5_clear_error_message (context);
749	ret = KRB5KRB_AP_ERR_MODIFIED;
750	goto out;
751    }
752
753    creds->times.endtime  = rep->enc_part.endtime;
754
755    if(rep->enc_part.caddr)
756	krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses);
757    else if(addrs)
758	krb5_copy_addresses (context, addrs, &creds->addresses);
759    else {
760	creds->addresses.len = 0;
761	creds->addresses.val = NULL;
762    }
763    creds->flags.b = rep->enc_part.flags;
764
765    creds->authdata.len = 0;
766    creds->authdata.val = NULL;
767
768    /* extract ticket */
769    ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length,
770		       &rep->kdc_rep.ticket, &len, ret);
771    if(ret)
772	goto out;
773    if (creds->ticket.length != len)
774	krb5_abortx(context, "internal error in ASN.1 encoder");
775    creds->second_ticket.length = 0;
776    creds->second_ticket.data   = NULL;
777
778
779out:
780    memset (rep->enc_part.key.keyvalue.data, 0,
781	    rep->enc_part.key.keyvalue.length);
782    return ret;
783}
784