xref: /netbsd-src/crypto/external/bsd/heimdal/dist/kdc/krb5tgs.c (revision a8c74629f602faa0ccf8a463757d7baf858bbf3a)
1 /*	$NetBSD: krb5tgs.c,v 1.3 2019/12/15 22:50:46 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
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.
18  *
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.
22  *
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.
34  */
35 
36 #include "kdc_locl.h"
37 
38 /*
39  * return the realm of a krbtgt-ticket or NULL
40  */
41 
42 static Realm
43 get_krbtgt_realm(const PrincipalName *p)
44 {
45     if(p->name_string.len == 2
46        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
47 	return p->name_string.val[1];
48     else
49 	return NULL;
50 }
51 
52 /*
53  * The KDC might add a signed path to the ticket authorization data
54  * field. This is to avoid server impersonating clients and the
55  * request constrained delegation.
56  *
57  * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58  * entry of type KRB5SignedPath.
59  */
60 
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context,
63 		    const AuthorizationData *ad,
64 		    krb5_data *data)
65 {
66     AuthorizationData child;
67     krb5_error_code ret;
68     int pos;
69 
70     if (ad == NULL || ad->len == 0)
71 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
72 
73     pos = ad->len - 1;
74 
75     if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
76 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
77 
78     ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
79 				   ad->val[pos].ad_data.length,
80 				   &child,
81 				   NULL);
82     if (ret) {
83 	krb5_set_error_message(context, ret, "Failed to decode "
84 			       "IF_RELEVANT with %d", ret);
85 	return ret;
86     }
87 
88     if (child.len != 1) {
89 	free_AuthorizationData(&child);
90 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91     }
92 
93     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94 	free_AuthorizationData(&child);
95 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
96     }
97 
98     if (data)
99 	ret = der_copy_octet_string(&child.val[0].ad_data, data);
100     free_AuthorizationData(&child);
101     return ret;
102 }
103 
104 krb5_error_code
105 _kdc_add_KRB5SignedPath(krb5_context context,
106 			krb5_kdc_configuration *config,
107 			hdb_entry_ex *krbtgt,
108 			krb5_enctype enctype,
109 			krb5_const_principal client,
110 			krb5_const_principal server,
111 			krb5_principals principals,
112 			EncTicketPart *tkt)
113 {
114     krb5_error_code ret;
115     KRB5SignedPath sp;
116     krb5_data data;
117     krb5_crypto crypto = NULL;
118     size_t size = 0;
119 
120     if (server && principals) {
121 	ret = add_Principals(principals, server);
122 	if (ret)
123 	    return ret;
124     }
125 
126     {
127 	KRB5SignedPathData spd;
128 
129 	spd.client = rk_UNCONST(client);
130 	spd.authtime = tkt->authtime;
131 	spd.delegated = principals;
132 	spd.method_data = NULL;
133 
134 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
135 			   &spd, &size, ret);
136 	if (ret)
137 	    return ret;
138 	if (data.length != size)
139 	    krb5_abortx(context, "internal asn.1 encoder error");
140     }
141 
142     {
143 	Key *key;
144 	ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
145 	if (ret == 0)
146 	    ret = krb5_crypto_init(context, &key->key, 0, &crypto);
147 	if (ret) {
148 	    free(data.data);
149 	    return ret;
150 	}
151     }
152 
153     /*
154      * Fill in KRB5SignedPath
155      */
156 
157     sp.etype = enctype;
158     sp.delegated = principals;
159     sp.method_data = NULL;
160 
161     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
162 			       data.data, data.length, &sp.cksum);
163     krb5_crypto_destroy(context, crypto);
164     free(data.data);
165     if (ret)
166 	return ret;
167 
168     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
169     free_Checksum(&sp.cksum);
170     if (ret)
171 	return ret;
172     if (data.length != size)
173 	krb5_abortx(context, "internal asn.1 encoder error");
174 
175 
176     /*
177      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178      * authorization data field.
179      */
180 
181     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
182 				      KRB5_AUTHDATA_SIGNTICKET, &data);
183     krb5_data_free(&data);
184 
185     return ret;
186 }
187 
188 static krb5_error_code
189 check_KRB5SignedPath(krb5_context context,
190 		     krb5_kdc_configuration *config,
191 		     hdb_entry_ex *krbtgt,
192 		     krb5_principal cp,
193 		     EncTicketPart *tkt,
194 		     krb5_principals *delegated,
195 		     int *signedpath)
196 {
197     krb5_error_code ret;
198     krb5_data data;
199     krb5_crypto crypto = NULL;
200 
201     if (delegated)
202 	*delegated = NULL;
203 
204     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
205     if (ret == 0) {
206 	KRB5SignedPathData spd;
207 	KRB5SignedPath sp;
208 	size_t size = 0;
209 
210 	ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
211 	krb5_data_free(&data);
212 	if (ret)
213 	    return ret;
214 
215 	spd.client = cp;
216 	spd.authtime = tkt->authtime;
217 	spd.delegated = sp.delegated;
218 	spd.method_data = sp.method_data;
219 
220 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221 			   &spd, &size, ret);
222 	if (ret) {
223 	    free_KRB5SignedPath(&sp);
224 	    return ret;
225 	}
226 	if (data.length != size)
227 	    krb5_abortx(context, "internal asn.1 encoder error");
228 
229 	{
230 	    Key *key;
231 	    ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
232 				  sp.etype, &key);
233 	    if (ret == 0)
234 		ret = krb5_crypto_init(context, &key->key, 0, &crypto);
235 	    if (ret) {
236 		free(data.data);
237 		free_KRB5SignedPath(&sp);
238 		return ret;
239 	    }
240 	}
241 	ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
242 				   data.data, data.length,
243 				   &sp.cksum);
244 	krb5_crypto_destroy(context, crypto);
245 	free(data.data);
246 	if (ret) {
247 	    free_KRB5SignedPath(&sp);
248 	    kdc_log(context, config, 5,
249 		    "KRB5SignedPath not signed correctly, not marking as signed");
250 	    return 0;
251 	}
252 
253 	if (delegated && sp.delegated) {
254 
255 	    *delegated = malloc(sizeof(*sp.delegated));
256 	    if (*delegated == NULL) {
257 		free_KRB5SignedPath(&sp);
258 		return ENOMEM;
259 	    }
260 
261 	    ret = copy_Principals(*delegated, sp.delegated);
262 	    if (ret) {
263 		free_KRB5SignedPath(&sp);
264 		free(*delegated);
265 		*delegated = NULL;
266 		return ret;
267 	    }
268 	}
269 	free_KRB5SignedPath(&sp);
270 
271 	*signedpath = 1;
272     }
273 
274     return 0;
275 }
276 
277 /*
278  *
279  */
280 
281 static krb5_error_code
282 check_PAC(krb5_context context,
283 	  krb5_kdc_configuration *config,
284 	  const krb5_principal client_principal,
285 	  const krb5_principal delegated_proxy_principal,
286 	  hdb_entry_ex *client,
287 	  hdb_entry_ex *server,
288 	  hdb_entry_ex *krbtgt,
289 	  const EncryptionKey *server_check_key,
290 	  const EncryptionKey *server_sign_key,
291 	  const EncryptionKey *krbtgt_sign_key,
292 	  EncTicketPart *tkt,
293 	  krb5_data *rspac,
294 	  int *signedpath)
295 {
296     AuthorizationData *ad = tkt->authorization_data;
297     unsigned i, j;
298     krb5_error_code ret;
299 
300     if (ad == NULL || ad->len == 0)
301 	return 0;
302 
303     for (i = 0; i < ad->len; i++) {
304 	AuthorizationData child;
305 
306 	if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
307 	    continue;
308 
309 	ret = decode_AuthorizationData(ad->val[i].ad_data.data,
310 				       ad->val[i].ad_data.length,
311 				       &child,
312 				       NULL);
313 	if (ret) {
314 	    krb5_set_error_message(context, ret, "Failed to decode "
315 				   "IF_RELEVANT with %d", ret);
316 	    return ret;
317 	}
318 	for (j = 0; j < child.len; j++) {
319 
320 	    if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
321 		int signed_pac = 0;
322 		krb5_pac pac;
323 
324 		/* Found PAC */
325 		ret = krb5_pac_parse(context,
326 				     child.val[j].ad_data.data,
327 				     child.val[j].ad_data.length,
328 				     &pac);
329 		free_AuthorizationData(&child);
330 		if (ret)
331 		    return ret;
332 
333 		ret = krb5_pac_verify(context, pac, tkt->authtime,
334 				      client_principal,
335 				      server_check_key, NULL);
336 		if (ret) {
337 		    krb5_pac_free(context, pac);
338 		    return ret;
339 		}
340 
341 		ret = _kdc_pac_verify(context, client_principal,
342 				      delegated_proxy_principal,
343 				      client, server, krbtgt, &pac, &signed_pac);
344 		if (ret) {
345 		    krb5_pac_free(context, pac);
346 		    return ret;
347 		}
348 
349 		/*
350 		 * Only re-sign PAC if we could verify it with the PAC
351 		 * function. The no-verify case happens when we get in
352 		 * a PAC from cross realm from a Windows domain and
353 		 * that there is no PAC verification function.
354 		 */
355 		if (signed_pac) {
356 		    *signedpath = 1;
357 		    ret = _krb5_pac_sign(context, pac, tkt->authtime,
358 					 client_principal,
359 					 server_sign_key, krbtgt_sign_key, rspac);
360 		}
361 		krb5_pac_free(context, pac);
362 
363 		return ret;
364 	    }
365 	}
366 	free_AuthorizationData(&child);
367     }
368     return 0;
369 }
370 
371 static krb5_boolean
372 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
373 		      const EncTicketPart *tgt)
374 {
375     KDCOptions f = b->kdc_options;
376 
377     /*
378      * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
379      * request-anonymous and cname-in-addl-tkt flags for constrained
380      * delegation requests. A true anonymous TGS request will only
381      * have the request-anonymous flag set. (A corollary of this is
382      * that it is not possible to support anonymous constrained
383      * delegation requests, although they would be of limited utility.)
384      */
385     return tgt->flags.anonymous ||
386 	(f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
387 }
388 
389 /*
390  *
391  */
392 
393 static krb5_error_code
394 check_tgs_flags(krb5_context context,
395 		krb5_kdc_configuration *config,
396 		KDC_REQ_BODY *b,
397 		krb5_const_principal tgt_name,
398 		const EncTicketPart *tgt,
399 		EncTicketPart *et)
400 {
401     KDCOptions f = b->kdc_options;
402 
403     if(f.validate){
404 	if(!tgt->flags.invalid || tgt->starttime == NULL){
405 	    kdc_log(context, config, 0,
406 		    "Bad request to validate ticket");
407 	    return KRB5KDC_ERR_BADOPTION;
408 	}
409 	if(*tgt->starttime > kdc_time){
410 	    kdc_log(context, config, 0,
411 		    "Early request to validate ticket");
412 	    return KRB5KRB_AP_ERR_TKT_NYV;
413 	}
414 	/* XXX  tkt = tgt */
415 	et->flags.invalid = 0;
416     }else if(tgt->flags.invalid){
417 	kdc_log(context, config, 0,
418 		"Ticket-granting ticket has INVALID flag set");
419 	return KRB5KRB_AP_ERR_TKT_INVALID;
420     }
421 
422     if(f.forwardable){
423 	if(!tgt->flags.forwardable){
424 	    kdc_log(context, config, 0,
425 		    "Bad request for forwardable ticket");
426 	    return KRB5KDC_ERR_BADOPTION;
427 	}
428 	et->flags.forwardable = 1;
429     }
430     if(f.forwarded){
431 	if(!tgt->flags.forwardable){
432 	    kdc_log(context, config, 0,
433 		    "Request to forward non-forwardable ticket");
434 	    return KRB5KDC_ERR_BADOPTION;
435 	}
436 	et->flags.forwarded = 1;
437 	et->caddr = b->addresses;
438     }
439     if(tgt->flags.forwarded)
440 	et->flags.forwarded = 1;
441 
442     if(f.proxiable){
443 	if(!tgt->flags.proxiable){
444 	    kdc_log(context, config, 0,
445 		    "Bad request for proxiable ticket");
446 	    return KRB5KDC_ERR_BADOPTION;
447 	}
448 	et->flags.proxiable = 1;
449     }
450     if(f.proxy){
451 	if(!tgt->flags.proxiable){
452 	    kdc_log(context, config, 0,
453 		    "Request to proxy non-proxiable ticket");
454 	    return KRB5KDC_ERR_BADOPTION;
455 	}
456 	et->flags.proxy = 1;
457 	et->caddr = b->addresses;
458     }
459     if(tgt->flags.proxy)
460 	et->flags.proxy = 1;
461 
462     if(f.allow_postdate){
463 	if(!tgt->flags.may_postdate){
464 	    kdc_log(context, config, 0,
465 		    "Bad request for post-datable ticket");
466 	    return KRB5KDC_ERR_BADOPTION;
467 	}
468 	et->flags.may_postdate = 1;
469     }
470     if(f.postdated){
471 	if(!tgt->flags.may_postdate){
472 	    kdc_log(context, config, 0,
473 		    "Bad request for postdated ticket");
474 	    return KRB5KDC_ERR_BADOPTION;
475 	}
476 	if(b->from)
477 	    *et->starttime = *b->from;
478 	et->flags.postdated = 1;
479 	et->flags.invalid = 1;
480     }else if(b->from && *b->from > kdc_time + context->max_skew){
481 	kdc_log(context, config, 0, "Ticket cannot be postdated");
482 	return KRB5KDC_ERR_CANNOT_POSTDATE;
483     }
484 
485     if(f.renewable){
486 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
487 	    kdc_log(context, config, 0,
488 		    "Bad request for renewable ticket");
489 	    return KRB5KDC_ERR_BADOPTION;
490 	}
491 	et->flags.renewable = 1;
492 	ALLOC(et->renew_till);
493 	_kdc_fix_time(&b->rtime);
494 	*et->renew_till = *b->rtime;
495     }
496     if(f.renew){
497 	time_t old_life;
498 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
499 	    kdc_log(context, config, 0,
500 		    "Request to renew non-renewable ticket");
501 	    return KRB5KDC_ERR_BADOPTION;
502 	}
503 	old_life = tgt->endtime;
504 	if(tgt->starttime)
505 	    old_life -= *tgt->starttime;
506 	else
507 	    old_life -= tgt->authtime;
508 	et->endtime = *et->starttime + old_life;
509 	if (et->renew_till != NULL)
510 	    et->endtime = min(*et->renew_till, et->endtime);
511     }
512 
513     /*
514      * RFC 8062 section 3 defines an anonymous ticket as one containing
515      * the anonymous principal and the anonymous ticket flag.
516      */
517     if (tgt->flags.anonymous &&
518 	!_kdc_is_anonymous(context, tgt_name)) {
519 	kdc_log(context, config, 0,
520 		"Anonymous ticket flag set without anonymous principal");
521 	return KRB5KDC_ERR_BADOPTION;
522     }
523 
524     /*
525      * RFC 8062 section 4.2 states that if the TGT is anonymous, the
526      * anonymous KDC option SHOULD be set, but it is not required.
527      * Treat an anonymous TGT as if the anonymous flag was set.
528      */
529     if (is_anon_tgs_request_p(b, tgt))
530 	et->flags.anonymous = 1;
531 
532     return 0;
533 }
534 
535 /*
536  * Determine if constrained delegation is allowed from this client to this server
537  */
538 
539 static krb5_error_code
540 check_constrained_delegation(krb5_context context,
541 			     krb5_kdc_configuration *config,
542 			     HDB *clientdb,
543 			     hdb_entry_ex *client,
544 			     hdb_entry_ex *server,
545 			     krb5_const_principal target)
546 {
547     const HDB_Ext_Constrained_delegation_acl *acl;
548     krb5_error_code ret;
549     size_t i;
550 
551     /*
552      * constrained_delegation (S4U2Proxy) only works within
553      * the same realm. We use the already canonicalized version
554      * of the principals here, while "target" is the principal
555      * provided by the client.
556      */
557     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
558 	ret = KRB5KDC_ERR_BADOPTION;
559 	kdc_log(context, config, 0,
560 	    "Bad request for constrained delegation");
561 	return ret;
562     }
563 
564     if (clientdb->hdb_check_constrained_delegation) {
565 	ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
566 	if (ret == 0)
567 	    return 0;
568     } else {
569 	/* if client delegates to itself, that ok */
570 	if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
571 	    return 0;
572 
573 	ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
574 	if (ret) {
575 	    krb5_clear_error_message(context);
576 	    return ret;
577 	}
578 
579 	if (acl) {
580 	    for (i = 0; i < acl->len; i++) {
581 		if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
582 		    return 0;
583 	    }
584 	}
585 	ret = KRB5KDC_ERR_BADOPTION;
586     }
587     kdc_log(context, config, 0,
588 	    "Bad request for constrained delegation");
589     return ret;
590 }
591 
592 /*
593  * Determine if s4u2self is allowed from this client to this server
594  *
595  * For example, regardless of the principal being impersonated, if the
596  * 'client' and 'server' are the same, then it's safe.
597  */
598 
599 static krb5_error_code
600 check_s4u2self(krb5_context context,
601 	       krb5_kdc_configuration *config,
602 	       HDB *clientdb,
603 	       hdb_entry_ex *client,
604 	       krb5_const_principal server)
605 {
606     krb5_error_code ret;
607 
608     /* if client does a s4u2self to itself, that ok */
609     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
610 	return 0;
611 
612     if (clientdb->hdb_check_s4u2self) {
613 	ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
614 	if (ret == 0)
615 	    return 0;
616     } else {
617 	ret = KRB5KDC_ERR_BADOPTION;
618     }
619     return ret;
620 }
621 
622 /*
623  *
624  */
625 
626 static krb5_error_code
627 verify_flags (krb5_context context,
628 	      krb5_kdc_configuration *config,
629 	      const EncTicketPart *et,
630 	      const char *pstr)
631 {
632     if(et->endtime < kdc_time){
633 	kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
634 	return KRB5KRB_AP_ERR_TKT_EXPIRED;
635     }
636     if(et->flags.invalid){
637 	kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
638 	return KRB5KRB_AP_ERR_TKT_NYV;
639     }
640     return 0;
641 }
642 
643 /*
644  *
645  */
646 
647 static krb5_error_code
648 fix_transited_encoding(krb5_context context,
649 		       krb5_kdc_configuration *config,
650 		       krb5_boolean check_policy,
651 		       const TransitedEncoding *tr,
652 		       EncTicketPart *et,
653 		       const char *client_realm,
654 		       const char *server_realm,
655 		       const char *tgt_realm)
656 {
657     krb5_error_code ret = 0;
658     char **realms, **tmp;
659     unsigned int num_realms;
660     size_t i;
661 
662     switch (tr->tr_type) {
663     case DOMAIN_X500_COMPRESS:
664 	break;
665     case 0:
666 	/*
667 	 * Allow empty content of type 0 because that is was Microsoft
668 	 * generates in their TGT.
669 	 */
670 	if (tr->contents.length == 0)
671 	    break;
672 	kdc_log(context, config, 0,
673 		"Transited type 0 with non empty content");
674 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
675     default:
676 	kdc_log(context, config, 0,
677 		"Unknown transited type: %u", tr->tr_type);
678 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
679     }
680 
681     ret = krb5_domain_x500_decode(context,
682 				  tr->contents,
683 				  &realms,
684 				  &num_realms,
685 				  client_realm,
686 				  server_realm);
687     if(ret){
688 	krb5_warn(context, ret,
689 		  "Decoding transited encoding");
690 	return ret;
691     }
692 
693     /*
694      * If the realm of the presented tgt is neither the client nor the server
695      * realm, it is a transit realm and must be added to transited set.
696      */
697     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
698 	if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
699 	    ret = ERANGE;
700 	    goto free_realms;
701 	}
702 	tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
703 	if(tmp == NULL){
704 	    ret = ENOMEM;
705 	    goto free_realms;
706 	}
707 	realms = tmp;
708 	realms[num_realms] = strdup(tgt_realm);
709 	if(realms[num_realms] == NULL){
710 	    ret = ENOMEM;
711 	    goto free_realms;
712 	}
713 	num_realms++;
714     }
715     if(num_realms == 0) {
716 	if(strcmp(client_realm, server_realm))
717 	    kdc_log(context, config, 0,
718 		    "cross-realm %s -> %s", client_realm, server_realm);
719     } else {
720 	size_t l = 0;
721 	char *rs;
722 	for(i = 0; i < num_realms; i++)
723 	    l += strlen(realms[i]) + 2;
724 	rs = malloc(l);
725 	if(rs != NULL) {
726 	    *rs = '\0';
727 	    for(i = 0; i < num_realms; i++) {
728 		if(i > 0)
729 		    strlcat(rs, ", ", l);
730 		strlcat(rs, realms[i], l);
731 	    }
732 	    kdc_log(context, config, 0,
733 		    "cross-realm %s -> %s via [%s]",
734 		    client_realm, server_realm, rs);
735 	    free(rs);
736 	}
737     }
738     if(check_policy) {
739 	ret = krb5_check_transited(context, client_realm,
740 				   server_realm,
741 				   realms, num_realms, NULL);
742 	if(ret) {
743 	    krb5_warn(context, ret, "cross-realm %s -> %s",
744 		      client_realm, server_realm);
745 	    goto free_realms;
746 	}
747 	et->flags.transited_policy_checked = 1;
748     }
749     et->transited.tr_type = DOMAIN_X500_COMPRESS;
750     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
751     if(ret)
752 	krb5_warn(context, ret, "Encoding transited encoding");
753   free_realms:
754     for(i = 0; i < num_realms; i++)
755 	free(realms[i]);
756     free(realms);
757     return ret;
758 }
759 
760 
761 static krb5_error_code
762 tgs_make_reply(krb5_context context,
763 	       krb5_kdc_configuration *config,
764 	       KDC_REQ_BODY *b,
765 	       krb5_const_principal tgt_name,
766 	       const EncTicketPart *tgt,
767 	       const krb5_keyblock *replykey,
768 	       int rk_is_subkey,
769 	       const EncryptionKey *serverkey,
770 	       const krb5_keyblock *sessionkey,
771 	       krb5_kvno kvno,
772 	       AuthorizationData *auth_data,
773 	       hdb_entry_ex *server,
774 	       krb5_principal server_principal,
775 	       const char *server_name,
776 	       hdb_entry_ex *client,
777 	       krb5_principal client_principal,
778                const char *tgt_realm,
779 	       hdb_entry_ex *krbtgt,
780 	       krb5_enctype krbtgt_etype,
781 	       krb5_principals spp,
782 	       const krb5_data *rspac,
783 	       const METHOD_DATA *enc_pa_data,
784 	       const char **e_text,
785 	       krb5_data *reply)
786 {
787     KDC_REP rep;
788     EncKDCRepPart ek;
789     EncTicketPart et;
790     KDCOptions f = b->kdc_options;
791     krb5_error_code ret;
792     int is_weak = 0;
793 
794     memset(&rep, 0, sizeof(rep));
795     memset(&et, 0, sizeof(et));
796     memset(&ek, 0, sizeof(ek));
797 
798     rep.pvno = 5;
799     rep.msg_type = krb_tgs_rep;
800 
801     et.authtime = tgt->authtime;
802     _kdc_fix_time(&b->till);
803     et.endtime = min(tgt->endtime, *b->till);
804     ALLOC(et.starttime);
805     *et.starttime = kdc_time;
806 
807     ret = check_tgs_flags(context, config, b, tgt_name, tgt, &et);
808     if(ret)
809 	goto out;
810 
811     /* We should check the transited encoding if:
812        1) the request doesn't ask not to be checked
813        2) globally enforcing a check
814        3) principal requires checking
815        4) we allow non-check per-principal, but principal isn't marked as allowing this
816        5) we don't globally allow this
817     */
818 
819 #define GLOBAL_FORCE_TRANSITED_CHECK		\
820     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
821 #define GLOBAL_ALLOW_PER_PRINCIPAL			\
822     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
823 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK			\
824     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
825 
826 /* these will consult the database in future release */
827 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)		0
828 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)	0
829 
830     ret = fix_transited_encoding(context, config,
831 				 !f.disable_transited_check ||
832 				 GLOBAL_FORCE_TRANSITED_CHECK ||
833 				 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
834 				 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
835 				    PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
836 				   GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
837 				 &tgt->transited, &et,
838 				 krb5_principal_get_realm(context, client_principal),
839 				 krb5_principal_get_realm(context, server->entry.principal),
840 				 tgt_realm);
841     if(ret)
842 	goto out;
843 
844     ret = copy_Realm(&server_principal->realm, &rep.ticket.realm);
845     if (ret)
846 	goto out;
847     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
848     ret = copy_Realm(&tgt_name->realm, &rep.crealm);
849     if (ret)
850 	goto out;
851 
852     /*
853      * RFC 8062 states "if the ticket in the TGS request is an anonymous
854      * one, the client and client realm are copied from that ticket". So
855      * whilst the TGT flag check below is superfluous, it is included in
856      * order to follow the specification to its letter.
857      */
858     if (et.flags.anonymous && !tgt->flags.anonymous)
859 	_kdc_make_anonymous_principalname(&rep.cname);
860     else
861 	ret = copy_PrincipalName(&tgt_name->name, &rep.cname);
862     if (ret)
863 	goto out;
864     rep.ticket.tkt_vno = 5;
865 
866     ek.caddr = et.caddr;
867 
868     {
869 	time_t life;
870 	life = et.endtime - *et.starttime;
871 	if(client && client->entry.max_life)
872 	    life = min(life, *client->entry.max_life);
873 	if(server->entry.max_life)
874 	    life = min(life, *server->entry.max_life);
875 	et.endtime = *et.starttime + life;
876     }
877     if(f.renewable_ok && tgt->flags.renewable &&
878        et.renew_till == NULL && et.endtime < *b->till &&
879        tgt->renew_till != NULL)
880     {
881 	et.flags.renewable = 1;
882 	ALLOC(et.renew_till);
883 	*et.renew_till = *b->till;
884     }
885     if(et.renew_till){
886 	time_t renew;
887 	renew = *et.renew_till - *et.starttime;
888 	if(client && client->entry.max_renew)
889 	    renew = min(renew, *client->entry.max_renew);
890 	if(server->entry.max_renew)
891 	    renew = min(renew, *server->entry.max_renew);
892 	*et.renew_till = *et.starttime + renew;
893     }
894 
895     if(et.renew_till){
896 	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
897 	*et.starttime = min(*et.starttime, *et.renew_till);
898 	et.endtime = min(et.endtime, *et.renew_till);
899     }
900 
901     *et.starttime = min(*et.starttime, et.endtime);
902 
903     if(*et.starttime == et.endtime){
904 	ret = KRB5KDC_ERR_NEVER_VALID;
905 	goto out;
906     }
907     if(et.renew_till && et.endtime == *et.renew_till){
908 	free(et.renew_till);
909 	et.renew_till = NULL;
910 	et.flags.renewable = 0;
911     }
912 
913     et.flags.pre_authent = tgt->flags.pre_authent;
914     et.flags.hw_authent  = tgt->flags.hw_authent;
915     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
916 
917     /*
918      * For anonymous tickets, we should filter out positive authorization data
919      * that could reveal the client's identity, and return a policy error for
920      * restrictive authorization data. Policy for unknown authorization types
921      * is implementation dependent.
922      */
923     if (rspac->length && !et.flags.anonymous) {
924 	/*
925 	 * No not need to filter out the any PAC from the
926 	 * auth_data since it's signed by the KDC.
927 	 */
928 	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
929 					  KRB5_AUTHDATA_WIN2K_PAC, rspac);
930 	if (ret)
931 	    goto out;
932     }
933 
934     if (auth_data) {
935 	unsigned int i = 0;
936 
937 	/* XXX check authdata */
938 
939 	if (et.authorization_data == NULL) {
940 	    et.authorization_data = calloc(1, sizeof(*et.authorization_data));
941 	    if (et.authorization_data == NULL) {
942 		ret = ENOMEM;
943 		krb5_set_error_message(context, ret, "malloc: out of memory");
944 		goto out;
945 	    }
946 	}
947 	for(i = 0; i < auth_data->len ; i++) {
948 	    ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
949 	    if (ret) {
950 		krb5_set_error_message(context, ret, "malloc: out of memory");
951 		goto out;
952 	    }
953 	}
954 
955 	/* Filter out type KRB5SignedPath */
956 	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
957 	if (ret == 0) {
958 	    if (et.authorization_data->len == 1) {
959 		free_AuthorizationData(et.authorization_data);
960 		free(et.authorization_data);
961 		et.authorization_data = NULL;
962 	    } else {
963 		AuthorizationData *ad = et.authorization_data;
964 		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
965 		ad->len--;
966 	    }
967 	}
968     }
969 
970     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
971     if (ret)
972 	goto out;
973     et.crealm = rep.crealm;
974     et.cname = rep.cname;
975 
976     ek.key = et.key;
977     /* MIT must have at least one last_req */
978     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
979     if (ek.last_req.val == NULL) {
980 	ret = ENOMEM;
981 	goto out;
982     }
983     ek.last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
984     ek.nonce = b->nonce;
985     ek.flags = et.flags;
986     ek.authtime = et.authtime;
987     ek.starttime = et.starttime;
988     ek.endtime = et.endtime;
989     ek.renew_till = et.renew_till;
990     ek.srealm = rep.ticket.realm;
991     ek.sname = rep.ticket.sname;
992 
993     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
994 		       et.endtime, et.renew_till);
995 
996     /* Don't sign cross realm tickets, they can't be checked anyway */
997     {
998 	char *r = get_krbtgt_realm(&ek.sname);
999 
1000 	if (r == NULL || strcmp(r, ek.srealm) == 0) {
1001 	    ret = _kdc_add_KRB5SignedPath(context,
1002 					  config,
1003 					  krbtgt,
1004 					  krbtgt_etype,
1005 					  client_principal,
1006 					  NULL,
1007 					  spp,
1008 					  &et);
1009 	    if (ret)
1010 		goto out;
1011 	}
1012     }
1013 
1014     if (enc_pa_data->len) {
1015 	rep.padata = calloc(1, sizeof(*rep.padata));
1016 	if (rep.padata == NULL) {
1017 	    ret = ENOMEM;
1018 	    goto out;
1019 	}
1020 	ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
1021 	if (ret)
1022 	    goto out;
1023     }
1024 
1025     if (krb5_enctype_valid(context, serverkey->keytype) != 0
1026 	&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
1027     {
1028 	krb5_enctype_enable(context, serverkey->keytype);
1029 	is_weak = 1;
1030     }
1031 
1032 
1033     /* It is somewhat unclear where the etype in the following
1034        encryption should come from. What we have is a session
1035        key in the passed tgt, and a list of preferred etypes
1036        *for the new ticket*. Should we pick the best possible
1037        etype, given the keytype in the tgt, or should we look
1038        at the etype list here as well?  What if the tgt
1039        session key is DES3 and we want a ticket with a (say)
1040        CAST session key. Should the DES3 etype be added to the
1041        etype list, even if we don't want a session key with
1042        DES3? */
1043     ret = _kdc_encode_reply(context, config, NULL, 0,
1044 			    &rep, &et, &ek, serverkey->keytype,
1045 			    kvno,
1046 			    serverkey, 0, replykey, rk_is_subkey,
1047 			    e_text, reply);
1048     if (is_weak)
1049 	krb5_enctype_disable(context, serverkey->keytype);
1050 
1051 out:
1052     free_TGS_REP(&rep);
1053     free_TransitedEncoding(&et.transited);
1054     if(et.starttime)
1055 	free(et.starttime);
1056     if(et.renew_till)
1057 	free(et.renew_till);
1058     if(et.authorization_data) {
1059 	free_AuthorizationData(et.authorization_data);
1060 	free(et.authorization_data);
1061     }
1062     free_LastReq(&ek.last_req);
1063     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1064     free_EncryptionKey(&et.key);
1065     return ret;
1066 }
1067 
1068 static krb5_error_code
1069 tgs_check_authenticator(krb5_context context,
1070 			krb5_kdc_configuration *config,
1071 	                krb5_auth_context ac,
1072 			KDC_REQ_BODY *b,
1073 			const char **e_text,
1074 			krb5_keyblock *key)
1075 {
1076     krb5_authenticator auth;
1077     size_t len = 0;
1078     unsigned char *buf;
1079     size_t buf_size;
1080     krb5_error_code ret;
1081     krb5_crypto crypto;
1082 
1083     krb5_auth_con_getauthenticator(context, ac, &auth);
1084     if(auth->cksum == NULL){
1085 	kdc_log(context, config, 0, "No authenticator in request");
1086 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1087 	goto out;
1088     }
1089     /*
1090      * according to RFC1510 it doesn't need to be keyed,
1091      * but according to the latest draft it needs to.
1092      */
1093     if (
1094 #if 0
1095 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1096 	||
1097 #endif
1098  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1099 	kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1100 		auth->cksum->cksumtype);
1101 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1102 	goto out;
1103     }
1104 
1105     /* XXX should not re-encode this */
1106     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1107     if(ret){
1108 	const char *msg = krb5_get_error_message(context, ret);
1109 	kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1110 	krb5_free_error_message(context, msg);
1111 	goto out;
1112     }
1113     if(buf_size != len) {
1114 	free(buf);
1115 	kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1116 	*e_text = "KDC internal error";
1117 	ret = KRB5KRB_ERR_GENERIC;
1118 	goto out;
1119     }
1120     ret = krb5_crypto_init(context, key, 0, &crypto);
1121     if (ret) {
1122 	const char *msg = krb5_get_error_message(context, ret);
1123 	free(buf);
1124 	kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1125 	krb5_free_error_message(context, msg);
1126 	goto out;
1127     }
1128     ret = krb5_verify_checksum(context,
1129 			       crypto,
1130 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
1131 			       buf,
1132 			       len,
1133 			       auth->cksum);
1134     free(buf);
1135     krb5_crypto_destroy(context, crypto);
1136     if(ret){
1137 	const char *msg = krb5_get_error_message(context, ret);
1138 	kdc_log(context, config, 0,
1139 		"Failed to verify authenticator checksum: %s", msg);
1140 	krb5_free_error_message(context, msg);
1141     }
1142 out:
1143     free_Authenticator(auth);
1144     free(auth);
1145     return ret;
1146 }
1147 
1148 static krb5_boolean
1149 need_referral(krb5_context context, krb5_kdc_configuration *config,
1150 	      const KDCOptions * const options, krb5_principal server,
1151 	      krb5_realm **realms)
1152 {
1153     const char *name;
1154 
1155     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1156 	return FALSE;
1157 
1158     if (server->name.name_string.len == 1)
1159 	name = server->name.name_string.val[0];
1160     else if (server->name.name_string.len == 3) {
1161 	/*
1162 	  This is used to give referrals for the
1163 	  E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
1164 	  SPN form, which is used for inter-domain communication in AD
1165 	 */
1166 	name = server->name.name_string.val[2];
1167 	kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
1168 	*realms = malloc(sizeof(char *)*2);
1169 	if (*realms == NULL) {
1170 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1171 	    return FALSE;
1172 	}
1173 	(*realms)[0] = strdup(name);
1174 	(*realms)[1] = NULL;
1175 	return TRUE;
1176     } else if (server->name.name_string.len > 1)
1177 	name = server->name.name_string.val[1];
1178     else
1179 	return FALSE;
1180 
1181     kdc_log(context, config, 0, "Searching referral for %s", name);
1182 
1183     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1184 }
1185 
1186 static krb5_error_code
1187 tgs_parse_request(krb5_context context,
1188 		  krb5_kdc_configuration *config,
1189 		  KDC_REQ_BODY *b,
1190 		  const PA_DATA *tgs_req,
1191 		  hdb_entry_ex **krbtgt,
1192 		  krb5_enctype *krbtgt_etype,
1193 		  krb5_ticket **ticket,
1194 		  const char **e_text,
1195 		  const char *from,
1196 		  const struct sockaddr *from_addr,
1197 		  time_t **csec,
1198 		  int **cusec,
1199 		  AuthorizationData **auth_data,
1200 		  krb5_keyblock **replykey,
1201 		  int *rk_is_subkey)
1202 {
1203     static char failed[] = "<unparse_name failed>";
1204     krb5_ap_req ap_req;
1205     krb5_error_code ret;
1206     krb5_principal princ;
1207     krb5_auth_context ac = NULL;
1208     krb5_flags ap_req_options;
1209     krb5_flags verify_ap_req_flags;
1210     krb5_crypto crypto;
1211     krb5uint32 krbtgt_kvno;     /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1212     krb5uint32 krbtgt_kvno_try;
1213     int kvno_search_tries = 4;  /* number of kvnos to try when tkt_vno == 0 */
1214     const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1215     Key *tkey;
1216     krb5_keyblock *subkey = NULL;
1217     unsigned usage;
1218 
1219     *auth_data = NULL;
1220     *csec  = NULL;
1221     *cusec = NULL;
1222     *replykey = NULL;
1223 
1224     memset(&ap_req, 0, sizeof(ap_req));
1225     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1226     if(ret){
1227 	const char *msg = krb5_get_error_message(context, ret);
1228 	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1229 	krb5_free_error_message(context, msg);
1230 	goto out;
1231     }
1232 
1233     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1234 	/* XXX check for ticket.sname == req.sname */
1235 	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1236 	ret = KRB5KDC_ERR_POLICY; /* ? */
1237 	goto out;
1238     }
1239 
1240     _krb5_principalname2krb5_principal(context,
1241 				       &princ,
1242 				       ap_req.ticket.sname,
1243 				       ap_req.ticket.realm);
1244 
1245     krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1246     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
1247 			&krbtgt_kvno, NULL, krbtgt);
1248 
1249     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1250 	/* XXX Factor out this unparsing of the same princ all over */
1251 	char *p;
1252 	ret = krb5_unparse_name(context, princ, &p);
1253 	if (ret != 0)
1254 	    p = failed;
1255 	krb5_free_principal(context, princ);
1256 	kdc_log(context, config, 5,
1257 		"Ticket-granting ticket account %s does not have secrets at "
1258 		"this KDC, need to proxy", p);
1259 	if (ret == 0)
1260 	    free(p);
1261 	ret = HDB_ERR_NOT_FOUND_HERE;
1262 	goto out;
1263     } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1264 	char *p;
1265 	ret = krb5_unparse_name(context, princ, &p);
1266 	if (ret != 0)
1267 	    p = failed;
1268 	krb5_free_principal(context, princ);
1269 	kdc_log(context, config, 5,
1270 		"Ticket-granting ticket account %s does not have keys for "
1271 		"kvno %d at this KDC", p, krbtgt_kvno);
1272 	if (ret == 0)
1273 	    free(p);
1274 	ret = HDB_ERR_KVNO_NOT_FOUND;
1275 	goto out;
1276     } else if (ret == HDB_ERR_NO_MKEY) {
1277 	char *p;
1278 	ret = krb5_unparse_name(context, princ, &p);
1279 	if (ret != 0)
1280 	    p = failed;
1281 	krb5_free_principal(context, princ);
1282 	kdc_log(context, config, 5,
1283 		"Missing master key for decrypting keys for ticket-granting "
1284 		"ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1285 	if (ret == 0)
1286 	    free(p);
1287 	ret = HDB_ERR_KVNO_NOT_FOUND;
1288 	goto out;
1289     } else if (ret) {
1290 	const char *msg = krb5_get_error_message(context, ret);
1291 	char *p;
1292 	ret = krb5_unparse_name(context, princ, &p);
1293 	if (ret != 0)
1294 	    p = failed;
1295 	krb5_free_principal(context, princ);
1296 	kdc_log(context, config, 0,
1297 		"Ticket-granting ticket not found in database: %s", msg);
1298 	krb5_free_error_message(context, msg);
1299 	if (ret == 0)
1300 	    free(p);
1301 	ret = KRB5KRB_AP_ERR_NOT_US;
1302 	goto out;
1303     }
1304 
1305     krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1306     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1307 
1308 next_kvno:
1309     krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
1310     ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
1311 			  ap_req.ticket.enc_part.etype, &tkey);
1312     if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1313 	kvno_search_tries--;
1314 	krbtgt_kvno_try--;
1315 	goto next_kvno;
1316     } else if (ret) {
1317 	char *str = NULL, *p = NULL;
1318 
1319 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1320 	krb5_unparse_name(context, princ, &p);
1321  	kdc_log(context, config, 0,
1322 		"No server key with enctype %s found for %s",
1323 		str ? str : "<unknown enctype>",
1324 		p ? p : "<unparse_name failed>");
1325 	free(str);
1326 	free(p);
1327 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1328 	goto out;
1329     }
1330 
1331     if (b->kdc_options.validate)
1332 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1333     else
1334 	verify_ap_req_flags = 0;
1335 
1336     ret = krb5_verify_ap_req2(context,
1337 			      &ac,
1338 			      &ap_req,
1339 			      princ,
1340 			      &tkey->key,
1341 			      verify_ap_req_flags,
1342 			      &ap_req_options,
1343 			      ticket,
1344 			      KRB5_KU_TGS_REQ_AUTH);
1345     if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1346 	kvno_search_tries--;
1347 	krbtgt_kvno_try--;
1348 	goto next_kvno;
1349     }
1350 
1351     krb5_free_principal(context, princ);
1352     if(ret) {
1353 	const char *msg = krb5_get_error_message(context, ret);
1354 	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1355 	krb5_free_error_message(context, msg);
1356 	goto out;
1357     }
1358 
1359     {
1360 	krb5_authenticator auth;
1361 
1362 	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1363 	if (ret == 0) {
1364 	    *csec   = malloc(sizeof(**csec));
1365 	    if (*csec == NULL) {
1366 		krb5_free_authenticator(context, &auth);
1367 		kdc_log(context, config, 0, "malloc failed");
1368 		goto out;
1369 	    }
1370 	    **csec  = auth->ctime;
1371 	    *cusec  = malloc(sizeof(**cusec));
1372 	    if (*cusec == NULL) {
1373 		krb5_free_authenticator(context, &auth);
1374 		kdc_log(context, config, 0, "malloc failed");
1375 		goto out;
1376 	    }
1377 	    **cusec  = auth->cusec;
1378 	    krb5_free_authenticator(context, &auth);
1379 	}
1380     }
1381 
1382     ret = tgs_check_authenticator(context, config,
1383 				  ac, b, e_text, &(*ticket)->ticket.key);
1384     if (ret) {
1385 	krb5_auth_con_free(context, ac);
1386 	goto out;
1387     }
1388 
1389     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1390     *rk_is_subkey = 1;
1391 
1392     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1393     if(ret){
1394 	const char *msg = krb5_get_error_message(context, ret);
1395 	krb5_auth_con_free(context, ac);
1396 	kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1397 	krb5_free_error_message(context, msg);
1398 	goto out;
1399     }
1400     if(subkey == NULL){
1401 	usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1402 	*rk_is_subkey = 0;
1403 
1404 	ret = krb5_auth_con_getkey(context, ac, &subkey);
1405 	if(ret) {
1406 	    const char *msg = krb5_get_error_message(context, ret);
1407 	    krb5_auth_con_free(context, ac);
1408 	    kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1409 	    krb5_free_error_message(context, msg);
1410 	    goto out;
1411 	}
1412     }
1413     if(subkey == NULL){
1414 	krb5_auth_con_free(context, ac);
1415 	kdc_log(context, config, 0,
1416 		"Failed to get key for enc-authorization-data");
1417 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1418 	goto out;
1419     }
1420 
1421     *replykey = subkey;
1422 
1423     if (b->enc_authorization_data) {
1424 	krb5_data ad;
1425 
1426 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
1427 	if (ret) {
1428 	    const char *msg = krb5_get_error_message(context, ret);
1429 	    krb5_auth_con_free(context, ac);
1430 	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1431 	    krb5_free_error_message(context, msg);
1432 	    goto out;
1433 	}
1434 	ret = krb5_decrypt_EncryptedData (context,
1435 					  crypto,
1436 					  usage,
1437 					  b->enc_authorization_data,
1438 					  &ad);
1439 	krb5_crypto_destroy(context, crypto);
1440 	if(ret){
1441 	    krb5_auth_con_free(context, ac);
1442 	    kdc_log(context, config, 0,
1443 		    "Failed to decrypt enc-authorization-data");
1444 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1445 	    goto out;
1446 	}
1447 	ALLOC(*auth_data);
1448 	if (*auth_data == NULL) {
1449 	    krb5_auth_con_free(context, ac);
1450 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1451 	    goto out;
1452 	}
1453 	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1454 	if(ret){
1455 	    krb5_auth_con_free(context, ac);
1456 	    free(*auth_data);
1457 	    *auth_data = NULL;
1458 	    kdc_log(context, config, 0, "Failed to decode authorization data");
1459 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1460 	    goto out;
1461 	}
1462     }
1463 
1464     krb5_auth_con_free(context, ac);
1465 
1466 out:
1467     free_AP_REQ(&ap_req);
1468 
1469     return ret;
1470 }
1471 
1472 static krb5_error_code
1473 build_server_referral(krb5_context context,
1474 		      krb5_kdc_configuration *config,
1475 		      krb5_crypto session,
1476 		      krb5_const_realm referred_realm,
1477 		      const PrincipalName *true_principal_name,
1478 		      const PrincipalName *requested_principal,
1479 		      krb5_data *outdata)
1480 {
1481     PA_ServerReferralData ref;
1482     krb5_error_code ret;
1483     EncryptedData ed;
1484     krb5_data data;
1485     size_t size = 0;
1486 
1487     memset(&ref, 0, sizeof(ref));
1488 
1489     if (referred_realm) {
1490 	ALLOC(ref.referred_realm);
1491 	if (ref.referred_realm == NULL)
1492 	    goto eout;
1493 	*ref.referred_realm = strdup(referred_realm);
1494 	if (*ref.referred_realm == NULL)
1495 	    goto eout;
1496     }
1497     if (true_principal_name) {
1498 	ALLOC(ref.true_principal_name);
1499 	if (ref.true_principal_name == NULL)
1500 	    goto eout;
1501 	ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1502 	if (ret)
1503 	    goto eout;
1504     }
1505     if (requested_principal) {
1506 	ALLOC(ref.requested_principal_name);
1507 	if (ref.requested_principal_name == NULL)
1508 	    goto eout;
1509 	ret = copy_PrincipalName(requested_principal,
1510 				 ref.requested_principal_name);
1511 	if (ret)
1512 	    goto eout;
1513     }
1514 
1515     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1516 		       data.data, data.length,
1517 		       &ref, &size, ret);
1518     free_PA_ServerReferralData(&ref);
1519     if (ret)
1520 	return ret;
1521     if (data.length != size)
1522 	krb5_abortx(context, "internal asn.1 encoder error");
1523 
1524     ret = krb5_encrypt_EncryptedData(context, session,
1525 				     KRB5_KU_PA_SERVER_REFERRAL,
1526 				     data.data, data.length,
1527 				     0 /* kvno */, &ed);
1528     free(data.data);
1529     if (ret)
1530 	return ret;
1531 
1532     ASN1_MALLOC_ENCODE(EncryptedData,
1533 		       outdata->data, outdata->length,
1534 		       &ed, &size, ret);
1535     free_EncryptedData(&ed);
1536     if (ret)
1537 	return ret;
1538     if (outdata->length != size)
1539 	krb5_abortx(context, "internal asn.1 encoder error");
1540 
1541     return 0;
1542 eout:
1543     free_PA_ServerReferralData(&ref);
1544     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1545     return ENOMEM;
1546 }
1547 
1548 static krb5_error_code
1549 tgs_build_reply(krb5_context context,
1550 		krb5_kdc_configuration *config,
1551 		KDC_REQ *req,
1552 		KDC_REQ_BODY *b,
1553 		hdb_entry_ex *krbtgt,
1554 		krb5_enctype krbtgt_etype,
1555 		const krb5_keyblock *replykey,
1556 		int rk_is_subkey,
1557 		krb5_ticket *ticket,
1558 		krb5_data *reply,
1559 		const char *from,
1560 		const char **e_text,
1561 		AuthorizationData **auth_data,
1562 		const struct sockaddr *from_addr)
1563 {
1564     krb5_error_code ret, ret2;
1565     krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1566     krb5_principal krbtgt_out_principal = NULL;
1567     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1568     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1569     HDB *clientdb, *s4u2self_impersonated_clientdb;
1570     krb5_realm ref_realm = NULL;
1571     EncTicketPart *tgt = &ticket->ticket;
1572     krb5_principals spp = NULL;
1573     const EncryptionKey *ekey;
1574     krb5_keyblock sessionkey;
1575     krb5_kvno kvno;
1576     krb5_data rspac;
1577     const char *tgt_realm = /* Realm of TGT issuer */
1578         krb5_principal_get_realm(context, krbtgt->entry.principal);
1579     const char *our_realm = /* Realm of this KDC */
1580         krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1581     char **capath = NULL;
1582     size_t num_capath = 0;
1583 
1584     hdb_entry_ex *krbtgt_out = NULL;
1585 
1586     METHOD_DATA enc_pa_data;
1587 
1588     PrincipalName *s;
1589     Realm r;
1590     EncTicketPart adtkt;
1591     char opt_str[128];
1592     int signedpath = 0;
1593 
1594     Key *tkey_check;
1595     Key *tkey_sign;
1596     int flags = HDB_F_FOR_TGS_REQ;
1597 
1598     memset(&sessionkey, 0, sizeof(sessionkey));
1599     memset(&adtkt, 0, sizeof(adtkt));
1600     krb5_data_zero(&rspac);
1601     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1602 
1603     s = b->sname;
1604     r = b->realm;
1605 
1606     /*
1607      * Always to do CANON, see comment below about returned server principal (rsp).
1608      */
1609     flags |= HDB_F_CANON;
1610 
1611     if(b->kdc_options.enc_tkt_in_skey){
1612 	Ticket *t;
1613 	hdb_entry_ex *uu;
1614 	krb5_principal p;
1615 	Key *uukey;
1616 	krb5uint32 second_kvno = 0;
1617 	krb5uint32 *kvno_ptr = NULL;
1618 
1619 	if(b->additional_tickets == NULL ||
1620 	   b->additional_tickets->len == 0){
1621 	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
1622 	    kdc_log(context, config, 0,
1623 		    "No second ticket present in request");
1624 	    goto out;
1625 	}
1626 	t = &b->additional_tickets->val[0];
1627 	if(!get_krbtgt_realm(&t->sname)){
1628 	    kdc_log(context, config, 0,
1629 		    "Additional ticket is not a ticket-granting ticket");
1630 	    ret = KRB5KDC_ERR_POLICY;
1631 	    goto out;
1632 	}
1633 	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1634 	if(t->enc_part.kvno){
1635 	    second_kvno = *t->enc_part.kvno;
1636 	    kvno_ptr = &second_kvno;
1637 	}
1638 	ret = _kdc_db_fetch(context, config, p,
1639 			    HDB_F_GET_KRBTGT, kvno_ptr,
1640 			    NULL, &uu);
1641 	krb5_free_principal(context, p);
1642 	if(ret){
1643 	    if (ret == HDB_ERR_NOENTRY)
1644 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1645 	    goto out;
1646 	}
1647 	ret = hdb_enctype2key(context, &uu->entry, NULL,
1648 			      t->enc_part.etype, &uukey);
1649 	if(ret){
1650 	    _kdc_free_ent(context, uu);
1651 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1652 	    goto out;
1653 	}
1654 	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1655 	_kdc_free_ent(context, uu);
1656 	if(ret)
1657 	    goto out;
1658 
1659 	ret = verify_flags(context, config, &adtkt, spn);
1660 	if (ret)
1661 	    goto out;
1662 
1663 	s = &adtkt.cname;
1664 	r = adtkt.crealm;
1665     }
1666 
1667     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1668     ret = krb5_unparse_name(context, sp, &spn);
1669     if (ret)
1670 	goto out;
1671     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1672     ret = krb5_unparse_name(context, cp, &cpn);
1673     if (ret)
1674 	goto out;
1675     unparse_flags (KDCOptions2int(b->kdc_options),
1676 		   asn1_KDCOptions_units(),
1677 		   opt_str, sizeof(opt_str));
1678     if(*opt_str)
1679 	kdc_log(context, config, 0,
1680 		"TGS-REQ %s from %s for %s [%s]",
1681 		cpn, from, spn, opt_str);
1682     else
1683 	kdc_log(context, config, 0,
1684 		"TGS-REQ %s from %s for %s", cpn, from, spn);
1685 
1686     /*
1687      * Fetch server
1688      */
1689 
1690 server_lookup:
1691     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1692 			NULL, NULL, &server);
1693 
1694     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1695 	kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1696 	goto out;
1697     } else if (ret == HDB_ERR_WRONG_REALM) {
1698         free(ref_realm);
1699 	ref_realm = strdup(server->entry.principal->realm);
1700 	if (ref_realm == NULL) {
1701             ret = krb5_enomem(context);
1702 	    goto out;
1703 	}
1704 
1705 	kdc_log(context, config, 5,
1706 		"Returning a referral to realm %s for "
1707 		"server %s.",
1708 		ref_realm, spn);
1709 	krb5_free_principal(context, sp);
1710 	sp = NULL;
1711 	ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1712 				  ref_realm, NULL);
1713 	if (ret)
1714 	    goto out;
1715 	free(spn);
1716         spn = NULL;
1717 	ret = krb5_unparse_name(context, sp, &spn);
1718 	if (ret)
1719 	    goto out;
1720 
1721 	goto server_lookup;
1722     } else if (ret) {
1723 	const char *new_rlm, *msg;
1724 	Realm req_rlm;
1725 	krb5_realm *realms;
1726 
1727 	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1728             if (capath == NULL) {
1729                 /* With referalls, hierarchical capaths are always enabled */
1730                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1731                                          req_rlm, TRUE, &capath, &num_capath);
1732                 if (ret2) {
1733                     ret = ret2;
1734                     goto out;
1735                 }
1736             }
1737             new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1738             if (new_rlm) {
1739                 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1740                         "realm %s not found, trying %s", tgt->crealm,
1741                         our_realm, req_rlm, new_rlm);
1742 
1743                 free(ref_realm);
1744                 ref_realm = strdup(new_rlm);
1745                 if (ref_realm == NULL) {
1746                     ret = krb5_enomem(context);
1747                     goto out;
1748                 }
1749 
1750                 krb5_free_principal(context, sp);
1751                 sp = NULL;
1752                 krb5_make_principal(context, &sp, r,
1753                                     KRB5_TGS_NAME, ref_realm, NULL);
1754                 free(spn);
1755                 spn = NULL;
1756                 ret = krb5_unparse_name(context, sp, &spn);
1757                 if (ret)
1758                     goto out;
1759                 goto server_lookup;
1760             }
1761 	} else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
1762 	    if (strcmp(realms[0], sp->realm) != 0) {
1763 		kdc_log(context, config, 5,
1764 			"Returning a referral to realm %s for "
1765 			"server %s that was not found",
1766 			realms[0], spn);
1767 		krb5_free_principal(context, sp);
1768                 sp = NULL;
1769 		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1770 				    realms[0], NULL);
1771 		free(spn);
1772                 spn = NULL;
1773 		ret = krb5_unparse_name(context, sp, &spn);
1774 		if (ret) {
1775 		    krb5_free_host_realm(context, realms);
1776 		    goto out;
1777 		}
1778 
1779                 free(ref_realm);
1780 		ref_realm = strdup(realms[0]);
1781 
1782 		krb5_free_host_realm(context, realms);
1783 		goto server_lookup;
1784 	    }
1785 	    krb5_free_host_realm(context, realms);
1786 	}
1787 	msg = krb5_get_error_message(context, ret);
1788 	kdc_log(context, config, 0,
1789 		"Server not found in database: %s: %s", spn, msg);
1790 	krb5_free_error_message(context, msg);
1791 	if (ret == HDB_ERR_NOENTRY)
1792 	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1793 	goto out;
1794     }
1795 
1796     /* the name returned to the client depend on what was asked for,
1797      * return canonical name if kdc_options.canonicalize was set, the
1798      * client wants the true name of the principal, if not it just
1799      * wants the name its asked for.
1800      */
1801 
1802     if (b->kdc_options.canonicalize)
1803 	rsp = server->entry.principal;
1804     else
1805 	rsp = sp;
1806 
1807 
1808     /*
1809      * Select enctype, return key and kvno.
1810      */
1811 
1812     {
1813 	krb5_enctype etype;
1814 
1815 	if(b->kdc_options.enc_tkt_in_skey) {
1816 	    size_t i;
1817 	    ekey = &adtkt.key;
1818 	    for(i = 0; i < b->etype.len; i++)
1819 		if (b->etype.val[i] == adtkt.key.keytype)
1820 		    break;
1821 	    if(i == b->etype.len) {
1822 		kdc_log(context, config, 0,
1823 			"Addition ticket have not matching etypes");
1824 		krb5_clear_error_message(context);
1825 		ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1826 		goto out;
1827 	    }
1828 	    etype = b->etype.val[i];
1829 	    kvno = 0;
1830 	} else {
1831 	    Key *skey;
1832 
1833 	    ret = _kdc_find_etype(context,
1834 				  krb5_principal_is_krbtgt(context, sp) ?
1835 				  config->tgt_use_strongest_session_key :
1836 				  config->svc_use_strongest_session_key, FALSE,
1837 				  server, b->etype.val, b->etype.len, &etype,
1838 				  NULL);
1839 	    if(ret) {
1840 		kdc_log(context, config, 0,
1841 			"Server (%s) has no support for etypes", spn);
1842 		goto out;
1843 	    }
1844 	    ret = _kdc_get_preferred_key(context, config, server, spn,
1845 					 NULL, &skey);
1846 	    if(ret) {
1847 		kdc_log(context, config, 0,
1848 			"Server (%s) has no supported etypes", spn);
1849 		goto out;
1850 	    }
1851 	    ekey = &skey->key;
1852 	    kvno = server->entry.kvno;
1853 	}
1854 
1855 	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1856 	if (ret)
1857 	    goto out;
1858     }
1859 
1860     /*
1861      * Check that service is in the same realm as the krbtgt. If it's
1862      * not the same, it's someone that is using a uni-directional trust
1863      * backward.
1864      */
1865 
1866     /*
1867      * Validate authoriation data
1868      */
1869 
1870     ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1871 			  krbtgt_etype, &tkey_check);
1872     if(ret) {
1873 	kdc_log(context, config, 0,
1874 		    "Failed to find key for krbtgt PAC check");
1875 	goto out;
1876     }
1877 
1878     /*
1879      * Now refetch the primary krbtgt, and get the current kvno (the
1880      * sign check may have been on an old kvno, and the server may
1881      * have been an incoming trust)
1882      */
1883 
1884     ret = krb5_make_principal(context,
1885                               &krbtgt_out_principal,
1886                               our_realm,
1887                               KRB5_TGS_NAME,
1888                               our_realm,
1889                               NULL);
1890     if (ret) {
1891         kdc_log(context, config, 0,
1892                 "Failed to make krbtgt principal name object for "
1893                 "authz-data signatures");
1894         goto out;
1895     }
1896     ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1897     if (ret) {
1898         kdc_log(context, config, 0,
1899                 "Failed to make krbtgt principal name object for "
1900                 "authz-data signatures");
1901         goto out;
1902     }
1903 
1904     ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1905 			HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1906     if (ret) {
1907 	char *ktpn = NULL;
1908 	ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1909 	kdc_log(context, config, 0,
1910 		"No such principal %s (needed for authz-data signature keys) "
1911 		"while processing TGS-REQ for service %s with krbtg %s",
1912 		krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1913 	free(ktpn);
1914 	ret = KRB5KRB_AP_ERR_NOT_US;
1915 	goto out;
1916     }
1917 
1918     /*
1919      * The first realm is the realm of the service, the second is
1920      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1921      * encrypted to.  The redirection via the krbtgt_out entry allows
1922      * the DB to possibly correct the case of the realm (Samba4 does
1923      * this) before the strcmp()
1924      */
1925     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1926 	       krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1927 	char *ktpn;
1928 	ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1929 	kdc_log(context, config, 0,
1930 		"Request with wrong krbtgt: %s",
1931 		(ret == 0) ? ktpn : "<unknown>");
1932 	if(ret == 0)
1933 	    free(ktpn);
1934 	ret = KRB5KRB_AP_ERR_NOT_US;
1935 	goto out;
1936     }
1937 
1938     ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1939 				 NULL, &tkey_sign);
1940     if (ret) {
1941 	kdc_log(context, config, 0,
1942 		    "Failed to find key for krbtgt PAC signature");
1943 	goto out;
1944     }
1945     ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1946 			  tkey_sign->key.keytype, &tkey_sign);
1947     if(ret) {
1948 	kdc_log(context, config, 0,
1949 		    "Failed to find key for krbtgt PAC signature");
1950 	goto out;
1951     }
1952 
1953     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1954 			NULL, &clientdb, &client);
1955     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1956 	/* This is OK, we are just trying to find out if they have
1957 	 * been disabled or deleted in the meantime, missing secrets
1958 	 * is OK */
1959     } else if(ret){
1960 	const char *krbtgt_realm, *msg;
1961 
1962 	/*
1963 	 * If the client belongs to the same realm as our krbtgt, it
1964 	 * should exist in the local database.
1965 	 *
1966 	 */
1967 
1968 	krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1969 
1970 	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1971 	    if (ret == HDB_ERR_NOENTRY)
1972 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1973 	    kdc_log(context, config, 1, "Client no longer in database: %s",
1974 		    cpn);
1975 	    goto out;
1976 	}
1977 
1978 	msg = krb5_get_error_message(context, ret);
1979 	kdc_log(context, config, 1, "Client not found in database: %s", msg);
1980 	krb5_free_error_message(context, msg);
1981     }
1982 
1983     ret = check_PAC(context, config, cp, NULL,
1984 		    client, server, krbtgt,
1985 		    &tkey_check->key,
1986 		    ekey, &tkey_sign->key,
1987 		    tgt, &rspac, &signedpath);
1988     if (ret) {
1989 	const char *msg = krb5_get_error_message(context, ret);
1990 	kdc_log(context, config, 0,
1991 		"Verify PAC failed for %s (%s) from %s with %s",
1992 		spn, cpn, from, msg);
1993 	krb5_free_error_message(context, msg);
1994 	goto out;
1995     }
1996 
1997     /* also check the krbtgt for signature */
1998     ret = check_KRB5SignedPath(context,
1999 			       config,
2000 			       krbtgt,
2001 			       cp,
2002 			       tgt,
2003 			       &spp,
2004 			       &signedpath);
2005     if (ret) {
2006 	const char *msg = krb5_get_error_message(context, ret);
2007 	kdc_log(context, config, 0,
2008 		"KRB5SignedPath check failed for %s (%s) from %s with %s",
2009 		spn, cpn, from, msg);
2010 	krb5_free_error_message(context, msg);
2011 	goto out;
2012     }
2013 
2014     /*
2015      * Process request
2016      */
2017 
2018     /* by default the tgt principal matches the client principal */
2019     tp = cp;
2020     tpn = cpn;
2021 
2022     if (client) {
2023 	const PA_DATA *sdata;
2024 	int i = 0;
2025 
2026 	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
2027 	if (sdata) {
2028 	    krb5_crypto crypto;
2029 	    krb5_data datack;
2030 	    PA_S4U2Self self;
2031 	    const char *str;
2032 
2033 	    ret = decode_PA_S4U2Self(sdata->padata_value.data,
2034 				     sdata->padata_value.length,
2035 				     &self, NULL);
2036 	    if (ret) {
2037 		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
2038 		goto out;
2039 	    }
2040 
2041 	    if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
2042 		free_PA_S4U2Self(&self);
2043 		kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
2044 		ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
2045 		goto out;
2046 	    }
2047 
2048 	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
2049 	    if (ret)
2050 		goto out;
2051 
2052 	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
2053 	    if (ret) {
2054 		const char *msg = krb5_get_error_message(context, ret);
2055 		free_PA_S4U2Self(&self);
2056 		krb5_data_free(&datack);
2057 		kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
2058 		krb5_free_error_message(context, msg);
2059 		goto out;
2060 	    }
2061 
2062 	    /* Allow HMAC_MD5 checksum with any key type */
2063 	    if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
2064 		unsigned char csdata[16];
2065 		Checksum cs;
2066 
2067 		cs.checksum.length = sizeof(csdata);
2068 		cs.checksum.data = &csdata;
2069 
2070 		ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
2071 					      datack.data, datack.length,
2072 					      KRB5_KU_OTHER_CKSUM, &cs);
2073 		if (ret == 0 &&
2074 		    krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
2075 		    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2076 	    }
2077 	    else {
2078 		ret = krb5_verify_checksum(context,
2079 					   crypto,
2080 					   KRB5_KU_OTHER_CKSUM,
2081 					   datack.data,
2082 					   datack.length,
2083 					   &self.cksum);
2084 	    }
2085 	    krb5_data_free(&datack);
2086 	    krb5_crypto_destroy(context, crypto);
2087 	    if (ret) {
2088 		const char *msg = krb5_get_error_message(context, ret);
2089 		free_PA_S4U2Self(&self);
2090 		kdc_log(context, config, 0,
2091 			"krb5_verify_checksum failed for S4U2Self: %s", msg);
2092 		krb5_free_error_message(context, msg);
2093 		goto out;
2094 	    }
2095 
2096 	    ret = _krb5_principalname2krb5_principal(context,
2097 						     &tp,
2098 						     self.name,
2099 						     self.realm);
2100 	    free_PA_S4U2Self(&self);
2101 	    if (ret)
2102 		goto out;
2103 
2104 	    ret = krb5_unparse_name(context, tp, &tpn);
2105 	    if (ret)
2106 		goto out;
2107 
2108 	    /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2109 	    if(rspac.data) {
2110 		krb5_pac p = NULL;
2111 		krb5_data_free(&rspac);
2112 		ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2113 				    NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
2114 		if (ret) {
2115 		    const char *msg;
2116 
2117 		    /*
2118 		     * If the client belongs to the same realm as our krbtgt, it
2119 		     * should exist in the local database.
2120 		     *
2121 		     */
2122 
2123 		    if (ret == HDB_ERR_NOENTRY)
2124 			ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2125 		    msg = krb5_get_error_message(context, ret);
2126 		    kdc_log(context, config, 1,
2127 			    "S2U4Self principal to impersonate %s not found in database: %s",
2128 			    tpn, msg);
2129 		    krb5_free_error_message(context, msg);
2130 		    goto out;
2131 		}
2132 		ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2133 		if (ret) {
2134 		    kdc_log(context, config, 0, "PAC generation failed for -- %s",
2135 			    tpn);
2136 		    goto out;
2137 		}
2138 		if (p != NULL) {
2139 		    ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2140 					 s4u2self_impersonated_client->entry.principal,
2141 					 ekey, &tkey_sign->key,
2142 					 &rspac);
2143 		    krb5_pac_free(context, p);
2144 		    if (ret) {
2145 			kdc_log(context, config, 0, "PAC signing failed for -- %s",
2146 				tpn);
2147 			goto out;
2148 		    }
2149 		}
2150 	    }
2151 
2152 	    /*
2153 	     * Check that service doing the impersonating is
2154 	     * requesting a ticket to it-self.
2155 	     */
2156 	    ret = check_s4u2self(context, config, clientdb, client, sp);
2157 	    if (ret) {
2158 		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2159 			"to impersonate to service "
2160 			"(tried for user %s to service %s)",
2161 			cpn, tpn, spn);
2162 		goto out;
2163 	    }
2164 
2165 	    /*
2166 	     * If the service isn't trusted for authentication to
2167 	     * delegation, remove the forward flag.
2168 	     */
2169 
2170 	    if (client->entry.flags.trusted_for_delegation) {
2171 		str = "[forwardable]";
2172 	    } else {
2173 		b->kdc_options.forwardable = 0;
2174 		str = "";
2175 	    }
2176 	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2177 		    "service %s %s", cpn, tpn, spn, str);
2178 	}
2179     }
2180 
2181     /*
2182      * Constrained delegation
2183      */
2184 
2185     if (client != NULL
2186 	&& b->additional_tickets != NULL
2187 	&& b->additional_tickets->len != 0
2188 	&& b->kdc_options.cname_in_addl_tkt
2189 	&& b->kdc_options.enc_tkt_in_skey == 0)
2190     {
2191 	int ad_signedpath = 0;
2192 	Key *clientkey;
2193 	Ticket *t;
2194 
2195 	/*
2196 	 * Require that the KDC have issued the service's krbtgt (not
2197 	 * self-issued ticket with kimpersonate(1).
2198 	 */
2199 	if (!signedpath) {
2200 	    ret = KRB5KDC_ERR_BADOPTION;
2201 	    kdc_log(context, config, 0,
2202 		    "Constrained delegation done on service ticket %s/%s",
2203 		    cpn, spn);
2204 	    goto out;
2205 	}
2206 
2207 	t = &b->additional_tickets->val[0];
2208 
2209 	ret = hdb_enctype2key(context, &client->entry,
2210 			      hdb_kvno2keys(context, &client->entry,
2211 					    t->enc_part.kvno ? * t->enc_part.kvno : 0),
2212 			      t->enc_part.etype, &clientkey);
2213 	if(ret){
2214 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2215 	    goto out;
2216 	}
2217 
2218 	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2219 	if (ret) {
2220 	    kdc_log(context, config, 0,
2221 		    "failed to decrypt ticket for "
2222 		    "constrained delegation from %s to %s ", cpn, spn);
2223 	    goto out;
2224 	}
2225 
2226 	ret = _krb5_principalname2krb5_principal(context,
2227 						 &tp,
2228 						 adtkt.cname,
2229 						 adtkt.crealm);
2230 	if (ret)
2231 	    goto out;
2232 
2233 	ret = krb5_unparse_name(context, tp, &tpn);
2234 	if (ret)
2235 	    goto out;
2236 
2237 	ret = _krb5_principalname2krb5_principal(context,
2238 						 &dp,
2239 						 t->sname,
2240 						 t->realm);
2241 	if (ret)
2242 	    goto out;
2243 
2244 	ret = krb5_unparse_name(context, dp, &dpn);
2245 	if (ret)
2246 	    goto out;
2247 
2248 	/* check that ticket is valid */
2249 	if (adtkt.flags.forwardable == 0) {
2250 	    kdc_log(context, config, 0,
2251 		    "Missing forwardable flag on ticket for "
2252 		    "constrained delegation from %s (%s) as %s to %s ",
2253 		    cpn, dpn, tpn, spn);
2254 	    ret = KRB5KDC_ERR_BADOPTION;
2255 	    goto out;
2256 	}
2257 
2258 	ret = check_constrained_delegation(context, config, clientdb,
2259 					   client, server, sp);
2260 	if (ret) {
2261 	    kdc_log(context, config, 0,
2262 		    "constrained delegation from %s (%s) as %s to %s not allowed",
2263 		    cpn, dpn, tpn, spn);
2264 	    goto out;
2265 	}
2266 
2267 	ret = verify_flags(context, config, &adtkt, tpn);
2268 	if (ret) {
2269 	    goto out;
2270 	}
2271 
2272 	krb5_data_free(&rspac);
2273 
2274 	/*
2275 	 * generate the PAC for the user.
2276 	 *
2277 	 * TODO: pass in t->sname and t->realm and build
2278 	 * a S4U_DELEGATION_INFO blob to the PAC.
2279 	 */
2280 	ret = check_PAC(context, config, tp, dp,
2281 			client, server, krbtgt,
2282 			&clientkey->key,
2283 			ekey, &tkey_sign->key,
2284 			&adtkt, &rspac, &ad_signedpath);
2285 	if (ret) {
2286 	    const char *msg = krb5_get_error_message(context, ret);
2287 	    kdc_log(context, config, 0,
2288 		    "Verify delegated PAC failed to %s for client"
2289 		    "%s (%s) as %s from %s with %s",
2290 		    spn, cpn, dpn, tpn, from, msg);
2291 	    krb5_free_error_message(context, msg);
2292 	    goto out;
2293 	}
2294 
2295 	/*
2296 	 * Check that the KDC issued the user's ticket.
2297 	 */
2298 	ret = check_KRB5SignedPath(context,
2299 				   config,
2300 				   krbtgt,
2301 				   cp,
2302 				   &adtkt,
2303 				   NULL,
2304 				   &ad_signedpath);
2305 	if (ret) {
2306 	    const char *msg = krb5_get_error_message(context, ret);
2307 	    kdc_log(context, config, 0,
2308 		    "KRB5SignedPath check from service %s failed "
2309 		    "for delegation to %s for client %s (%s)"
2310 		    "from %s failed with %s",
2311 		    spn, tpn, dpn, cpn, from, msg);
2312 	    krb5_free_error_message(context, msg);
2313 	    goto out;
2314 	}
2315 
2316 	if (!ad_signedpath) {
2317 	    ret = KRB5KDC_ERR_BADOPTION;
2318 	    kdc_log(context, config, 0,
2319 		    "Ticket not signed with PAC nor SignedPath service %s failed "
2320 		    "for delegation to %s for client %s (%s)"
2321 		    "from %s",
2322 		    spn, tpn, dpn, cpn, from);
2323 	    goto out;
2324 	}
2325 
2326 	kdc_log(context, config, 0, "constrained delegation for %s "
2327 		"from %s (%s) to %s", tpn, cpn, dpn, spn);
2328     }
2329 
2330     /*
2331      * Check flags
2332      */
2333 
2334     ret = kdc_check_flags(context, config,
2335 			  client, cpn,
2336 			  server, spn,
2337 			  FALSE);
2338     if(ret)
2339 	goto out;
2340 
2341     if((b->kdc_options.validate || b->kdc_options.renew) &&
2342        !krb5_principal_compare(context,
2343 			       krbtgt->entry.principal,
2344 			       server->entry.principal)){
2345 	kdc_log(context, config, 0, "Inconsistent request.");
2346 	ret = KRB5KDC_ERR_SERVER_NOMATCH;
2347 	goto out;
2348     }
2349 
2350     /* check for valid set of addresses */
2351     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2352 	ret = KRB5KRB_AP_ERR_BADADDR;
2353 	kdc_log(context, config, 0, "Request from wrong address");
2354 	goto out;
2355     }
2356 
2357     /* check local and per-principal anonymous ticket issuance policy */
2358     if (is_anon_tgs_request_p(b, tgt)) {
2359 	ret = _kdc_check_anon_policy(context, config, client, server);
2360 	if (ret)
2361 	    goto out;
2362     }
2363 
2364     /*
2365      * If this is an referral, add server referral data to the
2366      * auth_data reply .
2367      */
2368     if (ref_realm) {
2369 	PA_DATA pa;
2370 	krb5_crypto crypto;
2371 
2372 	kdc_log(context, config, 0,
2373 		"Adding server referral to %s", ref_realm);
2374 
2375 	ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2376 	if (ret)
2377 	    goto out;
2378 
2379 	ret = build_server_referral(context, config, crypto, ref_realm,
2380 				    NULL, s, &pa.padata_value);
2381 	krb5_crypto_destroy(context, crypto);
2382 	if (ret) {
2383 	    kdc_log(context, config, 0,
2384 		    "Failed building server referral");
2385 	    goto out;
2386 	}
2387 	pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2388 
2389 	ret = add_METHOD_DATA(&enc_pa_data, &pa);
2390 	krb5_data_free(&pa.padata_value);
2391 	if (ret) {
2392 	    kdc_log(context, config, 0,
2393 		    "Add server referral METHOD-DATA failed");
2394 	    goto out;
2395 	}
2396     }
2397 
2398     /*
2399      *
2400      */
2401 
2402     ret = tgs_make_reply(context,
2403 			 config,
2404 			 b,
2405 			 tp,
2406 			 tgt,
2407 			 replykey,
2408 			 rk_is_subkey,
2409 			 ekey,
2410 			 &sessionkey,
2411 			 kvno,
2412 			 *auth_data,
2413 			 server,
2414 			 rsp,
2415 			 spn,
2416 			 client,
2417 			 cp,
2418                          tgt_realm,
2419 			 krbtgt_out,
2420 			 tkey_sign->key.keytype,
2421 			 spp,
2422 			 &rspac,
2423 			 &enc_pa_data,
2424 			 e_text,
2425 			 reply);
2426 
2427 out:
2428     if (tpn != cpn)
2429 	    free(tpn);
2430     free(spn);
2431     free(cpn);
2432     free(dpn);
2433     free(krbtgt_out_n);
2434     _krb5_free_capath(context, capath);
2435 
2436     krb5_data_free(&rspac);
2437     krb5_free_keyblock_contents(context, &sessionkey);
2438     if(krbtgt_out)
2439 	_kdc_free_ent(context, krbtgt_out);
2440     if(server)
2441 	_kdc_free_ent(context, server);
2442     if(client)
2443 	_kdc_free_ent(context, client);
2444     if(s4u2self_impersonated_client)
2445 	_kdc_free_ent(context, s4u2self_impersonated_client);
2446 
2447     if (tp && tp != cp)
2448 	krb5_free_principal(context, tp);
2449     krb5_free_principal(context, cp);
2450     krb5_free_principal(context, dp);
2451     krb5_free_principal(context, sp);
2452     krb5_free_principal(context, krbtgt_out_principal);
2453     free(ref_realm);
2454     free_METHOD_DATA(&enc_pa_data);
2455 
2456     free_EncTicketPart(&adtkt);
2457 
2458     return ret;
2459 }
2460 
2461 /*
2462  *
2463  */
2464 
2465 krb5_error_code
2466 _kdc_tgs_rep(krb5_context context,
2467 	     krb5_kdc_configuration *config,
2468 	     KDC_REQ *req,
2469 	     krb5_data *data,
2470 	     const char *from,
2471 	     struct sockaddr *from_addr,
2472 	     int datagram_reply)
2473 {
2474     AuthorizationData *auth_data = NULL;
2475     krb5_error_code ret;
2476     int i = 0;
2477     const PA_DATA *tgs_req;
2478 
2479     hdb_entry_ex *krbtgt = NULL;
2480     krb5_ticket *ticket = NULL;
2481     const char *e_text = NULL;
2482     krb5_enctype krbtgt_etype = ETYPE_NULL;
2483 
2484     krb5_keyblock *replykey = NULL;
2485     int rk_is_subkey = 0;
2486     time_t *csec = NULL;
2487     int *cusec = NULL;
2488 
2489     if(req->padata == NULL){
2490 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2491 	kdc_log(context, config, 0,
2492 		"TGS-REQ from %s without PA-DATA", from);
2493 	goto out;
2494     }
2495 
2496     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2497 
2498     if(tgs_req == NULL){
2499 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2500 
2501 	kdc_log(context, config, 0,
2502 		"TGS-REQ from %s without PA-TGS-REQ", from);
2503 	goto out;
2504     }
2505     ret = tgs_parse_request(context, config,
2506 			    &req->req_body, tgs_req,
2507 			    &krbtgt,
2508 			    &krbtgt_etype,
2509 			    &ticket,
2510 			    &e_text,
2511 			    from, from_addr,
2512 			    &csec, &cusec,
2513 			    &auth_data,
2514 			    &replykey,
2515 			    &rk_is_subkey);
2516     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2517 	/* kdc_log() is called in tgs_parse_request() */
2518 	goto out;
2519     }
2520     if (ret) {
2521 	kdc_log(context, config, 0,
2522 		"Failed parsing TGS-REQ from %s", from);
2523 	goto out;
2524     }
2525 
2526     {
2527 	const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2528 	if (pa)
2529 	    kdc_log(context, config, 10, "Got TGS FAST request");
2530     }
2531 
2532 
2533     ret = tgs_build_reply(context,
2534 			  config,
2535 			  req,
2536 			  &req->req_body,
2537 			  krbtgt,
2538 			  krbtgt_etype,
2539 			  replykey,
2540 			  rk_is_subkey,
2541 			  ticket,
2542 			  data,
2543 			  from,
2544 			  &e_text,
2545 			  &auth_data,
2546 			  from_addr);
2547     if (ret) {
2548 	kdc_log(context, config, 0,
2549 		"Failed building TGS-REP to %s", from);
2550 	goto out;
2551     }
2552 
2553     /* */
2554     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2555 	krb5_data_free(data);
2556 	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2557 	e_text = "Reply packet too large";
2558     }
2559 
2560 out:
2561     if (replykey)
2562 	krb5_free_keyblock(context, replykey);
2563 
2564     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2565 	/* XXX add fast wrapping on the error */
2566 	METHOD_DATA error_method = { 0, NULL };
2567 
2568 
2569 	kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2570 	ret = _kdc_fast_mk_error(context, NULL,
2571 				 &error_method,
2572 				 NULL,
2573 				 NULL,
2574 				 ret, NULL,
2575 				 NULL,
2576 				 NULL, NULL,
2577 				 csec, cusec,
2578 				 data);
2579 	free_METHOD_DATA(&error_method);
2580     }
2581     free(csec);
2582     free(cusec);
2583     if (ticket)
2584 	krb5_free_ticket(context, ticket);
2585     if(krbtgt)
2586 	_kdc_free_ent(context, krbtgt);
2587 
2588     if (auth_data) {
2589 	free_AuthorizationData(auth_data);
2590 	free(auth_data);
2591     }
2592 
2593     return ret;
2594 }
2595