xref: /netbsd-src/crypto/external/bsd/heimdal/dist/kdc/krb5tgs.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /*	$NetBSD: krb5tgs.c,v 1.4 2023/06/19 21:41:41 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
get_krbtgt_realm(const PrincipalName * p)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
find_KRB5SignedPath(krb5_context context,const AuthorizationData * ad,krb5_data * data)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
_kdc_add_KRB5SignedPath(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * krbtgt,krb5_enctype enctype,krb5_const_principal client,krb5_const_principal server,krb5_principals principals,EncTicketPart * tkt)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
check_KRB5SignedPath(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * krbtgt,krb5_principal cp,EncTicketPart * tkt,krb5_principals * delegated,int * signedpath)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
check_PAC(krb5_context context,krb5_kdc_configuration * config,const krb5_principal client_principal,const krb5_principal delegated_proxy_principal,hdb_entry_ex * client,hdb_entry_ex * server,hdb_entry_ex * krbtgt,const EncryptionKey * server_check_key,const EncryptionKey * server_sign_key,const EncryptionKey * krbtgt_sign_key,EncTicketPart * tkt,krb5_data * rspac,int * signedpath)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
is_anon_tgs_request_p(const KDC_REQ_BODY * b,const EncTicketPart * tgt)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
check_tgs_flags(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,krb5_const_principal tgt_name,const EncTicketPart * tgt,EncTicketPart * et)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
check_constrained_delegation(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,hdb_entry_ex * server,krb5_const_principal target)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
check_s4u2self(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,krb5_const_principal server)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
verify_flags(krb5_context context,krb5_kdc_configuration * config,const EncTicketPart * et,const char * pstr)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
fix_transited_encoding(krb5_context context,krb5_kdc_configuration * config,krb5_boolean check_policy,const TransitedEncoding * tr,EncTicketPart * et,const char * client_realm,const char * server_realm,const char * tgt_realm)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
tgs_make_reply(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,krb5_const_principal tgt_name,const EncTicketPart * tgt,const krb5_keyblock * replykey,int rk_is_subkey,const EncryptionKey * serverkey,const krb5_keyblock * sessionkey,krb5_kvno kvno,AuthorizationData * auth_data,hdb_entry_ex * server,krb5_principal server_principal,const char * server_name,hdb_entry_ex * client,krb5_principal client_principal,const char * tgt_realm,hdb_entry_ex * krbtgt,krb5_enctype krbtgt_etype,krb5_principals spp,const krb5_data * rspac,const METHOD_DATA * enc_pa_data,const char ** e_text,krb5_data * reply)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     /* See MS-KILE 3.3.5.1 */
918     if (!server->entry.flags.forwardable)
919 	et.flags.forwardable = 0;
920     if (!server->entry.flags.proxiable)
921 	et.flags.proxiable = 0;
922 
923     /*
924      * For anonymous tickets, we should filter out positive authorization data
925      * that could reveal the client's identity, and return a policy error for
926      * restrictive authorization data. Policy for unknown authorization types
927      * is implementation dependent.
928      */
929     if (rspac->length && !et.flags.anonymous) {
930 	/*
931 	 * No not need to filter out the any PAC from the
932 	 * auth_data since it's signed by the KDC.
933 	 */
934 	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
935 					  KRB5_AUTHDATA_WIN2K_PAC, rspac);
936 	if (ret)
937 	    goto out;
938     }
939 
940     if (auth_data) {
941 	unsigned int i = 0;
942 
943 	/* XXX check authdata */
944 
945 	if (et.authorization_data == NULL) {
946 	    et.authorization_data = calloc(1, sizeof(*et.authorization_data));
947 	    if (et.authorization_data == NULL) {
948 		ret = ENOMEM;
949 		krb5_set_error_message(context, ret, "malloc: out of memory");
950 		goto out;
951 	    }
952 	}
953 	for(i = 0; i < auth_data->len ; i++) {
954 	    ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
955 	    if (ret) {
956 		krb5_set_error_message(context, ret, "malloc: out of memory");
957 		goto out;
958 	    }
959 	}
960 
961 	/* Filter out type KRB5SignedPath */
962 	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
963 	if (ret == 0) {
964 	    if (et.authorization_data->len == 1) {
965 		free_AuthorizationData(et.authorization_data);
966 		free(et.authorization_data);
967 		et.authorization_data = NULL;
968 	    } else {
969 		AuthorizationData *ad = et.authorization_data;
970 		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
971 		ad->len--;
972 	    }
973 	}
974     }
975 
976     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
977     if (ret)
978 	goto out;
979     et.crealm = rep.crealm;
980     et.cname = rep.cname;
981 
982     ek.key = et.key;
983     /* MIT must have at least one last_req */
984     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
985     if (ek.last_req.val == NULL) {
986 	ret = ENOMEM;
987 	goto out;
988     }
989     ek.last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
990     ek.nonce = b->nonce;
991     ek.flags = et.flags;
992     ek.authtime = et.authtime;
993     ek.starttime = et.starttime;
994     ek.endtime = et.endtime;
995     ek.renew_till = et.renew_till;
996     ek.srealm = rep.ticket.realm;
997     ek.sname = rep.ticket.sname;
998 
999     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
1000 		       et.endtime, et.renew_till);
1001 
1002     /* Don't sign cross realm tickets, they can't be checked anyway */
1003     {
1004 	char *r = get_krbtgt_realm(&ek.sname);
1005 
1006 	if (r == NULL || strcmp(r, ek.srealm) == 0) {
1007 	    ret = _kdc_add_KRB5SignedPath(context,
1008 					  config,
1009 					  krbtgt,
1010 					  krbtgt_etype,
1011 					  client_principal,
1012 					  NULL,
1013 					  spp,
1014 					  &et);
1015 	    if (ret)
1016 		goto out;
1017 	}
1018     }
1019 
1020     if (enc_pa_data->len) {
1021 	rep.padata = calloc(1, sizeof(*rep.padata));
1022 	if (rep.padata == NULL) {
1023 	    ret = ENOMEM;
1024 	    goto out;
1025 	}
1026 	ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
1027 	if (ret)
1028 	    goto out;
1029     }
1030 
1031     if (krb5_enctype_valid(context, serverkey->keytype) != 0
1032 	&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
1033     {
1034 	krb5_enctype_enable(context, serverkey->keytype);
1035 	is_weak = 1;
1036     }
1037 
1038 
1039     /* It is somewhat unclear where the etype in the following
1040        encryption should come from. What we have is a session
1041        key in the passed tgt, and a list of preferred etypes
1042        *for the new ticket*. Should we pick the best possible
1043        etype, given the keytype in the tgt, or should we look
1044        at the etype list here as well?  What if the tgt
1045        session key is DES3 and we want a ticket with a (say)
1046        CAST session key. Should the DES3 etype be added to the
1047        etype list, even if we don't want a session key with
1048        DES3? */
1049     ret = _kdc_encode_reply(context, config, NULL, 0,
1050 			    &rep, &et, &ek, serverkey->keytype,
1051 			    kvno,
1052 			    serverkey, 0, replykey, rk_is_subkey,
1053 			    e_text, reply);
1054     if (is_weak)
1055 	krb5_enctype_disable(context, serverkey->keytype);
1056 
1057 out:
1058     free_TGS_REP(&rep);
1059     free_TransitedEncoding(&et.transited);
1060     if(et.starttime)
1061 	free(et.starttime);
1062     if(et.renew_till)
1063 	free(et.renew_till);
1064     if(et.authorization_data) {
1065 	free_AuthorizationData(et.authorization_data);
1066 	free(et.authorization_data);
1067     }
1068     free_LastReq(&ek.last_req);
1069     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1070     free_EncryptionKey(&et.key);
1071     return ret;
1072 }
1073 
1074 static krb5_error_code
tgs_check_authenticator(krb5_context context,krb5_kdc_configuration * config,krb5_auth_context ac,KDC_REQ_BODY * b,const char ** e_text,krb5_keyblock * key)1075 tgs_check_authenticator(krb5_context context,
1076 			krb5_kdc_configuration *config,
1077 	                krb5_auth_context ac,
1078 			KDC_REQ_BODY *b,
1079 			const char **e_text,
1080 			krb5_keyblock *key)
1081 {
1082     krb5_authenticator auth;
1083     size_t len = 0;
1084     unsigned char *buf;
1085     size_t buf_size;
1086     krb5_error_code ret;
1087     krb5_crypto crypto;
1088 
1089     krb5_auth_con_getauthenticator(context, ac, &auth);
1090     if(auth->cksum == NULL){
1091 	kdc_log(context, config, 0, "No authenticator in request");
1092 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1093 	goto out;
1094     }
1095     /*
1096      * according to RFC1510 it doesn't need to be keyed,
1097      * but according to the latest draft it needs to.
1098      */
1099     if (
1100 #if 0
1101 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1102 	||
1103 #endif
1104  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1105 	kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1106 		auth->cksum->cksumtype);
1107 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1108 	goto out;
1109     }
1110 
1111     /* XXX should not re-encode this */
1112     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1113     if(ret){
1114 	const char *msg = krb5_get_error_message(context, ret);
1115 	kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1116 	krb5_free_error_message(context, msg);
1117 	goto out;
1118     }
1119     if(buf_size != len) {
1120 	free(buf);
1121 	kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1122 	*e_text = "KDC internal error";
1123 	ret = KRB5KRB_ERR_GENERIC;
1124 	goto out;
1125     }
1126     ret = krb5_crypto_init(context, key, 0, &crypto);
1127     if (ret) {
1128 	const char *msg = krb5_get_error_message(context, ret);
1129 	free(buf);
1130 	kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1131 	krb5_free_error_message(context, msg);
1132 	goto out;
1133     }
1134     ret = krb5_verify_checksum(context,
1135 			       crypto,
1136 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
1137 			       buf,
1138 			       len,
1139 			       auth->cksum);
1140     free(buf);
1141     krb5_crypto_destroy(context, crypto);
1142     if(ret){
1143 	const char *msg = krb5_get_error_message(context, ret);
1144 	kdc_log(context, config, 0,
1145 		"Failed to verify authenticator checksum: %s", msg);
1146 	krb5_free_error_message(context, msg);
1147     }
1148 out:
1149     free_Authenticator(auth);
1150     free(auth);
1151     return ret;
1152 }
1153 
1154 static krb5_boolean
need_referral(krb5_context context,krb5_kdc_configuration * config,const KDCOptions * const options,krb5_principal server,krb5_realm ** realms)1155 need_referral(krb5_context context, krb5_kdc_configuration *config,
1156 	      const KDCOptions * const options, krb5_principal server,
1157 	      krb5_realm **realms)
1158 {
1159     const char *name;
1160 
1161     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1162 	return FALSE;
1163 
1164     if (server->name.name_string.len == 1)
1165 	name = server->name.name_string.val[0];
1166     else if (server->name.name_string.len == 3) {
1167 	/*
1168 	  This is used to give referrals for the
1169 	  E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
1170 	  SPN form, which is used for inter-domain communication in AD
1171 	 */
1172 	name = server->name.name_string.val[2];
1173 	kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
1174 	*realms = malloc(sizeof(char *)*2);
1175 	if (*realms == NULL) {
1176 	    krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1177 	    return FALSE;
1178 	}
1179 	(*realms)[0] = strdup(name);
1180 	(*realms)[1] = NULL;
1181 	return TRUE;
1182     } else if (server->name.name_string.len > 1)
1183 	name = server->name.name_string.val[1];
1184     else
1185 	return FALSE;
1186 
1187     kdc_log(context, config, 0, "Searching referral for %s", name);
1188 
1189     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1190 }
1191 
1192 static krb5_error_code
tgs_parse_request(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,const PA_DATA * tgs_req,hdb_entry_ex ** krbtgt,krb5_enctype * krbtgt_etype,krb5_ticket ** ticket,const char ** e_text,const char * from,const struct sockaddr * from_addr,time_t ** csec,int ** cusec,AuthorizationData ** auth_data,krb5_keyblock ** replykey,int * rk_is_subkey)1193 tgs_parse_request(krb5_context context,
1194 		  krb5_kdc_configuration *config,
1195 		  KDC_REQ_BODY *b,
1196 		  const PA_DATA *tgs_req,
1197 		  hdb_entry_ex **krbtgt,
1198 		  krb5_enctype *krbtgt_etype,
1199 		  krb5_ticket **ticket,
1200 		  const char **e_text,
1201 		  const char *from,
1202 		  const struct sockaddr *from_addr,
1203 		  time_t **csec,
1204 		  int **cusec,
1205 		  AuthorizationData **auth_data,
1206 		  krb5_keyblock **replykey,
1207 		  int *rk_is_subkey)
1208 {
1209     static char failed[] = "<unparse_name failed>";
1210     krb5_ap_req ap_req;
1211     krb5_error_code ret;
1212     krb5_principal princ;
1213     krb5_auth_context ac = NULL;
1214     krb5_flags ap_req_options;
1215     krb5_flags verify_ap_req_flags;
1216     krb5_crypto crypto;
1217     krb5uint32 krbtgt_kvno;     /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1218     krb5uint32 krbtgt_kvno_try;
1219     int kvno_search_tries = 4;  /* number of kvnos to try when tkt_vno == 0 */
1220     const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1221     Key *tkey;
1222     krb5_keyblock *subkey = NULL;
1223     unsigned usage;
1224 
1225     *auth_data = NULL;
1226     *csec  = NULL;
1227     *cusec = NULL;
1228     *replykey = NULL;
1229 
1230     memset(&ap_req, 0, sizeof(ap_req));
1231     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1232     if(ret){
1233 	const char *msg = krb5_get_error_message(context, ret);
1234 	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1235 	krb5_free_error_message(context, msg);
1236 	goto out;
1237     }
1238 
1239     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1240 	/* XXX check for ticket.sname == req.sname */
1241 	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1242 	ret = KRB5KDC_ERR_POLICY; /* ? */
1243 	goto out;
1244     }
1245 
1246     _krb5_principalname2krb5_principal(context,
1247 				       &princ,
1248 				       ap_req.ticket.sname,
1249 				       ap_req.ticket.realm);
1250 
1251     krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1252     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
1253 			&krbtgt_kvno, NULL, krbtgt);
1254 
1255     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1256 	/* XXX Factor out this unparsing of the same princ all over */
1257 	char *p;
1258 	ret = krb5_unparse_name(context, princ, &p);
1259 	if (ret != 0)
1260 	    p = failed;
1261 	krb5_free_principal(context, princ);
1262 	kdc_log(context, config, 5,
1263 		"Ticket-granting ticket account %s does not have secrets at "
1264 		"this KDC, need to proxy", p);
1265 	if (ret == 0)
1266 	    free(p);
1267 	ret = HDB_ERR_NOT_FOUND_HERE;
1268 	goto out;
1269     } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1270 	char *p;
1271 	ret = krb5_unparse_name(context, princ, &p);
1272 	if (ret != 0)
1273 	    p = failed;
1274 	krb5_free_principal(context, princ);
1275 	kdc_log(context, config, 5,
1276 		"Ticket-granting ticket account %s does not have keys for "
1277 		"kvno %d at this KDC", p, krbtgt_kvno);
1278 	if (ret == 0)
1279 	    free(p);
1280 	ret = HDB_ERR_KVNO_NOT_FOUND;
1281 	goto out;
1282     } else if (ret == HDB_ERR_NO_MKEY) {
1283 	char *p;
1284 	ret = krb5_unparse_name(context, princ, &p);
1285 	if (ret != 0)
1286 	    p = failed;
1287 	krb5_free_principal(context, princ);
1288 	kdc_log(context, config, 5,
1289 		"Missing master key for decrypting keys for ticket-granting "
1290 		"ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1291 	if (ret == 0)
1292 	    free(p);
1293 	ret = HDB_ERR_KVNO_NOT_FOUND;
1294 	goto out;
1295     } else if (ret) {
1296 	const char *msg = krb5_get_error_message(context, ret);
1297 	char *p;
1298 	ret = krb5_unparse_name(context, princ, &p);
1299 	if (ret != 0)
1300 	    p = failed;
1301 	krb5_free_principal(context, princ);
1302 	kdc_log(context, config, 0,
1303 		"Ticket-granting ticket not found in database: %s", msg);
1304 	krb5_free_error_message(context, msg);
1305 	if (ret == 0)
1306 	    free(p);
1307 	ret = KRB5KRB_AP_ERR_NOT_US;
1308 	goto out;
1309     }
1310 
1311     krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1312     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1313 
1314 next_kvno:
1315     krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
1316     ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
1317 			  ap_req.ticket.enc_part.etype, &tkey);
1318     if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1319 	kvno_search_tries--;
1320 	krbtgt_kvno_try--;
1321 	goto next_kvno;
1322     } else if (ret) {
1323 	char *str = NULL, *p = NULL;
1324 
1325 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1326 	krb5_unparse_name(context, princ, &p);
1327  	kdc_log(context, config, 0,
1328 		"No server key with enctype %s found for %s",
1329 		str ? str : "<unknown enctype>",
1330 		p ? p : "<unparse_name failed>");
1331 	free(str);
1332 	free(p);
1333 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1334 	goto out;
1335     }
1336 
1337     if (b->kdc_options.validate)
1338 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1339     else
1340 	verify_ap_req_flags = 0;
1341 
1342     ret = krb5_verify_ap_req2(context,
1343 			      &ac,
1344 			      &ap_req,
1345 			      princ,
1346 			      &tkey->key,
1347 			      verify_ap_req_flags,
1348 			      &ap_req_options,
1349 			      ticket,
1350 			      KRB5_KU_TGS_REQ_AUTH);
1351     if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1352 	kvno_search_tries--;
1353 	krbtgt_kvno_try--;
1354 	goto next_kvno;
1355     }
1356 
1357     krb5_free_principal(context, princ);
1358     if(ret) {
1359 	const char *msg = krb5_get_error_message(context, ret);
1360 	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1361 	krb5_free_error_message(context, msg);
1362 	goto out;
1363     }
1364 
1365     {
1366 	krb5_authenticator auth;
1367 
1368 	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1369 	if (ret == 0) {
1370 	    *csec   = malloc(sizeof(**csec));
1371 	    if (*csec == NULL) {
1372 		krb5_free_authenticator(context, &auth);
1373 		kdc_log(context, config, 0, "malloc failed");
1374 		goto out;
1375 	    }
1376 	    **csec  = auth->ctime;
1377 	    *cusec  = malloc(sizeof(**cusec));
1378 	    if (*cusec == NULL) {
1379 		krb5_free_authenticator(context, &auth);
1380 		kdc_log(context, config, 0, "malloc failed");
1381 		goto out;
1382 	    }
1383 	    **cusec  = auth->cusec;
1384 	    krb5_free_authenticator(context, &auth);
1385 	}
1386     }
1387 
1388     ret = tgs_check_authenticator(context, config,
1389 				  ac, b, e_text, &(*ticket)->ticket.key);
1390     if (ret) {
1391 	krb5_auth_con_free(context, ac);
1392 	goto out;
1393     }
1394 
1395     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1396     *rk_is_subkey = 1;
1397 
1398     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1399     if(ret){
1400 	const char *msg = krb5_get_error_message(context, ret);
1401 	krb5_auth_con_free(context, ac);
1402 	kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1403 	krb5_free_error_message(context, msg);
1404 	goto out;
1405     }
1406     if(subkey == NULL){
1407 	usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1408 	*rk_is_subkey = 0;
1409 
1410 	ret = krb5_auth_con_getkey(context, ac, &subkey);
1411 	if(ret) {
1412 	    const char *msg = krb5_get_error_message(context, ret);
1413 	    krb5_auth_con_free(context, ac);
1414 	    kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1415 	    krb5_free_error_message(context, msg);
1416 	    goto out;
1417 	}
1418     }
1419     if(subkey == NULL){
1420 	krb5_auth_con_free(context, ac);
1421 	kdc_log(context, config, 0,
1422 		"Failed to get key for enc-authorization-data");
1423 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1424 	goto out;
1425     }
1426 
1427     *replykey = subkey;
1428 
1429     if (b->enc_authorization_data) {
1430 	krb5_data ad;
1431 
1432 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
1433 	if (ret) {
1434 	    const char *msg = krb5_get_error_message(context, ret);
1435 	    krb5_auth_con_free(context, ac);
1436 	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1437 	    krb5_free_error_message(context, msg);
1438 	    goto out;
1439 	}
1440 	ret = krb5_decrypt_EncryptedData (context,
1441 					  crypto,
1442 					  usage,
1443 					  b->enc_authorization_data,
1444 					  &ad);
1445 	krb5_crypto_destroy(context, crypto);
1446 	if(ret){
1447 	    krb5_auth_con_free(context, ac);
1448 	    kdc_log(context, config, 0,
1449 		    "Failed to decrypt enc-authorization-data");
1450 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1451 	    goto out;
1452 	}
1453 	ALLOC(*auth_data);
1454 	if (*auth_data == NULL) {
1455 	    krb5_auth_con_free(context, ac);
1456 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1457 	    goto out;
1458 	}
1459 	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1460 	if(ret){
1461 	    krb5_auth_con_free(context, ac);
1462 	    free(*auth_data);
1463 	    *auth_data = NULL;
1464 	    kdc_log(context, config, 0, "Failed to decode authorization data");
1465 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1466 	    goto out;
1467 	}
1468     }
1469 
1470     krb5_auth_con_free(context, ac);
1471 
1472 out:
1473     free_AP_REQ(&ap_req);
1474 
1475     return ret;
1476 }
1477 
1478 static krb5_error_code
build_server_referral(krb5_context context,krb5_kdc_configuration * config,krb5_crypto session,krb5_const_realm referred_realm,const PrincipalName * true_principal_name,const PrincipalName * requested_principal,krb5_data * outdata)1479 build_server_referral(krb5_context context,
1480 		      krb5_kdc_configuration *config,
1481 		      krb5_crypto session,
1482 		      krb5_const_realm referred_realm,
1483 		      const PrincipalName *true_principal_name,
1484 		      const PrincipalName *requested_principal,
1485 		      krb5_data *outdata)
1486 {
1487     PA_ServerReferralData ref;
1488     krb5_error_code ret;
1489     EncryptedData ed;
1490     krb5_data data;
1491     size_t size = 0;
1492 
1493     memset(&ref, 0, sizeof(ref));
1494 
1495     if (referred_realm) {
1496 	ALLOC(ref.referred_realm);
1497 	if (ref.referred_realm == NULL)
1498 	    goto eout;
1499 	*ref.referred_realm = strdup(referred_realm);
1500 	if (*ref.referred_realm == NULL)
1501 	    goto eout;
1502     }
1503     if (true_principal_name) {
1504 	ALLOC(ref.true_principal_name);
1505 	if (ref.true_principal_name == NULL)
1506 	    goto eout;
1507 	ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1508 	if (ret)
1509 	    goto eout;
1510     }
1511     if (requested_principal) {
1512 	ALLOC(ref.requested_principal_name);
1513 	if (ref.requested_principal_name == NULL)
1514 	    goto eout;
1515 	ret = copy_PrincipalName(requested_principal,
1516 				 ref.requested_principal_name);
1517 	if (ret)
1518 	    goto eout;
1519     }
1520 
1521     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1522 		       data.data, data.length,
1523 		       &ref, &size, ret);
1524     free_PA_ServerReferralData(&ref);
1525     if (ret)
1526 	return ret;
1527     if (data.length != size)
1528 	krb5_abortx(context, "internal asn.1 encoder error");
1529 
1530     ret = krb5_encrypt_EncryptedData(context, session,
1531 				     KRB5_KU_PA_SERVER_REFERRAL,
1532 				     data.data, data.length,
1533 				     0 /* kvno */, &ed);
1534     free(data.data);
1535     if (ret)
1536 	return ret;
1537 
1538     ASN1_MALLOC_ENCODE(EncryptedData,
1539 		       outdata->data, outdata->length,
1540 		       &ed, &size, ret);
1541     free_EncryptedData(&ed);
1542     if (ret)
1543 	return ret;
1544     if (outdata->length != size)
1545 	krb5_abortx(context, "internal asn.1 encoder error");
1546 
1547     return 0;
1548 eout:
1549     free_PA_ServerReferralData(&ref);
1550     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1551     return ENOMEM;
1552 }
1553 
1554 static krb5_error_code
tgs_build_reply(krb5_context context,krb5_kdc_configuration * config,KDC_REQ * req,KDC_REQ_BODY * b,hdb_entry_ex * krbtgt,krb5_enctype krbtgt_etype,const krb5_keyblock * replykey,int rk_is_subkey,krb5_ticket * ticket,krb5_data * reply,const char * from,const char ** e_text,AuthorizationData ** auth_data,const struct sockaddr * from_addr)1555 tgs_build_reply(krb5_context context,
1556 		krb5_kdc_configuration *config,
1557 		KDC_REQ *req,
1558 		KDC_REQ_BODY *b,
1559 		hdb_entry_ex *krbtgt,
1560 		krb5_enctype krbtgt_etype,
1561 		const krb5_keyblock *replykey,
1562 		int rk_is_subkey,
1563 		krb5_ticket *ticket,
1564 		krb5_data *reply,
1565 		const char *from,
1566 		const char **e_text,
1567 		AuthorizationData **auth_data,
1568 		const struct sockaddr *from_addr)
1569 {
1570     krb5_error_code ret, ret2;
1571     krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1572     krb5_principal krbtgt_out_principal = NULL;
1573     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1574     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1575     HDB *clientdb, *s4u2self_impersonated_clientdb;
1576     krb5_realm ref_realm = NULL;
1577     EncTicketPart *tgt = &ticket->ticket;
1578     krb5_principals spp = NULL;
1579     const EncryptionKey *ekey;
1580     krb5_keyblock sessionkey;
1581     krb5_kvno kvno;
1582     krb5_data rspac;
1583     const char *tgt_realm = /* Realm of TGT issuer */
1584         krb5_principal_get_realm(context, krbtgt->entry.principal);
1585     const char *our_realm = /* Realm of this KDC */
1586         krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1587     char **capath = NULL;
1588     size_t num_capath = 0;
1589 
1590     hdb_entry_ex *krbtgt_out = NULL;
1591 
1592     METHOD_DATA enc_pa_data;
1593 
1594     PrincipalName *s;
1595     Realm r;
1596     EncTicketPart adtkt;
1597     char opt_str[128];
1598     int signedpath = 0;
1599 
1600     Key *tkey_check;
1601     Key *tkey_sign;
1602     int flags = HDB_F_FOR_TGS_REQ;
1603 
1604     memset(&sessionkey, 0, sizeof(sessionkey));
1605     memset(&adtkt, 0, sizeof(adtkt));
1606     krb5_data_zero(&rspac);
1607     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1608 
1609     s = b->sname;
1610     r = b->realm;
1611 
1612     /*
1613      * Always to do CANON, see comment below about returned server principal (rsp).
1614      */
1615     flags |= HDB_F_CANON;
1616 
1617     if(b->kdc_options.enc_tkt_in_skey){
1618 	Ticket *t;
1619 	hdb_entry_ex *uu;
1620 	krb5_principal p;
1621 	Key *uukey;
1622 	krb5uint32 second_kvno = 0;
1623 	krb5uint32 *kvno_ptr = NULL;
1624 
1625 	if(b->additional_tickets == NULL ||
1626 	   b->additional_tickets->len == 0){
1627 	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
1628 	    kdc_log(context, config, 0,
1629 		    "No second ticket present in request");
1630 	    goto out;
1631 	}
1632 	t = &b->additional_tickets->val[0];
1633 	if(!get_krbtgt_realm(&t->sname)){
1634 	    kdc_log(context, config, 0,
1635 		    "Additional ticket is not a ticket-granting ticket");
1636 	    ret = KRB5KDC_ERR_POLICY;
1637 	    goto out;
1638 	}
1639 	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1640 	if(t->enc_part.kvno){
1641 	    second_kvno = *t->enc_part.kvno;
1642 	    kvno_ptr = &second_kvno;
1643 	}
1644 	ret = _kdc_db_fetch(context, config, p,
1645 			    HDB_F_GET_KRBTGT, kvno_ptr,
1646 			    NULL, &uu);
1647 	krb5_free_principal(context, p);
1648 	if(ret){
1649 	    if (ret == HDB_ERR_NOENTRY)
1650 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1651 	    goto out;
1652 	}
1653 	ret = hdb_enctype2key(context, &uu->entry, NULL,
1654 			      t->enc_part.etype, &uukey);
1655 	if(ret){
1656 	    _kdc_free_ent(context, uu);
1657 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1658 	    goto out;
1659 	}
1660 	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1661 	_kdc_free_ent(context, uu);
1662 	if(ret)
1663 	    goto out;
1664 
1665 	ret = verify_flags(context, config, &adtkt, spn);
1666 	if (ret)
1667 	    goto out;
1668 
1669 	s = &adtkt.cname;
1670 	r = adtkt.crealm;
1671     } else if (s == NULL) {
1672 	ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1673 	kdc_log(context, config, 0, "No server in request");
1674 	goto out;
1675     }
1676 
1677     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1678     ret = krb5_unparse_name(context, sp, &spn);
1679     if (ret)
1680 	goto out;
1681     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1682     ret = krb5_unparse_name(context, cp, &cpn);
1683     if (ret)
1684 	goto out;
1685     unparse_flags (KDCOptions2int(b->kdc_options),
1686 		   asn1_KDCOptions_units(),
1687 		   opt_str, sizeof(opt_str));
1688     if(*opt_str)
1689 	kdc_log(context, config, 0,
1690 		"TGS-REQ %s from %s for %s [%s]",
1691 		cpn, from, spn, opt_str);
1692     else
1693 	kdc_log(context, config, 0,
1694 		"TGS-REQ %s from %s for %s", cpn, from, spn);
1695 
1696     /*
1697      * Fetch server
1698      */
1699 
1700 server_lookup:
1701     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1702 			NULL, NULL, &server);
1703 
1704     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1705 	kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1706 	goto out;
1707     } else if (ret == HDB_ERR_WRONG_REALM) {
1708         free(ref_realm);
1709 	ref_realm = strdup(server->entry.principal->realm);
1710 	if (ref_realm == NULL) {
1711             ret = krb5_enomem(context);
1712 	    goto out;
1713 	}
1714 
1715 	kdc_log(context, config, 5,
1716 		"Returning a referral to realm %s for "
1717 		"server %s.",
1718 		ref_realm, spn);
1719 	krb5_free_principal(context, sp);
1720 	sp = NULL;
1721 	ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1722 				  ref_realm, NULL);
1723 	if (ret)
1724 	    goto out;
1725 	free(spn);
1726         spn = NULL;
1727 	ret = krb5_unparse_name(context, sp, &spn);
1728 	if (ret)
1729 	    goto out;
1730 
1731 	goto server_lookup;
1732     } else if (ret) {
1733 	const char *new_rlm, *msg;
1734 	Realm req_rlm;
1735 	krb5_realm *realms;
1736 
1737 	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1738             if (capath == NULL) {
1739                 /* With referalls, hierarchical capaths are always enabled */
1740                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1741                                          req_rlm, TRUE, &capath, &num_capath);
1742                 if (ret2) {
1743                     ret = ret2;
1744                     goto out;
1745                 }
1746             }
1747             new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1748             if (new_rlm) {
1749                 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1750                         "realm %s not found, trying %s", tgt->crealm,
1751                         our_realm, req_rlm, new_rlm);
1752 
1753                 free(ref_realm);
1754                 ref_realm = strdup(new_rlm);
1755                 if (ref_realm == NULL) {
1756                     ret = krb5_enomem(context);
1757                     goto out;
1758                 }
1759 
1760                 krb5_free_principal(context, sp);
1761                 sp = NULL;
1762                 krb5_make_principal(context, &sp, r,
1763                                     KRB5_TGS_NAME, ref_realm, NULL);
1764                 free(spn);
1765                 spn = NULL;
1766                 ret = krb5_unparse_name(context, sp, &spn);
1767                 if (ret)
1768                     goto out;
1769                 goto server_lookup;
1770             }
1771 	} else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
1772 	    if (strcmp(realms[0], sp->realm) != 0) {
1773 		kdc_log(context, config, 5,
1774 			"Returning a referral to realm %s for "
1775 			"server %s that was not found",
1776 			realms[0], spn);
1777 		krb5_free_principal(context, sp);
1778                 sp = NULL;
1779 		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1780 				    realms[0], NULL);
1781 		free(spn);
1782                 spn = NULL;
1783 		ret = krb5_unparse_name(context, sp, &spn);
1784 		if (ret) {
1785 		    krb5_free_host_realm(context, realms);
1786 		    goto out;
1787 		}
1788 
1789                 free(ref_realm);
1790 		ref_realm = strdup(realms[0]);
1791 
1792 		krb5_free_host_realm(context, realms);
1793 		goto server_lookup;
1794 	    }
1795 	    krb5_free_host_realm(context, realms);
1796 	}
1797 	msg = krb5_get_error_message(context, ret);
1798 	kdc_log(context, config, 0,
1799 		"Server not found in database: %s: %s", spn, msg);
1800 	krb5_free_error_message(context, msg);
1801 	if (ret == HDB_ERR_NOENTRY)
1802 	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1803 	goto out;
1804     }
1805 
1806     /* the name returned to the client depend on what was asked for,
1807      * return canonical name if kdc_options.canonicalize was set, the
1808      * client wants the true name of the principal, if not it just
1809      * wants the name its asked for.
1810      */
1811 
1812     if (b->kdc_options.canonicalize)
1813 	rsp = server->entry.principal;
1814     else
1815 	rsp = sp;
1816 
1817 
1818     /*
1819      * Select enctype, return key and kvno.
1820      */
1821 
1822     {
1823 	krb5_enctype etype;
1824 
1825 	if(b->kdc_options.enc_tkt_in_skey) {
1826 	    size_t i;
1827 	    ekey = &adtkt.key;
1828 	    for(i = 0; i < b->etype.len; i++)
1829 		if (b->etype.val[i] == adtkt.key.keytype)
1830 		    break;
1831 	    if(i == b->etype.len) {
1832 		kdc_log(context, config, 0,
1833 			"Addition ticket have not matching etypes");
1834 		krb5_clear_error_message(context);
1835 		ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1836 		goto out;
1837 	    }
1838 	    etype = b->etype.val[i];
1839 	    kvno = 0;
1840 	} else {
1841 	    Key *skey;
1842 
1843 	    ret = _kdc_find_etype(context,
1844 				  krb5_principal_is_krbtgt(context, sp) ?
1845 				  config->tgt_use_strongest_session_key :
1846 				  config->svc_use_strongest_session_key, FALSE,
1847 				  server, b->etype.val, b->etype.len, &etype,
1848 				  NULL);
1849 	    if(ret) {
1850 		kdc_log(context, config, 0,
1851 			"Server (%s) has no support for etypes", spn);
1852 		goto out;
1853 	    }
1854 	    ret = _kdc_get_preferred_key(context, config, server, spn,
1855 					 NULL, &skey);
1856 	    if(ret) {
1857 		kdc_log(context, config, 0,
1858 			"Server (%s) has no supported etypes", spn);
1859 		goto out;
1860 	    }
1861 	    ekey = &skey->key;
1862 	    kvno = server->entry.kvno;
1863 	}
1864 
1865 	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1866 	if (ret)
1867 	    goto out;
1868     }
1869 
1870     /*
1871      * Check that service is in the same realm as the krbtgt. If it's
1872      * not the same, it's someone that is using a uni-directional trust
1873      * backward.
1874      */
1875 
1876     /*
1877      * Validate authoriation data
1878      */
1879 
1880     ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1881 			  krbtgt_etype, &tkey_check);
1882     if(ret) {
1883 	kdc_log(context, config, 0,
1884 		    "Failed to find key for krbtgt PAC check");
1885 	goto out;
1886     }
1887 
1888     /*
1889      * Now refetch the primary krbtgt, and get the current kvno (the
1890      * sign check may have been on an old kvno, and the server may
1891      * have been an incoming trust)
1892      */
1893 
1894     ret = krb5_make_principal(context,
1895                               &krbtgt_out_principal,
1896                               our_realm,
1897                               KRB5_TGS_NAME,
1898                               our_realm,
1899                               NULL);
1900     if (ret) {
1901         kdc_log(context, config, 0,
1902                 "Failed to make krbtgt principal name object for "
1903                 "authz-data signatures");
1904         goto out;
1905     }
1906     ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1907     if (ret) {
1908         kdc_log(context, config, 0,
1909                 "Failed to make krbtgt principal name object for "
1910                 "authz-data signatures");
1911         goto out;
1912     }
1913 
1914     ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1915 			HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1916     if (ret) {
1917 	char *ktpn = NULL;
1918 	ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1919 	kdc_log(context, config, 0,
1920 		"No such principal %s (needed for authz-data signature keys) "
1921 		"while processing TGS-REQ for service %s with krbtg %s",
1922 		krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1923 	free(ktpn);
1924 	ret = KRB5KRB_AP_ERR_NOT_US;
1925 	goto out;
1926     }
1927 
1928     /*
1929      * The first realm is the realm of the service, the second is
1930      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1931      * encrypted to.  The redirection via the krbtgt_out entry allows
1932      * the DB to possibly correct the case of the realm (Samba4 does
1933      * this) before the strcmp()
1934      */
1935     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1936 	       krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1937 	char *ktpn;
1938 	ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1939 	kdc_log(context, config, 0,
1940 		"Request with wrong krbtgt: %s",
1941 		(ret == 0) ? ktpn : "<unknown>");
1942 	if(ret == 0)
1943 	    free(ktpn);
1944 	ret = KRB5KRB_AP_ERR_NOT_US;
1945 	goto out;
1946     }
1947 
1948     ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1949 				 NULL, &tkey_sign);
1950     if (ret) {
1951 	kdc_log(context, config, 0,
1952 		    "Failed to find key for krbtgt PAC signature");
1953 	goto out;
1954     }
1955     ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1956 			  tkey_sign->key.keytype, &tkey_sign);
1957     if(ret) {
1958 	kdc_log(context, config, 0,
1959 		    "Failed to find key for krbtgt PAC signature");
1960 	goto out;
1961     }
1962 
1963     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1964 			NULL, &clientdb, &client);
1965     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1966 	/* This is OK, we are just trying to find out if they have
1967 	 * been disabled or deleted in the meantime, missing secrets
1968 	 * is OK */
1969     } else if(ret){
1970 	const char *krbtgt_realm, *msg;
1971 
1972 	/*
1973 	 * If the client belongs to the same realm as our krbtgt, it
1974 	 * should exist in the local database.
1975 	 *
1976 	 */
1977 
1978 	krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1979 
1980 	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1981 	    if (ret == HDB_ERR_NOENTRY)
1982 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1983 	    kdc_log(context, config, 1, "Client no longer in database: %s",
1984 		    cpn);
1985 	    goto out;
1986 	}
1987 
1988 	msg = krb5_get_error_message(context, ret);
1989 	kdc_log(context, config, 1, "Client not found in database: %s", msg);
1990 	krb5_free_error_message(context, msg);
1991     }
1992 
1993     ret = check_PAC(context, config, cp, NULL,
1994 		    client, server, krbtgt,
1995 		    &tkey_check->key,
1996 		    ekey, &tkey_sign->key,
1997 		    tgt, &rspac, &signedpath);
1998     if (ret) {
1999 	const char *msg = krb5_get_error_message(context, ret);
2000 	kdc_log(context, config, 0,
2001 		"Verify PAC failed for %s (%s) from %s with %s",
2002 		spn, cpn, from, msg);
2003 	krb5_free_error_message(context, msg);
2004 	goto out;
2005     }
2006 
2007     /* also check the krbtgt for signature */
2008     ret = check_KRB5SignedPath(context,
2009 			       config,
2010 			       krbtgt,
2011 			       cp,
2012 			       tgt,
2013 			       &spp,
2014 			       &signedpath);
2015     if (ret) {
2016 	const char *msg = krb5_get_error_message(context, ret);
2017 	kdc_log(context, config, 0,
2018 		"KRB5SignedPath check failed for %s (%s) from %s with %s",
2019 		spn, cpn, from, msg);
2020 	krb5_free_error_message(context, msg);
2021 	goto out;
2022     }
2023 
2024     /*
2025      * Process request
2026      */
2027 
2028     /* by default the tgt principal matches the client principal */
2029     tp = cp;
2030     tpn = cpn;
2031 
2032     if (client) {
2033 	const PA_DATA *sdata;
2034 	int i = 0;
2035 
2036 	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
2037 	if (sdata) {
2038 	    krb5_crypto crypto;
2039 	    krb5_data datack;
2040 	    PA_S4U2Self self;
2041 	    const char *str;
2042 
2043 	    ret = decode_PA_S4U2Self(sdata->padata_value.data,
2044 				     sdata->padata_value.length,
2045 				     &self, NULL);
2046 	    if (ret) {
2047 		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
2048 		goto out;
2049 	    }
2050 
2051 	    if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
2052 		free_PA_S4U2Self(&self);
2053 		kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
2054 		ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
2055 		goto out;
2056 	    }
2057 
2058 	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
2059 	    if (ret)
2060 		goto out;
2061 
2062 	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
2063 	    if (ret) {
2064 		const char *msg = krb5_get_error_message(context, ret);
2065 		free_PA_S4U2Self(&self);
2066 		krb5_data_free(&datack);
2067 		kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
2068 		krb5_free_error_message(context, msg);
2069 		goto out;
2070 	    }
2071 
2072 	    /* Allow HMAC_MD5 checksum with any key type */
2073 	    if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
2074 		unsigned char csdata[16];
2075 		Checksum cs;
2076 
2077 		cs.checksum.length = sizeof(csdata);
2078 		cs.checksum.data = &csdata;
2079 
2080 		ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
2081 					      datack.data, datack.length,
2082 					      KRB5_KU_OTHER_CKSUM, &cs);
2083 		if (ret == 0 &&
2084 		    krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
2085 		    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2086 	    }
2087 	    else {
2088 		ret = krb5_verify_checksum(context,
2089 					   crypto,
2090 					   KRB5_KU_OTHER_CKSUM,
2091 					   datack.data,
2092 					   datack.length,
2093 					   &self.cksum);
2094 	    }
2095 	    krb5_data_free(&datack);
2096 	    krb5_crypto_destroy(context, crypto);
2097 	    if (ret) {
2098 		const char *msg = krb5_get_error_message(context, ret);
2099 		free_PA_S4U2Self(&self);
2100 		kdc_log(context, config, 0,
2101 			"krb5_verify_checksum failed for S4U2Self: %s", msg);
2102 		krb5_free_error_message(context, msg);
2103 		goto out;
2104 	    }
2105 
2106 	    ret = _krb5_principalname2krb5_principal(context,
2107 						     &tp,
2108 						     self.name,
2109 						     self.realm);
2110 	    free_PA_S4U2Self(&self);
2111 	    if (ret)
2112 		goto out;
2113 
2114 	    ret = krb5_unparse_name(context, tp, &tpn);
2115 	    if (ret)
2116 		goto out;
2117 
2118 	    ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2119 				NULL, &s4u2self_impersonated_clientdb,
2120 				&s4u2self_impersonated_client);
2121 	    if (ret) {
2122 		const char *msg;
2123 
2124 		/*
2125 		 * If the client belongs to the same realm as our krbtgt, it
2126 		 * should exist in the local database.
2127 		 *
2128 		 */
2129 
2130 		if (ret == HDB_ERR_NOENTRY)
2131 		    ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2132 		msg = krb5_get_error_message(context, ret);
2133 		kdc_log(context, config, 2,
2134 			"S4U2Self principal to impersonate %s not found in database: %s",
2135 			tpn, msg);
2136 		krb5_free_error_message(context, msg);
2137 		goto out;
2138 	    }
2139 
2140 	    /* Ignore require_pwchange and pw_end attributes (as Windows does),
2141 	     * since S4U2Self is not password authentication. */
2142 	    s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE;
2143 	    free(s4u2self_impersonated_client->entry.pw_end);
2144 	    s4u2self_impersonated_client->entry.pw_end = NULL;
2145 
2146 	    ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
2147 				  NULL, NULL, FALSE);
2148 	    if (ret)
2149 		goto out;
2150 
2151 	    /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2152 	    if(rspac.data) {
2153 		krb5_pac p = NULL;
2154 		krb5_data_free(&rspac);
2155 		ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2156 		if (ret) {
2157 		    kdc_log(context, config, 0, "PAC generation failed for -- %s",
2158 			    tpn);
2159 		    goto out;
2160 		}
2161 		if (p != NULL) {
2162 		    ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2163 					 s4u2self_impersonated_client->entry.principal,
2164 					 ekey, &tkey_sign->key,
2165 					 &rspac);
2166 		    krb5_pac_free(context, p);
2167 		    if (ret) {
2168 			kdc_log(context, config, 0, "PAC signing failed for -- %s",
2169 				tpn);
2170 			goto out;
2171 		    }
2172 		}
2173 	    }
2174 
2175 	    /*
2176 	     * Check that service doing the impersonating is
2177 	     * requesting a ticket to it-self.
2178 	     */
2179 	    ret = check_s4u2self(context, config, clientdb, client, sp);
2180 	    if (ret) {
2181 		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2182 			"to impersonate to service "
2183 			"(tried for user %s to service %s)",
2184 			cpn, tpn, spn);
2185 		goto out;
2186 	    }
2187 
2188 	    /*
2189 	     * If the service isn't trusted for authentication to
2190 	     * delegation or if the impersonate client is disallowed
2191 	     * forwardable, remove the forwardable flag.
2192 	     */
2193 
2194 	    if (client->entry.flags.trusted_for_delegation &&
2195 		s4u2self_impersonated_client->entry.flags.forwardable) {
2196 		str = "[forwardable]";
2197 	    } else {
2198 		b->kdc_options.forwardable = 0;
2199 		str = "";
2200 	    }
2201 	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2202 		    "service %s %s", cpn, tpn, spn, str);
2203 	}
2204     }
2205 
2206     /*
2207      * Constrained delegation
2208      */
2209 
2210     if (client != NULL
2211 	&& b->additional_tickets != NULL
2212 	&& b->additional_tickets->len != 0
2213 	&& b->kdc_options.cname_in_addl_tkt
2214 	&& b->kdc_options.enc_tkt_in_skey == 0)
2215     {
2216 	int ad_signedpath = 0;
2217 	Key *clientkey;
2218 	Ticket *t;
2219 
2220 	/*
2221 	 * Require that the KDC have issued the service's krbtgt (not
2222 	 * self-issued ticket with kimpersonate(1).
2223 	 */
2224 	if (!signedpath) {
2225 	    ret = KRB5KDC_ERR_BADOPTION;
2226 	    kdc_log(context, config, 0,
2227 		    "Constrained delegation done on service ticket %s/%s",
2228 		    cpn, spn);
2229 	    goto out;
2230 	}
2231 
2232 	t = &b->additional_tickets->val[0];
2233 
2234 	ret = hdb_enctype2key(context, &client->entry,
2235 			      hdb_kvno2keys(context, &client->entry,
2236 					    t->enc_part.kvno ? * t->enc_part.kvno : 0),
2237 			      t->enc_part.etype, &clientkey);
2238 	if(ret){
2239 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2240 	    goto out;
2241 	}
2242 
2243 	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2244 	if (ret) {
2245 	    kdc_log(context, config, 0,
2246 		    "failed to decrypt ticket for "
2247 		    "constrained delegation from %s to %s ", cpn, spn);
2248 	    goto out;
2249 	}
2250 
2251 	ret = _krb5_principalname2krb5_principal(context,
2252 						 &tp,
2253 						 adtkt.cname,
2254 						 adtkt.crealm);
2255 	if (ret)
2256 	    goto out;
2257 
2258 	ret = krb5_unparse_name(context, tp, &tpn);
2259 	if (ret)
2260 	    goto out;
2261 
2262 	ret = _krb5_principalname2krb5_principal(context,
2263 						 &dp,
2264 						 t->sname,
2265 						 t->realm);
2266 	if (ret)
2267 	    goto out;
2268 
2269 	ret = krb5_unparse_name(context, dp, &dpn);
2270 	if (ret)
2271 	    goto out;
2272 
2273 	/* check that ticket is valid */
2274 	if (adtkt.flags.forwardable == 0) {
2275 	    kdc_log(context, config, 0,
2276 		    "Missing forwardable flag on ticket for "
2277 		    "constrained delegation from %s (%s) as %s to %s ",
2278 		    cpn, dpn, tpn, spn);
2279 	    ret = KRB5KDC_ERR_BADOPTION;
2280 	    goto out;
2281 	}
2282 
2283 	ret = check_constrained_delegation(context, config, clientdb,
2284 					   client, server, sp);
2285 	if (ret) {
2286 	    kdc_log(context, config, 0,
2287 		    "constrained delegation from %s (%s) as %s to %s not allowed",
2288 		    cpn, dpn, tpn, spn);
2289 	    goto out;
2290 	}
2291 
2292 	ret = verify_flags(context, config, &adtkt, tpn);
2293 	if (ret) {
2294 	    goto out;
2295 	}
2296 
2297 	krb5_data_free(&rspac);
2298 
2299 	/*
2300 	 * generate the PAC for the user.
2301 	 *
2302 	 * TODO: pass in t->sname and t->realm and build
2303 	 * a S4U_DELEGATION_INFO blob to the PAC.
2304 	 */
2305 	ret = check_PAC(context, config, tp, dp,
2306 			client, server, krbtgt,
2307 			&clientkey->key,
2308 			ekey, &tkey_sign->key,
2309 			&adtkt, &rspac, &ad_signedpath);
2310 	if (ret) {
2311 	    const char *msg = krb5_get_error_message(context, ret);
2312 	    kdc_log(context, config, 0,
2313 		    "Verify delegated PAC failed to %s for client"
2314 		    "%s (%s) as %s from %s with %s",
2315 		    spn, cpn, dpn, tpn, from, msg);
2316 	    krb5_free_error_message(context, msg);
2317 	    goto out;
2318 	}
2319 
2320 	/*
2321 	 * Check that the KDC issued the user's ticket.
2322 	 */
2323 	ret = check_KRB5SignedPath(context,
2324 				   config,
2325 				   krbtgt,
2326 				   cp,
2327 				   &adtkt,
2328 				   NULL,
2329 				   &ad_signedpath);
2330 	if (ret) {
2331 	    const char *msg = krb5_get_error_message(context, ret);
2332 	    kdc_log(context, config, 0,
2333 		    "KRB5SignedPath check from service %s failed "
2334 		    "for delegation to %s for client %s (%s)"
2335 		    "from %s failed with %s",
2336 		    spn, tpn, dpn, cpn, from, msg);
2337 	    krb5_free_error_message(context, msg);
2338 	    goto out;
2339 	}
2340 
2341 	if (!ad_signedpath) {
2342 	    ret = KRB5KDC_ERR_BADOPTION;
2343 	    kdc_log(context, config, 0,
2344 		    "Ticket not signed with PAC nor SignedPath service %s failed "
2345 		    "for delegation to %s for client %s (%s)"
2346 		    "from %s",
2347 		    spn, tpn, dpn, cpn, from);
2348 	    goto out;
2349 	}
2350 
2351 	kdc_log(context, config, 0, "constrained delegation for %s "
2352 		"from %s (%s) to %s", tpn, cpn, dpn, spn);
2353     }
2354 
2355     /*
2356      * Check flags
2357      */
2358 
2359     ret = kdc_check_flags(context, config,
2360 			  client, cpn,
2361 			  server, spn,
2362 			  FALSE);
2363     if(ret)
2364 	goto out;
2365 
2366     if((b->kdc_options.validate || b->kdc_options.renew) &&
2367        !krb5_principal_compare(context,
2368 			       krbtgt->entry.principal,
2369 			       server->entry.principal)){
2370 	kdc_log(context, config, 0, "Inconsistent request.");
2371 	ret = KRB5KDC_ERR_SERVER_NOMATCH;
2372 	goto out;
2373     }
2374 
2375     /* check for valid set of addresses */
2376     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2377 	ret = KRB5KRB_AP_ERR_BADADDR;
2378 	kdc_log(context, config, 0, "Request from wrong address");
2379 	goto out;
2380     }
2381 
2382     /* check local and per-principal anonymous ticket issuance policy */
2383     if (is_anon_tgs_request_p(b, tgt)) {
2384 	ret = _kdc_check_anon_policy(context, config, client, server);
2385 	if (ret)
2386 	    goto out;
2387     }
2388 
2389     /*
2390      * If this is an referral, add server referral data to the
2391      * auth_data reply .
2392      */
2393     if (ref_realm) {
2394 	PA_DATA pa;
2395 	krb5_crypto crypto;
2396 
2397 	kdc_log(context, config, 0,
2398 		"Adding server referral to %s", ref_realm);
2399 
2400 	ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2401 	if (ret)
2402 	    goto out;
2403 
2404 	ret = build_server_referral(context, config, crypto, ref_realm,
2405 				    NULL, s, &pa.padata_value);
2406 	krb5_crypto_destroy(context, crypto);
2407 	if (ret) {
2408 	    kdc_log(context, config, 0,
2409 		    "Failed building server referral");
2410 	    goto out;
2411 	}
2412 	pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2413 
2414 	ret = add_METHOD_DATA(&enc_pa_data, &pa);
2415 	krb5_data_free(&pa.padata_value);
2416 	if (ret) {
2417 	    kdc_log(context, config, 0,
2418 		    "Add server referral METHOD-DATA failed");
2419 	    goto out;
2420 	}
2421     }
2422 
2423     /*
2424      *
2425      */
2426 
2427     ret = tgs_make_reply(context,
2428 			 config,
2429 			 b,
2430 			 tp,
2431 			 tgt,
2432 			 replykey,
2433 			 rk_is_subkey,
2434 			 ekey,
2435 			 &sessionkey,
2436 			 kvno,
2437 			 *auth_data,
2438 			 server,
2439 			 rsp,
2440 			 spn,
2441 			 client,
2442 			 cp,
2443                          tgt_realm,
2444 			 krbtgt_out,
2445 			 tkey_sign->key.keytype,
2446 			 spp,
2447 			 &rspac,
2448 			 &enc_pa_data,
2449 			 e_text,
2450 			 reply);
2451 
2452 out:
2453     if (tpn != cpn)
2454 	    free(tpn);
2455     free(spn);
2456     free(cpn);
2457     free(dpn);
2458     free(krbtgt_out_n);
2459     _krb5_free_capath(context, capath);
2460 
2461     krb5_data_free(&rspac);
2462     krb5_free_keyblock_contents(context, &sessionkey);
2463     if(krbtgt_out)
2464 	_kdc_free_ent(context, krbtgt_out);
2465     if(server)
2466 	_kdc_free_ent(context, server);
2467     if(client)
2468 	_kdc_free_ent(context, client);
2469     if(s4u2self_impersonated_client)
2470 	_kdc_free_ent(context, s4u2self_impersonated_client);
2471 
2472     if (tp && tp != cp)
2473 	krb5_free_principal(context, tp);
2474     krb5_free_principal(context, cp);
2475     krb5_free_principal(context, dp);
2476     krb5_free_principal(context, sp);
2477     krb5_free_principal(context, krbtgt_out_principal);
2478     free(ref_realm);
2479     free_METHOD_DATA(&enc_pa_data);
2480 
2481     free_EncTicketPart(&adtkt);
2482 
2483     return ret;
2484 }
2485 
2486 /*
2487  *
2488  */
2489 
2490 krb5_error_code
_kdc_tgs_rep(krb5_context context,krb5_kdc_configuration * config,KDC_REQ * req,krb5_data * data,const char * from,struct sockaddr * from_addr,int datagram_reply)2491 _kdc_tgs_rep(krb5_context context,
2492 	     krb5_kdc_configuration *config,
2493 	     KDC_REQ *req,
2494 	     krb5_data *data,
2495 	     const char *from,
2496 	     struct sockaddr *from_addr,
2497 	     int datagram_reply)
2498 {
2499     AuthorizationData *auth_data = NULL;
2500     krb5_error_code ret;
2501     int i = 0;
2502     const PA_DATA *tgs_req;
2503 
2504     hdb_entry_ex *krbtgt = NULL;
2505     krb5_ticket *ticket = NULL;
2506     const char *e_text = NULL;
2507     krb5_enctype krbtgt_etype = ETYPE_NULL;
2508 
2509     krb5_keyblock *replykey = NULL;
2510     int rk_is_subkey = 0;
2511     time_t *csec = NULL;
2512     int *cusec = NULL;
2513 
2514     if(req->padata == NULL){
2515 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2516 	kdc_log(context, config, 0,
2517 		"TGS-REQ from %s without PA-DATA", from);
2518 	goto out;
2519     }
2520 
2521     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2522 
2523     if(tgs_req == NULL){
2524 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2525 
2526 	kdc_log(context, config, 0,
2527 		"TGS-REQ from %s without PA-TGS-REQ", from);
2528 	goto out;
2529     }
2530     ret = tgs_parse_request(context, config,
2531 			    &req->req_body, tgs_req,
2532 			    &krbtgt,
2533 			    &krbtgt_etype,
2534 			    &ticket,
2535 			    &e_text,
2536 			    from, from_addr,
2537 			    &csec, &cusec,
2538 			    &auth_data,
2539 			    &replykey,
2540 			    &rk_is_subkey);
2541     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2542 	/* kdc_log() is called in tgs_parse_request() */
2543 	goto out;
2544     }
2545     if (ret) {
2546 	kdc_log(context, config, 0,
2547 		"Failed parsing TGS-REQ from %s", from);
2548 	goto out;
2549     }
2550 
2551     {
2552 	const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2553 	if (pa)
2554 	    kdc_log(context, config, 10, "Got TGS FAST request");
2555     }
2556 
2557 
2558     ret = tgs_build_reply(context,
2559 			  config,
2560 			  req,
2561 			  &req->req_body,
2562 			  krbtgt,
2563 			  krbtgt_etype,
2564 			  replykey,
2565 			  rk_is_subkey,
2566 			  ticket,
2567 			  data,
2568 			  from,
2569 			  &e_text,
2570 			  &auth_data,
2571 			  from_addr);
2572     if (ret) {
2573 	kdc_log(context, config, 0,
2574 		"Failed building TGS-REP to %s", from);
2575 	goto out;
2576     }
2577 
2578     /* */
2579     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2580 	krb5_data_free(data);
2581 	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2582 	e_text = "Reply packet too large";
2583     }
2584 
2585 out:
2586     if (replykey)
2587 	krb5_free_keyblock(context, replykey);
2588 
2589     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2590 	/* XXX add fast wrapping on the error */
2591 	METHOD_DATA error_method = { 0, NULL };
2592 
2593 
2594 	kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2595 	ret = _kdc_fast_mk_error(context, NULL,
2596 				 &error_method,
2597 				 NULL,
2598 				 NULL,
2599 				 ret, NULL,
2600 				 NULL,
2601 				 NULL, NULL,
2602 				 csec, cusec,
2603 				 data);
2604 	free_METHOD_DATA(&error_method);
2605     }
2606     free(csec);
2607     free(cusec);
2608     if (ticket)
2609 	krb5_free_ticket(context, ticket);
2610     if(krbtgt)
2611 	_kdc_free_ent(context, krbtgt);
2612 
2613     if (auth_data) {
2614 	free_AuthorizationData(auth_data);
2615 	free(auth_data);
2616     }
2617 
2618     return ret;
2619 }
2620