1 /*	$NetBSD: krb5tgs.c,v 1.1.1.2 2014/04/24 12:45:27 pettai 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_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_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 = 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, 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, sp.etype, &key);
232 	    if (ret == 0)
233 		ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234 	    if (ret) {
235 		free(data.data);
236 		free_KRB5SignedPath(&sp);
237 		return ret;
238 	    }
239 	}
240 	ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
241 				   data.data, data.length,
242 				   &sp.cksum);
243 	krb5_crypto_destroy(context, crypto);
244 	free(data.data);
245 	if (ret) {
246 	    free_KRB5SignedPath(&sp);
247 	    kdc_log(context, config, 5,
248 		    "KRB5SignedPath not signed correctly, not marking as signed");
249 	    return 0;
250 	}
251 
252 	if (delegated && sp.delegated) {
253 
254 	    *delegated = malloc(sizeof(*sp.delegated));
255 	    if (*delegated == NULL) {
256 		free_KRB5SignedPath(&sp);
257 		return ENOMEM;
258 	    }
259 
260 	    ret = copy_Principals(*delegated, sp.delegated);
261 	    if (ret) {
262 		free_KRB5SignedPath(&sp);
263 		free(*delegated);
264 		*delegated = NULL;
265 		return ret;
266 	    }
267 	}
268 	free_KRB5SignedPath(&sp);
269 
270 	*signedpath = 1;
271     }
272 
273     return 0;
274 }
275 
276 /*
277  *
278  */
279 
280 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 * krbtgt_check_key,const EncryptionKey * server_sign_key,const EncryptionKey * krbtgt_sign_key,EncTicketPart * tkt,krb5_data * rspac,int * signedpath)281 check_PAC(krb5_context context,
282 	  krb5_kdc_configuration *config,
283 	  const krb5_principal client_principal,
284 	  const krb5_principal delegated_proxy_principal,
285 	  hdb_entry_ex *client,
286 	  hdb_entry_ex *server,
287 	  hdb_entry_ex *krbtgt,
288 	  const EncryptionKey *server_check_key,
289 	  const EncryptionKey *krbtgt_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, krbtgt_check_key);
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 /*
372  *
373  */
374 
375 static krb5_error_code
check_tgs_flags(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,const EncTicketPart * tgt,EncTicketPart * et)376 check_tgs_flags(krb5_context context,
377 		krb5_kdc_configuration *config,
378 		KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
379 {
380     KDCOptions f = b->kdc_options;
381 
382     if(f.validate){
383 	if(!tgt->flags.invalid || tgt->starttime == NULL){
384 	    kdc_log(context, config, 0,
385 		    "Bad request to validate ticket");
386 	    return KRB5KDC_ERR_BADOPTION;
387 	}
388 	if(*tgt->starttime > kdc_time){
389 	    kdc_log(context, config, 0,
390 		    "Early request to validate ticket");
391 	    return KRB5KRB_AP_ERR_TKT_NYV;
392 	}
393 	/* XXX  tkt = tgt */
394 	et->flags.invalid = 0;
395     }else if(tgt->flags.invalid){
396 	kdc_log(context, config, 0,
397 		"Ticket-granting ticket has INVALID flag set");
398 	return KRB5KRB_AP_ERR_TKT_INVALID;
399     }
400 
401     if(f.forwardable){
402 	if(!tgt->flags.forwardable){
403 	    kdc_log(context, config, 0,
404 		    "Bad request for forwardable ticket");
405 	    return KRB5KDC_ERR_BADOPTION;
406 	}
407 	et->flags.forwardable = 1;
408     }
409     if(f.forwarded){
410 	if(!tgt->flags.forwardable){
411 	    kdc_log(context, config, 0,
412 		    "Request to forward non-forwardable ticket");
413 	    return KRB5KDC_ERR_BADOPTION;
414 	}
415 	et->flags.forwarded = 1;
416 	et->caddr = b->addresses;
417     }
418     if(tgt->flags.forwarded)
419 	et->flags.forwarded = 1;
420 
421     if(f.proxiable){
422 	if(!tgt->flags.proxiable){
423 	    kdc_log(context, config, 0,
424 		    "Bad request for proxiable ticket");
425 	    return KRB5KDC_ERR_BADOPTION;
426 	}
427 	et->flags.proxiable = 1;
428     }
429     if(f.proxy){
430 	if(!tgt->flags.proxiable){
431 	    kdc_log(context, config, 0,
432 		    "Request to proxy non-proxiable ticket");
433 	    return KRB5KDC_ERR_BADOPTION;
434 	}
435 	et->flags.proxy = 1;
436 	et->caddr = b->addresses;
437     }
438     if(tgt->flags.proxy)
439 	et->flags.proxy = 1;
440 
441     if(f.allow_postdate){
442 	if(!tgt->flags.may_postdate){
443 	    kdc_log(context, config, 0,
444 		    "Bad request for post-datable ticket");
445 	    return KRB5KDC_ERR_BADOPTION;
446 	}
447 	et->flags.may_postdate = 1;
448     }
449     if(f.postdated){
450 	if(!tgt->flags.may_postdate){
451 	    kdc_log(context, config, 0,
452 		    "Bad request for postdated ticket");
453 	    return KRB5KDC_ERR_BADOPTION;
454 	}
455 	if(b->from)
456 	    *et->starttime = *b->from;
457 	et->flags.postdated = 1;
458 	et->flags.invalid = 1;
459     }else if(b->from && *b->from > kdc_time + context->max_skew){
460 	kdc_log(context, config, 0, "Ticket cannot be postdated");
461 	return KRB5KDC_ERR_CANNOT_POSTDATE;
462     }
463 
464     if(f.renewable){
465 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
466 	    kdc_log(context, config, 0,
467 		    "Bad request for renewable ticket");
468 	    return KRB5KDC_ERR_BADOPTION;
469 	}
470 	et->flags.renewable = 1;
471 	ALLOC(et->renew_till);
472 	_kdc_fix_time(&b->rtime);
473 	*et->renew_till = *b->rtime;
474     }
475     if(f.renew){
476 	time_t old_life;
477 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
478 	    kdc_log(context, config, 0,
479 		    "Request to renew non-renewable ticket");
480 	    return KRB5KDC_ERR_BADOPTION;
481 	}
482 	old_life = tgt->endtime;
483 	if(tgt->starttime)
484 	    old_life -= *tgt->starttime;
485 	else
486 	    old_life -= tgt->authtime;
487 	et->endtime = *et->starttime + old_life;
488 	if (et->renew_till != NULL)
489 	    et->endtime = min(*et->renew_till, et->endtime);
490     }
491 
492 #if 0
493     /* checks for excess flags */
494     if(f.request_anonymous && !config->allow_anonymous){
495 	kdc_log(context, config, 0,
496 		"Request for anonymous ticket");
497 	return KRB5KDC_ERR_BADOPTION;
498     }
499 #endif
500     return 0;
501 }
502 
503 /*
504  * Determine if constrained delegation is allowed from this client to this server
505  */
506 
507 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)508 check_constrained_delegation(krb5_context context,
509 			     krb5_kdc_configuration *config,
510 			     HDB *clientdb,
511 			     hdb_entry_ex *client,
512 			     hdb_entry_ex *server,
513 			     krb5_const_principal target)
514 {
515     const HDB_Ext_Constrained_delegation_acl *acl;
516     krb5_error_code ret;
517     size_t i;
518 
519     /*
520      * constrained_delegation (S4U2Proxy) only works within
521      * the same realm. We use the already canonicalized version
522      * of the principals here, while "target" is the principal
523      * provided by the client.
524      */
525     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
526 	ret = KRB5KDC_ERR_BADOPTION;
527 	kdc_log(context, config, 0,
528 	    "Bad request for constrained delegation");
529 	return ret;
530     }
531 
532     if (clientdb->hdb_check_constrained_delegation) {
533 	ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
534 	if (ret == 0)
535 	    return 0;
536     } else {
537 	/* if client delegates to itself, that ok */
538 	if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
539 	    return 0;
540 
541 	ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
542 	if (ret) {
543 	    krb5_clear_error_message(context);
544 	    return ret;
545 	}
546 
547 	if (acl) {
548 	    for (i = 0; i < acl->len; i++) {
549 		if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
550 		    return 0;
551 	    }
552 	}
553 	ret = KRB5KDC_ERR_BADOPTION;
554     }
555     kdc_log(context, config, 0,
556 	    "Bad request for constrained delegation");
557     return ret;
558 }
559 
560 /*
561  * Determine if s4u2self is allowed from this client to this server
562  *
563  * For example, regardless of the principal being impersonated, if the
564  * 'client' and 'server' are the same, then it's safe.
565  */
566 
567 static krb5_error_code
check_s4u2self(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,krb5_const_principal server)568 check_s4u2self(krb5_context context,
569 	       krb5_kdc_configuration *config,
570 	       HDB *clientdb,
571 	       hdb_entry_ex *client,
572 	       krb5_const_principal server)
573 {
574     krb5_error_code ret;
575 
576     /* if client does a s4u2self to itself, that ok */
577     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
578 	return 0;
579 
580     if (clientdb->hdb_check_s4u2self) {
581 	ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
582 	if (ret == 0)
583 	    return 0;
584     } else {
585 	ret = KRB5KDC_ERR_BADOPTION;
586     }
587     return ret;
588 }
589 
590 /*
591  *
592  */
593 
594 static krb5_error_code
verify_flags(krb5_context context,krb5_kdc_configuration * config,const EncTicketPart * et,const char * pstr)595 verify_flags (krb5_context context,
596 	      krb5_kdc_configuration *config,
597 	      const EncTicketPart *et,
598 	      const char *pstr)
599 {
600     if(et->endtime < kdc_time){
601 	kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
602 	return KRB5KRB_AP_ERR_TKT_EXPIRED;
603     }
604     if(et->flags.invalid){
605 	kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
606 	return KRB5KRB_AP_ERR_TKT_NYV;
607     }
608     return 0;
609 }
610 
611 /*
612  *
613  */
614 
615 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)616 fix_transited_encoding(krb5_context context,
617 		       krb5_kdc_configuration *config,
618 		       krb5_boolean check_policy,
619 		       const TransitedEncoding *tr,
620 		       EncTicketPart *et,
621 		       const char *client_realm,
622 		       const char *server_realm,
623 		       const char *tgt_realm)
624 {
625     krb5_error_code ret = 0;
626     char **realms, **tmp;
627     unsigned int num_realms;
628     size_t i;
629 
630     switch (tr->tr_type) {
631     case DOMAIN_X500_COMPRESS:
632 	break;
633     case 0:
634 	/*
635 	 * Allow empty content of type 0 because that is was Microsoft
636 	 * generates in their TGT.
637 	 */
638 	if (tr->contents.length == 0)
639 	    break;
640 	kdc_log(context, config, 0,
641 		"Transited type 0 with non empty content");
642 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
643     default:
644 	kdc_log(context, config, 0,
645 		"Unknown transited type: %u", tr->tr_type);
646 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
647     }
648 
649     ret = krb5_domain_x500_decode(context,
650 				  tr->contents,
651 				  &realms,
652 				  &num_realms,
653 				  client_realm,
654 				  server_realm);
655     if(ret){
656 	krb5_warn(context, ret,
657 		  "Decoding transited encoding");
658 	return ret;
659     }
660     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
661 	/* not us, so add the previous realm to transited set */
662 	if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
663 	    ret = ERANGE;
664 	    goto free_realms;
665 	}
666 	tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
667 	if(tmp == NULL){
668 	    ret = ENOMEM;
669 	    goto free_realms;
670 	}
671 	realms = tmp;
672 	realms[num_realms] = strdup(tgt_realm);
673 	if(realms[num_realms] == NULL){
674 	    ret = ENOMEM;
675 	    goto free_realms;
676 	}
677 	num_realms++;
678     }
679     if(num_realms == 0) {
680 	if(strcmp(client_realm, server_realm))
681 	    kdc_log(context, config, 0,
682 		    "cross-realm %s -> %s", client_realm, server_realm);
683     } else {
684 	size_t l = 0;
685 	char *rs;
686 	for(i = 0; i < num_realms; i++)
687 	    l += strlen(realms[i]) + 2;
688 	rs = malloc(l);
689 	if(rs != NULL) {
690 	    *rs = '\0';
691 	    for(i = 0; i < num_realms; i++) {
692 		if(i > 0)
693 		    strlcat(rs, ", ", l);
694 		strlcat(rs, realms[i], l);
695 	    }
696 	    kdc_log(context, config, 0,
697 		    "cross-realm %s -> %s via [%s]",
698 		    client_realm, server_realm, rs);
699 	    free(rs);
700 	}
701     }
702     if(check_policy) {
703 	ret = krb5_check_transited(context, client_realm,
704 				   server_realm,
705 				   realms, num_realms, NULL);
706 	if(ret) {
707 	    krb5_warn(context, ret, "cross-realm %s -> %s",
708 		      client_realm, server_realm);
709 	    goto free_realms;
710 	}
711 	et->flags.transited_policy_checked = 1;
712     }
713     et->transited.tr_type = DOMAIN_X500_COMPRESS;
714     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
715     if(ret)
716 	krb5_warn(context, ret, "Encoding transited encoding");
717   free_realms:
718     for(i = 0; i < num_realms; i++)
719 	free(realms[i]);
720     free(realms);
721     return ret;
722 }
723 
724 
725 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,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)726 tgs_make_reply(krb5_context context,
727 	       krb5_kdc_configuration *config,
728 	       KDC_REQ_BODY *b,
729 	       krb5_const_principal tgt_name,
730 	       const EncTicketPart *tgt,
731 	       const krb5_keyblock *replykey,
732 	       int rk_is_subkey,
733 	       const EncryptionKey *serverkey,
734 	       const krb5_keyblock *sessionkey,
735 	       krb5_kvno kvno,
736 	       AuthorizationData *auth_data,
737 	       hdb_entry_ex *server,
738 	       krb5_principal server_principal,
739 	       const char *server_name,
740 	       hdb_entry_ex *client,
741 	       krb5_principal client_principal,
742 	       hdb_entry_ex *krbtgt,
743 	       krb5_enctype krbtgt_etype,
744 	       krb5_principals spp,
745 	       const krb5_data *rspac,
746 	       const METHOD_DATA *enc_pa_data,
747 	       const char **e_text,
748 	       krb5_data *reply)
749 {
750     KDC_REP rep;
751     EncKDCRepPart ek;
752     EncTicketPart et;
753     KDCOptions f = b->kdc_options;
754     krb5_error_code ret;
755     int is_weak = 0;
756 
757     memset(&rep, 0, sizeof(rep));
758     memset(&et, 0, sizeof(et));
759     memset(&ek, 0, sizeof(ek));
760 
761     rep.pvno = 5;
762     rep.msg_type = krb_tgs_rep;
763 
764     et.authtime = tgt->authtime;
765     _kdc_fix_time(&b->till);
766     et.endtime = min(tgt->endtime, *b->till);
767     ALLOC(et.starttime);
768     *et.starttime = kdc_time;
769 
770     ret = check_tgs_flags(context, config, b, tgt, &et);
771     if(ret)
772 	goto out;
773 
774     /* We should check the transited encoding if:
775        1) the request doesn't ask not to be checked
776        2) globally enforcing a check
777        3) principal requires checking
778        4) we allow non-check per-principal, but principal isn't marked as allowing this
779        5) we don't globally allow this
780     */
781 
782 #define GLOBAL_FORCE_TRANSITED_CHECK		\
783     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
784 #define GLOBAL_ALLOW_PER_PRINCIPAL			\
785     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
786 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK			\
787     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
788 
789 /* these will consult the database in future release */
790 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)		0
791 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)	0
792 
793     ret = fix_transited_encoding(context, config,
794 				 !f.disable_transited_check ||
795 				 GLOBAL_FORCE_TRANSITED_CHECK ||
796 				 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
797 				 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
798 				    PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
799 				   GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
800 				 &tgt->transited, &et,
801 				 krb5_principal_get_realm(context, client_principal),
802 				 krb5_principal_get_realm(context, server->entry.principal),
803 				 krb5_principal_get_realm(context, krbtgt->entry.principal));
804     if(ret)
805 	goto out;
806 
807     copy_Realm(&server_principal->realm, &rep.ticket.realm);
808     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
809     copy_Realm(&tgt_name->realm, &rep.crealm);
810 /*
811     if (f.request_anonymous)
812 	_kdc_make_anonymous_principalname (&rep.cname);
813     else */
814 
815     copy_PrincipalName(&tgt_name->name, &rep.cname);
816     rep.ticket.tkt_vno = 5;
817 
818     ek.caddr = et.caddr;
819     if(et.caddr == NULL)
820 	et.caddr = tgt->caddr;
821 
822     {
823 	time_t life;
824 	life = et.endtime - *et.starttime;
825 	if(client && client->entry.max_life)
826 	    life = min(life, *client->entry.max_life);
827 	if(server->entry.max_life)
828 	    life = min(life, *server->entry.max_life);
829 	et.endtime = *et.starttime + life;
830     }
831     if(f.renewable_ok && tgt->flags.renewable &&
832        et.renew_till == NULL && et.endtime < *b->till &&
833        tgt->renew_till != NULL)
834     {
835 	et.flags.renewable = 1;
836 	ALLOC(et.renew_till);
837 	*et.renew_till = *b->till;
838     }
839     if(et.renew_till){
840 	time_t renew;
841 	renew = *et.renew_till - *et.starttime;
842 	if(client && client->entry.max_renew)
843 	    renew = min(renew, *client->entry.max_renew);
844 	if(server->entry.max_renew)
845 	    renew = min(renew, *server->entry.max_renew);
846 	*et.renew_till = *et.starttime + renew;
847     }
848 
849     if(et.renew_till){
850 	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
851 	*et.starttime = min(*et.starttime, *et.renew_till);
852 	et.endtime = min(et.endtime, *et.renew_till);
853     }
854 
855     *et.starttime = min(*et.starttime, et.endtime);
856 
857     if(*et.starttime == et.endtime){
858 	ret = KRB5KDC_ERR_NEVER_VALID;
859 	goto out;
860     }
861     if(et.renew_till && et.endtime == *et.renew_till){
862 	free(et.renew_till);
863 	et.renew_till = NULL;
864 	et.flags.renewable = 0;
865     }
866 
867     et.flags.pre_authent = tgt->flags.pre_authent;
868     et.flags.hw_authent  = tgt->flags.hw_authent;
869     et.flags.anonymous   = tgt->flags.anonymous;
870     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
871 
872     if(rspac->length) {
873 	/*
874 	 * No not need to filter out the any PAC from the
875 	 * auth_data since it's signed by the KDC.
876 	 */
877 	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
878 					  KRB5_AUTHDATA_WIN2K_PAC, rspac);
879 	if (ret)
880 	    goto out;
881     }
882 
883     if (auth_data) {
884 	unsigned int i = 0;
885 
886 	/* XXX check authdata */
887 
888 	if (et.authorization_data == NULL) {
889 	    et.authorization_data = calloc(1, sizeof(*et.authorization_data));
890 	    if (et.authorization_data == NULL) {
891 		ret = ENOMEM;
892 		krb5_set_error_message(context, ret, "malloc: out of memory");
893 		goto out;
894 	    }
895 	}
896 	for(i = 0; i < auth_data->len ; i++) {
897 	    ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
898 	    if (ret) {
899 		krb5_set_error_message(context, ret, "malloc: out of memory");
900 		goto out;
901 	    }
902 	}
903 
904 	/* Filter out type KRB5SignedPath */
905 	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
906 	if (ret == 0) {
907 	    if (et.authorization_data->len == 1) {
908 		free_AuthorizationData(et.authorization_data);
909 		free(et.authorization_data);
910 		et.authorization_data = NULL;
911 	    } else {
912 		AuthorizationData *ad = et.authorization_data;
913 		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
914 		ad->len--;
915 	    }
916 	}
917     }
918 
919     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
920     if (ret)
921 	goto out;
922     et.crealm = tgt_name->realm;
923     et.cname = tgt_name->name;
924 
925     ek.key = et.key;
926     /* MIT must have at least one last_req */
927     ek.last_req.len = 1;
928     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
929     if (ek.last_req.val == NULL) {
930 	ret = ENOMEM;
931 	goto out;
932     }
933     ek.nonce = b->nonce;
934     ek.flags = et.flags;
935     ek.authtime = et.authtime;
936     ek.starttime = et.starttime;
937     ek.endtime = et.endtime;
938     ek.renew_till = et.renew_till;
939     ek.srealm = rep.ticket.realm;
940     ek.sname = rep.ticket.sname;
941 
942     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
943 		       et.endtime, et.renew_till);
944 
945     /* Don't sign cross realm tickets, they can't be checked anyway */
946     {
947 	char *r = get_krbtgt_realm(&ek.sname);
948 
949 	if (r == NULL || strcmp(r, ek.srealm) == 0) {
950 	    ret = _kdc_add_KRB5SignedPath(context,
951 					  config,
952 					  krbtgt,
953 					  krbtgt_etype,
954 					  client_principal,
955 					  NULL,
956 					  spp,
957 					  &et);
958 	    if (ret)
959 		goto out;
960 	}
961     }
962 
963     if (enc_pa_data->len) {
964 	rep.padata = calloc(1, sizeof(*rep.padata));
965 	if (rep.padata == NULL) {
966 	    ret = ENOMEM;
967 	    goto out;
968 	}
969 	ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
970 	if (ret)
971 	    goto out;
972     }
973 
974     if (krb5_enctype_valid(context, serverkey->keytype) != 0
975 	&& _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
976     {
977 	krb5_enctype_enable(context, serverkey->keytype);
978 	is_weak = 1;
979     }
980 
981 
982     /* It is somewhat unclear where the etype in the following
983        encryption should come from. What we have is a session
984        key in the passed tgt, and a list of preferred etypes
985        *for the new ticket*. Should we pick the best possible
986        etype, given the keytype in the tgt, or should we look
987        at the etype list here as well?  What if the tgt
988        session key is DES3 and we want a ticket with a (say)
989        CAST session key. Should the DES3 etype be added to the
990        etype list, even if we don't want a session key with
991        DES3? */
992     ret = _kdc_encode_reply(context, config,
993 			    &rep, &et, &ek, serverkey->keytype,
994 			    kvno,
995 			    serverkey, 0, replykey, rk_is_subkey,
996 			    e_text, reply);
997     if (is_weak)
998 	krb5_enctype_disable(context, serverkey->keytype);
999 
1000 out:
1001     free_TGS_REP(&rep);
1002     free_TransitedEncoding(&et.transited);
1003     if(et.starttime)
1004 	free(et.starttime);
1005     if(et.renew_till)
1006 	free(et.renew_till);
1007     if(et.authorization_data) {
1008 	free_AuthorizationData(et.authorization_data);
1009 	free(et.authorization_data);
1010     }
1011     free_LastReq(&ek.last_req);
1012     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1013     free_EncryptionKey(&et.key);
1014     return ret;
1015 }
1016 
1017 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)1018 tgs_check_authenticator(krb5_context context,
1019 			krb5_kdc_configuration *config,
1020 	                krb5_auth_context ac,
1021 			KDC_REQ_BODY *b,
1022 			const char **e_text,
1023 			krb5_keyblock *key)
1024 {
1025     krb5_authenticator auth;
1026     size_t len = 0;
1027     unsigned char *buf;
1028     size_t buf_size;
1029     krb5_error_code ret;
1030     krb5_crypto crypto;
1031 
1032     krb5_auth_con_getauthenticator(context, ac, &auth);
1033     if(auth->cksum == NULL){
1034 	kdc_log(context, config, 0, "No authenticator in request");
1035 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1036 	goto out;
1037     }
1038     /*
1039      * according to RFC1510 it doesn't need to be keyed,
1040      * but according to the latest draft it needs to.
1041      */
1042     if (
1043 #if 0
1044 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1045 	||
1046 #endif
1047  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1048 	kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1049 		auth->cksum->cksumtype);
1050 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1051 	goto out;
1052     }
1053 
1054     /* XXX should not re-encode this */
1055     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1056     if(ret){
1057 	const char *msg = krb5_get_error_message(context, ret);
1058 	kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1059 	krb5_free_error_message(context, msg);
1060 	goto out;
1061     }
1062     if(buf_size != len) {
1063 	free(buf);
1064 	kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1065 	*e_text = "KDC internal error";
1066 	ret = KRB5KRB_ERR_GENERIC;
1067 	goto out;
1068     }
1069     ret = krb5_crypto_init(context, key, 0, &crypto);
1070     if (ret) {
1071 	const char *msg = krb5_get_error_message(context, ret);
1072 	free(buf);
1073 	kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1074 	krb5_free_error_message(context, msg);
1075 	goto out;
1076     }
1077     ret = krb5_verify_checksum(context,
1078 			       crypto,
1079 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
1080 			       buf,
1081 			       len,
1082 			       auth->cksum);
1083     free(buf);
1084     krb5_crypto_destroy(context, crypto);
1085     if(ret){
1086 	const char *msg = krb5_get_error_message(context, ret);
1087 	kdc_log(context, config, 0,
1088 		"Failed to verify authenticator checksum: %s", msg);
1089 	krb5_free_error_message(context, msg);
1090     }
1091 out:
1092     free_Authenticator(auth);
1093     free(auth);
1094     return ret;
1095 }
1096 
1097 /*
1098  *
1099  */
1100 
1101 static const char *
find_rpath(krb5_context context,Realm crealm,Realm srealm)1102 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1103 {
1104     const char *new_realm = krb5_config_get_string(context,
1105 						   NULL,
1106 						   "capaths",
1107 						   crealm,
1108 						   srealm,
1109 						   NULL);
1110     return new_realm;
1111 }
1112 
1113 
1114 static krb5_boolean
need_referral(krb5_context context,krb5_kdc_configuration * config,const KDCOptions * const options,krb5_principal server,krb5_realm ** realms)1115 need_referral(krb5_context context, krb5_kdc_configuration *config,
1116 	      const KDCOptions * const options, krb5_principal server,
1117 	      krb5_realm **realms)
1118 {
1119     const char *name;
1120 
1121     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1122 	return FALSE;
1123 
1124     if (server->name.name_string.len == 1)
1125 	name = server->name.name_string.val[0];
1126     else if (server->name.name_string.len > 1)
1127 	name = server->name.name_string.val[1];
1128     else
1129 	return FALSE;
1130 
1131     kdc_log(context, config, 0, "Searching referral for %s", name);
1132 
1133     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1134 }
1135 
1136 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)1137 tgs_parse_request(krb5_context context,
1138 		  krb5_kdc_configuration *config,
1139 		  KDC_REQ_BODY *b,
1140 		  const PA_DATA *tgs_req,
1141 		  hdb_entry_ex **krbtgt,
1142 		  krb5_enctype *krbtgt_etype,
1143 		  krb5_ticket **ticket,
1144 		  const char **e_text,
1145 		  const char *from,
1146 		  const struct sockaddr *from_addr,
1147 		  time_t **csec,
1148 		  int **cusec,
1149 		  AuthorizationData **auth_data,
1150 		  krb5_keyblock **replykey,
1151 		  int *rk_is_subkey)
1152 {
1153     static char failed[] = "<unparse_name failed>";
1154     krb5_ap_req ap_req;
1155     krb5_error_code ret;
1156     krb5_principal princ;
1157     krb5_auth_context ac = NULL;
1158     krb5_flags ap_req_options;
1159     krb5_flags verify_ap_req_flags;
1160     krb5_crypto crypto;
1161     Key *tkey;
1162     krb5_keyblock *subkey = NULL;
1163     unsigned usage;
1164 
1165     *auth_data = NULL;
1166     *csec  = NULL;
1167     *cusec = NULL;
1168     *replykey = NULL;
1169 
1170     memset(&ap_req, 0, sizeof(ap_req));
1171     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1172     if(ret){
1173 	const char *msg = krb5_get_error_message(context, ret);
1174 	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1175 	krb5_free_error_message(context, msg);
1176 	goto out;
1177     }
1178 
1179     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1180 	/* XXX check for ticket.sname == req.sname */
1181 	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1182 	ret = KRB5KDC_ERR_POLICY; /* ? */
1183 	goto out;
1184     }
1185 
1186     _krb5_principalname2krb5_principal(context,
1187 				       &princ,
1188 				       ap_req.ticket.sname,
1189 				       ap_req.ticket.realm);
1190 
1191     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
1192 
1193     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1194 	char *p;
1195 	ret = krb5_unparse_name(context, princ, &p);
1196 	if (ret != 0)
1197 	    p = failed;
1198 	krb5_free_principal(context, princ);
1199 	kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
1200 	if (ret == 0)
1201 	    free(p);
1202 	ret = HDB_ERR_NOT_FOUND_HERE;
1203 	goto out;
1204     } else if(ret){
1205 	const char *msg = krb5_get_error_message(context, ret);
1206 	char *p;
1207 	ret = krb5_unparse_name(context, princ, &p);
1208 	if (ret != 0)
1209 	    p = failed;
1210 	krb5_free_principal(context, princ);
1211 	kdc_log(context, config, 0,
1212 		"Ticket-granting ticket not found in database: %s", msg);
1213 	krb5_free_error_message(context, msg);
1214 	if (ret == 0)
1215 	    free(p);
1216 	ret = KRB5KRB_AP_ERR_NOT_US;
1217 	goto out;
1218     }
1219 
1220     if(ap_req.ticket.enc_part.kvno &&
1221        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1222 	char *p;
1223 
1224 	ret = krb5_unparse_name (context, princ, &p);
1225 	krb5_free_principal(context, princ);
1226 	if (ret != 0)
1227 	    p = failed;
1228 	kdc_log(context, config, 0,
1229 		"Ticket kvno = %d, DB kvno = %d (%s)",
1230 		*ap_req.ticket.enc_part.kvno,
1231 		(*krbtgt)->entry.kvno,
1232 		p);
1233 	if (ret == 0)
1234 	    free (p);
1235 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1236 	goto out;
1237     }
1238 
1239     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1240 
1241     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1242 			  ap_req.ticket.enc_part.etype, &tkey);
1243     if(ret){
1244 	char *str = NULL, *p = NULL;
1245 
1246 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1247 	krb5_unparse_name(context, princ, &p);
1248  	kdc_log(context, config, 0,
1249 		"No server key with enctype %s found for %s",
1250 		str ? str : "<unknown enctype>",
1251 		p ? p : "<unparse_name failed>");
1252 	free(str);
1253 	free(p);
1254 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1255 	goto out;
1256     }
1257 
1258     if (b->kdc_options.validate)
1259 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1260     else
1261 	verify_ap_req_flags = 0;
1262 
1263     ret = krb5_verify_ap_req2(context,
1264 			      &ac,
1265 			      &ap_req,
1266 			      princ,
1267 			      &tkey->key,
1268 			      verify_ap_req_flags,
1269 			      &ap_req_options,
1270 			      ticket,
1271 			      KRB5_KU_TGS_REQ_AUTH);
1272 
1273     krb5_free_principal(context, princ);
1274     if(ret) {
1275 	const char *msg = krb5_get_error_message(context, ret);
1276 	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1277 	krb5_free_error_message(context, msg);
1278 	goto out;
1279     }
1280 
1281     {
1282 	krb5_authenticator auth;
1283 
1284 	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1285 	if (ret == 0) {
1286 	    *csec   = malloc(sizeof(**csec));
1287 	    if (*csec == NULL) {
1288 		krb5_free_authenticator(context, &auth);
1289 		kdc_log(context, config, 0, "malloc failed");
1290 		goto out;
1291 	    }
1292 	    **csec  = auth->ctime;
1293 	    *cusec  = malloc(sizeof(**cusec));
1294 	    if (*cusec == NULL) {
1295 		krb5_free_authenticator(context, &auth);
1296 		kdc_log(context, config, 0, "malloc failed");
1297 		goto out;
1298 	    }
1299 	    **cusec  = auth->cusec;
1300 	    krb5_free_authenticator(context, &auth);
1301 	}
1302     }
1303 
1304     ret = tgs_check_authenticator(context, config,
1305 				  ac, b, e_text, &(*ticket)->ticket.key);
1306     if (ret) {
1307 	krb5_auth_con_free(context, ac);
1308 	goto out;
1309     }
1310 
1311     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1312     *rk_is_subkey = 1;
1313 
1314     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1315     if(ret){
1316 	const char *msg = krb5_get_error_message(context, ret);
1317 	krb5_auth_con_free(context, ac);
1318 	kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1319 	krb5_free_error_message(context, msg);
1320 	goto out;
1321     }
1322     if(subkey == NULL){
1323 	usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1324 	*rk_is_subkey = 0;
1325 
1326 	ret = krb5_auth_con_getkey(context, ac, &subkey);
1327 	if(ret) {
1328 	    const char *msg = krb5_get_error_message(context, ret);
1329 	    krb5_auth_con_free(context, ac);
1330 	    kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1331 	    krb5_free_error_message(context, msg);
1332 	    goto out;
1333 	}
1334     }
1335     if(subkey == NULL){
1336 	krb5_auth_con_free(context, ac);
1337 	kdc_log(context, config, 0,
1338 		"Failed to get key for enc-authorization-data");
1339 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1340 	goto out;
1341     }
1342 
1343     *replykey = subkey;
1344 
1345     if (b->enc_authorization_data) {
1346 	krb5_data ad;
1347 
1348 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
1349 	if (ret) {
1350 	    const char *msg = krb5_get_error_message(context, ret);
1351 	    krb5_auth_con_free(context, ac);
1352 	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1353 	    krb5_free_error_message(context, msg);
1354 	    goto out;
1355 	}
1356 	ret = krb5_decrypt_EncryptedData (context,
1357 					  crypto,
1358 					  usage,
1359 					  b->enc_authorization_data,
1360 					  &ad);
1361 	krb5_crypto_destroy(context, crypto);
1362 	if(ret){
1363 	    krb5_auth_con_free(context, ac);
1364 	    kdc_log(context, config, 0,
1365 		    "Failed to decrypt enc-authorization-data");
1366 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1367 	    goto out;
1368 	}
1369 	ALLOC(*auth_data);
1370 	if (*auth_data == NULL) {
1371 	    krb5_auth_con_free(context, ac);
1372 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1373 	    goto out;
1374 	}
1375 	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1376 	if(ret){
1377 	    krb5_auth_con_free(context, ac);
1378 	    free(*auth_data);
1379 	    *auth_data = NULL;
1380 	    kdc_log(context, config, 0, "Failed to decode authorization data");
1381 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1382 	    goto out;
1383 	}
1384     }
1385 
1386     krb5_auth_con_free(context, ac);
1387 
1388 out:
1389     free_AP_REQ(&ap_req);
1390 
1391     return ret;
1392 }
1393 
1394 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)1395 build_server_referral(krb5_context context,
1396 		      krb5_kdc_configuration *config,
1397 		      krb5_crypto session,
1398 		      krb5_const_realm referred_realm,
1399 		      const PrincipalName *true_principal_name,
1400 		      const PrincipalName *requested_principal,
1401 		      krb5_data *outdata)
1402 {
1403     PA_ServerReferralData ref;
1404     krb5_error_code ret;
1405     EncryptedData ed;
1406     krb5_data data;
1407     size_t size = 0;
1408 
1409     memset(&ref, 0, sizeof(ref));
1410 
1411     if (referred_realm) {
1412 	ALLOC(ref.referred_realm);
1413 	if (ref.referred_realm == NULL)
1414 	    goto eout;
1415 	*ref.referred_realm = strdup(referred_realm);
1416 	if (*ref.referred_realm == NULL)
1417 	    goto eout;
1418     }
1419     if (true_principal_name) {
1420 	ALLOC(ref.true_principal_name);
1421 	if (ref.true_principal_name == NULL)
1422 	    goto eout;
1423 	ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1424 	if (ret)
1425 	    goto eout;
1426     }
1427     if (requested_principal) {
1428 	ALLOC(ref.requested_principal_name);
1429 	if (ref.requested_principal_name == NULL)
1430 	    goto eout;
1431 	ret = copy_PrincipalName(requested_principal,
1432 				 ref.requested_principal_name);
1433 	if (ret)
1434 	    goto eout;
1435     }
1436 
1437     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1438 		       data.data, data.length,
1439 		       &ref, &size, ret);
1440     free_PA_ServerReferralData(&ref);
1441     if (ret)
1442 	return ret;
1443     if (data.length != size)
1444 	krb5_abortx(context, "internal asn.1 encoder error");
1445 
1446     ret = krb5_encrypt_EncryptedData(context, session,
1447 				     KRB5_KU_PA_SERVER_REFERRAL,
1448 				     data.data, data.length,
1449 				     0 /* kvno */, &ed);
1450     free(data.data);
1451     if (ret)
1452 	return ret;
1453 
1454     ASN1_MALLOC_ENCODE(EncryptedData,
1455 		       outdata->data, outdata->length,
1456 		       &ed, &size, ret);
1457     free_EncryptedData(&ed);
1458     if (ret)
1459 	return ret;
1460     if (outdata->length != size)
1461 	krb5_abortx(context, "internal asn.1 encoder error");
1462 
1463     return 0;
1464 eout:
1465     free_PA_ServerReferralData(&ref);
1466     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1467     return ENOMEM;
1468 }
1469 
1470 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)1471 tgs_build_reply(krb5_context context,
1472 		krb5_kdc_configuration *config,
1473 		KDC_REQ *req,
1474 		KDC_REQ_BODY *b,
1475 		hdb_entry_ex *krbtgt,
1476 		krb5_enctype krbtgt_etype,
1477 		const krb5_keyblock *replykey,
1478 		int rk_is_subkey,
1479 		krb5_ticket *ticket,
1480 		krb5_data *reply,
1481 		const char *from,
1482 		const char **e_text,
1483 		AuthorizationData **auth_data,
1484 		const struct sockaddr *from_addr)
1485 {
1486     krb5_error_code ret;
1487     krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1488     krb5_principal krbtgt_principal = NULL;
1489     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1490     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1491     HDB *clientdb, *s4u2self_impersonated_clientdb;
1492     krb5_realm ref_realm = NULL;
1493     EncTicketPart *tgt = &ticket->ticket;
1494     krb5_principals spp = NULL;
1495     const EncryptionKey *ekey;
1496     krb5_keyblock sessionkey;
1497     krb5_kvno kvno;
1498     krb5_data rspac;
1499 
1500     hdb_entry_ex *krbtgt_out = NULL;
1501 
1502     METHOD_DATA enc_pa_data;
1503 
1504     PrincipalName *s;
1505     Realm r;
1506     int nloop = 0;
1507     EncTicketPart adtkt;
1508     char opt_str[128];
1509     int signedpath = 0;
1510 
1511     Key *tkey_check;
1512     Key *tkey_sign;
1513     int flags = HDB_F_FOR_TGS_REQ;
1514 
1515     memset(&sessionkey, 0, sizeof(sessionkey));
1516     memset(&adtkt, 0, sizeof(adtkt));
1517     krb5_data_zero(&rspac);
1518     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1519 
1520     s = b->sname;
1521     r = b->realm;
1522 
1523     /*
1524      * Always to do CANON, see comment below about returned server principal (rsp).
1525      */
1526     flags |= HDB_F_CANON;
1527 
1528     if(b->kdc_options.enc_tkt_in_skey){
1529 	Ticket *t;
1530 	hdb_entry_ex *uu;
1531 	krb5_principal p;
1532 	Key *uukey;
1533 
1534 	if(b->additional_tickets == NULL ||
1535 	   b->additional_tickets->len == 0){
1536 	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
1537 	    kdc_log(context, config, 0,
1538 		    "No second ticket present in request");
1539 	    goto out;
1540 	}
1541 	t = &b->additional_tickets->val[0];
1542 	if(!get_krbtgt_realm(&t->sname)){
1543 	    kdc_log(context, config, 0,
1544 		    "Additional ticket is not a ticket-granting ticket");
1545 	    ret = KRB5KDC_ERR_POLICY;
1546 	    goto out;
1547 	}
1548 	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1549 	ret = _kdc_db_fetch(context, config, p,
1550 			    HDB_F_GET_KRBTGT, t->enc_part.kvno,
1551 			    NULL, &uu);
1552 	krb5_free_principal(context, p);
1553 	if(ret){
1554 	    if (ret == HDB_ERR_NOENTRY)
1555 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1556 	    goto out;
1557 	}
1558 	ret = hdb_enctype2key(context, &uu->entry,
1559 			      t->enc_part.etype, &uukey);
1560 	if(ret){
1561 	    _kdc_free_ent(context, uu);
1562 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1563 	    goto out;
1564 	}
1565 	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1566 	_kdc_free_ent(context, uu);
1567 	if(ret)
1568 	    goto out;
1569 
1570 	ret = verify_flags(context, config, &adtkt, spn);
1571 	if (ret)
1572 	    goto out;
1573 
1574 	s = &adtkt.cname;
1575 	r = adtkt.crealm;
1576     }
1577 
1578     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1579     ret = krb5_unparse_name(context, sp, &spn);
1580     if (ret)
1581 	goto out;
1582     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1583     ret = krb5_unparse_name(context, cp, &cpn);
1584     if (ret)
1585 	goto out;
1586     unparse_flags (KDCOptions2int(b->kdc_options),
1587 		   asn1_KDCOptions_units(),
1588 		   opt_str, sizeof(opt_str));
1589     if(*opt_str)
1590 	kdc_log(context, config, 0,
1591 		"TGS-REQ %s from %s for %s [%s]",
1592 		cpn, from, spn, opt_str);
1593     else
1594 	kdc_log(context, config, 0,
1595 		"TGS-REQ %s from %s for %s", cpn, from, spn);
1596 
1597     /*
1598      * Fetch server
1599      */
1600 
1601 server_lookup:
1602     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1603 			NULL, NULL, &server);
1604 
1605     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1606 	kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1607 	goto out;
1608     } else if(ret){
1609 	const char *new_rlm, *msg;
1610 	Realm req_rlm;
1611 	krb5_realm *realms;
1612 
1613 	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1614 	    if(nloop++ < 2) {
1615 		new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1616 		if(new_rlm) {
1617 		    kdc_log(context, config, 5, "krbtgt for realm %s "
1618 			    "not found, trying %s",
1619 			    req_rlm, new_rlm);
1620 		    krb5_free_principal(context, sp);
1621 		    free(spn);
1622 		    krb5_make_principal(context, &sp, r,
1623 					KRB5_TGS_NAME, new_rlm, NULL);
1624 		    ret = krb5_unparse_name(context, sp, &spn);
1625 		    if (ret)
1626 			goto out;
1627 
1628 		    if (ref_realm)
1629 			free(ref_realm);
1630 		    ref_realm = strdup(new_rlm);
1631 		    goto server_lookup;
1632 		}
1633 	    }
1634 	} else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1635 	    if (strcmp(realms[0], sp->realm) != 0) {
1636 		kdc_log(context, config, 5,
1637 			"Returning a referral to realm %s for "
1638 			"server %s that was not found",
1639 			realms[0], spn);
1640 		krb5_free_principal(context, sp);
1641 		free(spn);
1642 		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1643 				    realms[0], NULL);
1644 		ret = krb5_unparse_name(context, sp, &spn);
1645 		if (ret)
1646 		    goto out;
1647 
1648 		if (ref_realm)
1649 		    free(ref_realm);
1650 		ref_realm = strdup(realms[0]);
1651 
1652 		krb5_free_host_realm(context, realms);
1653 		goto server_lookup;
1654 	    }
1655 	    krb5_free_host_realm(context, realms);
1656 	}
1657 	msg = krb5_get_error_message(context, ret);
1658 	kdc_log(context, config, 0,
1659 		"Server not found in database: %s: %s", spn, msg);
1660 	krb5_free_error_message(context, msg);
1661 	if (ret == HDB_ERR_NOENTRY)
1662 	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1663 	goto out;
1664     }
1665 
1666     /* the name returned to the client depend on what was asked for,
1667      * return canonical name if kdc_options.canonicalize was set, the
1668      * client wants the true name of the principal, if not it just
1669      * wants the name its asked for.
1670      */
1671 
1672     if (b->kdc_options.canonicalize)
1673 	rsp = server->entry.principal;
1674     else
1675 	rsp = sp;
1676 
1677 
1678     /*
1679      * Select enctype, return key and kvno.
1680      */
1681 
1682     {
1683 	krb5_enctype etype;
1684 
1685 	if(b->kdc_options.enc_tkt_in_skey) {
1686 	    size_t i;
1687 	    ekey = &adtkt.key;
1688 	    for(i = 0; i < b->etype.len; i++)
1689 		if (b->etype.val[i] == adtkt.key.keytype)
1690 		    break;
1691 	    if(i == b->etype.len) {
1692 		kdc_log(context, config, 0,
1693 			"Addition ticket have not matching etypes");
1694 		krb5_clear_error_message(context);
1695 		ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1696 		goto out;
1697 	    }
1698 	    etype = b->etype.val[i];
1699 	    kvno = 0;
1700 	} else {
1701 	    Key *skey;
1702 
1703 	    ret = _kdc_find_etype(context,
1704 				  krb5_principal_is_krbtgt(context, sp) ?
1705 				  config->tgt_use_strongest_session_key :
1706 				  config->svc_use_strongest_session_key, FALSE,
1707 				  server, b->etype.val, b->etype.len, &etype,
1708 				  NULL);
1709 	    if(ret) {
1710 		kdc_log(context, config, 0,
1711 			"Server (%s) has no support for etypes", spn);
1712 		goto out;
1713 	    }
1714 	    ret = _kdc_get_preferred_key(context, config, server, spn,
1715 					 NULL, &skey);
1716 	    if(ret) {
1717 		kdc_log(context, config, 0,
1718 			"Server (%s) has no supported etypes", spn);
1719 		goto out;
1720 	    }
1721 	    ekey = &skey->key;
1722 	    kvno = server->entry.kvno;
1723 	}
1724 
1725 	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1726 	if (ret)
1727 	    goto out;
1728     }
1729 
1730     /*
1731      * Check that service is in the same realm as the krbtgt. If it's
1732      * not the same, it's someone that is using a uni-directional trust
1733      * backward.
1734      */
1735 
1736     /*
1737      * Validate authoriation data
1738      */
1739 
1740     ret = hdb_enctype2key(context, &krbtgt->entry,
1741 			  krbtgt_etype, &tkey_check);
1742     if(ret) {
1743 	kdc_log(context, config, 0,
1744 		    "Failed to find key for krbtgt PAC check");
1745 	goto out;
1746     }
1747 
1748     /* Now refetch the primary krbtgt, and get the current kvno (the
1749      * sign check may have been on an old kvno, and the server may
1750      * have been an incoming trust) */
1751     ret = krb5_make_principal(context, &krbtgt_principal,
1752 			      krb5_principal_get_comp_string(context,
1753 							     krbtgt->entry.principal,
1754 							     1),
1755 			      KRB5_TGS_NAME,
1756 			      krb5_principal_get_comp_string(context,
1757 							     krbtgt->entry.principal,
1758 							     1), NULL);
1759     if(ret) {
1760 	kdc_log(context, config, 0,
1761 		    "Failed to generate krbtgt principal");
1762 	goto out;
1763     }
1764 
1765     ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1766     krb5_free_principal(context, krbtgt_principal);
1767     if (ret) {
1768 	krb5_error_code ret2;
1769 	char *ktpn, *ktpn2;
1770 	ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1771 	ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1772 	kdc_log(context, config, 0,
1773 		"Request with wrong krbtgt: %s, %s not found in our database",
1774 		(ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1775 	if(ret == 0)
1776 	    free(ktpn);
1777 	if(ret2 == 0)
1778 	    free(ktpn2);
1779 	ret = KRB5KRB_AP_ERR_NOT_US;
1780 	goto out;
1781     }
1782 
1783     /* The first realm is the realm of the service, the second is
1784      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1785      * encrypted to.  The redirection via the krbtgt_out entry allows
1786      * the DB to possibly correct the case of the realm (Samba4 does
1787      * this) before the strcmp() */
1788     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1789 	       krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1790 	char *ktpn;
1791 	ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1792 	kdc_log(context, config, 0,
1793 		"Request with wrong krbtgt: %s",
1794 		(ret == 0) ? ktpn : "<unknown>");
1795 	if(ret == 0)
1796 	    free(ktpn);
1797 	ret = KRB5KRB_AP_ERR_NOT_US;
1798     }
1799 
1800     ret = hdb_enctype2key(context, &krbtgt_out->entry,
1801 			  krbtgt_etype, &tkey_sign);
1802     if(ret) {
1803 	kdc_log(context, config, 0,
1804 		    "Failed to find key for krbtgt PAC signature");
1805 	goto out;
1806     }
1807 
1808     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1809 			NULL, &clientdb, &client);
1810     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1811 	/* This is OK, we are just trying to find out if they have
1812 	 * been disabled or deleted in the meantime, missing secrets
1813 	 * is OK */
1814     } else if(ret){
1815 	const char *krbtgt_realm, *msg;
1816 
1817 	/*
1818 	 * If the client belongs to the same realm as our krbtgt, it
1819 	 * should exist in the local database.
1820 	 *
1821 	 */
1822 
1823 	krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1824 
1825 	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1826 	    if (ret == HDB_ERR_NOENTRY)
1827 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1828 	    kdc_log(context, config, 1, "Client no longer in database: %s",
1829 		    cpn);
1830 	    goto out;
1831 	}
1832 
1833 	msg = krb5_get_error_message(context, ret);
1834 	kdc_log(context, config, 1, "Client not found in database: %s", msg);
1835 	krb5_free_error_message(context, msg);
1836     }
1837 
1838     ret = check_PAC(context, config, cp, NULL,
1839 		    client, server, krbtgt,
1840 		    &tkey_check->key, &tkey_check->key,
1841 		    ekey, &tkey_sign->key,
1842 		    tgt, &rspac, &signedpath);
1843     if (ret) {
1844 	const char *msg = krb5_get_error_message(context, ret);
1845 	kdc_log(context, config, 0,
1846 		"Verify PAC failed for %s (%s) from %s with %s",
1847 		spn, cpn, from, msg);
1848 	krb5_free_error_message(context, msg);
1849 	goto out;
1850     }
1851 
1852     /* also check the krbtgt for signature */
1853     ret = check_KRB5SignedPath(context,
1854 			       config,
1855 			       krbtgt,
1856 			       cp,
1857 			       tgt,
1858 			       &spp,
1859 			       &signedpath);
1860     if (ret) {
1861 	const char *msg = krb5_get_error_message(context, ret);
1862 	kdc_log(context, config, 0,
1863 		"KRB5SignedPath check failed for %s (%s) from %s with %s",
1864 		spn, cpn, from, msg);
1865 	krb5_free_error_message(context, msg);
1866 	goto out;
1867     }
1868 
1869     /*
1870      * Process request
1871      */
1872 
1873     /* by default the tgt principal matches the client principal */
1874     tp = cp;
1875     tpn = cpn;
1876 
1877     if (client) {
1878 	const PA_DATA *sdata;
1879 	int i = 0;
1880 
1881 	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1882 	if (sdata) {
1883 	    krb5_crypto crypto;
1884 	    krb5_data datack;
1885 	    PA_S4U2Self self;
1886 	    const char *str;
1887 
1888 	    ret = decode_PA_S4U2Self(sdata->padata_value.data,
1889 				     sdata->padata_value.length,
1890 				     &self, NULL);
1891 	    if (ret) {
1892 		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1893 		goto out;
1894 	    }
1895 
1896 	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1897 	    if (ret)
1898 		goto out;
1899 
1900 	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1901 	    if (ret) {
1902 		const char *msg = krb5_get_error_message(context, ret);
1903 		free_PA_S4U2Self(&self);
1904 		krb5_data_free(&datack);
1905 		kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1906 		krb5_free_error_message(context, msg);
1907 		goto out;
1908 	    }
1909 
1910 	    ret = krb5_verify_checksum(context,
1911 				       crypto,
1912 				       KRB5_KU_OTHER_CKSUM,
1913 				       datack.data,
1914 				       datack.length,
1915 				       &self.cksum);
1916 	    krb5_data_free(&datack);
1917 	    krb5_crypto_destroy(context, crypto);
1918 	    if (ret) {
1919 		const char *msg = krb5_get_error_message(context, ret);
1920 		free_PA_S4U2Self(&self);
1921 		kdc_log(context, config, 0,
1922 			"krb5_verify_checksum failed for S4U2Self: %s", msg);
1923 		krb5_free_error_message(context, msg);
1924 		goto out;
1925 	    }
1926 
1927 	    ret = _krb5_principalname2krb5_principal(context,
1928 						     &tp,
1929 						     self.name,
1930 						     self.realm);
1931 	    free_PA_S4U2Self(&self);
1932 	    if (ret)
1933 		goto out;
1934 
1935 	    ret = krb5_unparse_name(context, tp, &tpn);
1936 	    if (ret)
1937 		goto out;
1938 
1939 	    /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1940 	    if(rspac.data) {
1941 		krb5_pac p = NULL;
1942 		krb5_data_free(&rspac);
1943 		ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1944 				    NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1945 		if (ret) {
1946 		    const char *msg;
1947 
1948 		    /*
1949 		     * If the client belongs to the same realm as our krbtgt, it
1950 		     * should exist in the local database.
1951 		     *
1952 		     */
1953 
1954 		    if (ret == HDB_ERR_NOENTRY)
1955 			ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1956 		    msg = krb5_get_error_message(context, ret);
1957 		    kdc_log(context, config, 1,
1958 			    "S2U4Self principal to impersonate %s not found in database: %s",
1959 			    tpn, msg);
1960 		    krb5_free_error_message(context, msg);
1961 		    goto out;
1962 		}
1963 		ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1964 		if (ret) {
1965 		    kdc_log(context, config, 0, "PAC generation failed for -- %s",
1966 			    tpn);
1967 		    goto out;
1968 		}
1969 		if (p != NULL) {
1970 		    ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1971 					 s4u2self_impersonated_client->entry.principal,
1972 					 ekey, &tkey_sign->key,
1973 					 &rspac);
1974 		    krb5_pac_free(context, p);
1975 		    if (ret) {
1976 			kdc_log(context, config, 0, "PAC signing failed for -- %s",
1977 				tpn);
1978 			goto out;
1979 		    }
1980 		}
1981 	    }
1982 
1983 	    /*
1984 	     * Check that service doing the impersonating is
1985 	     * requesting a ticket to it-self.
1986 	     */
1987 	    ret = check_s4u2self(context, config, clientdb, client, sp);
1988 	    if (ret) {
1989 		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1990 			"to impersonate to service "
1991 			"(tried for user %s to service %s)",
1992 			cpn, tpn, spn);
1993 		goto out;
1994 	    }
1995 
1996 	    /*
1997 	     * If the service isn't trusted for authentication to
1998 	     * delegation, remove the forward flag.
1999 	     */
2000 
2001 	    if (client->entry.flags.trusted_for_delegation) {
2002 		str = "[forwardable]";
2003 	    } else {
2004 		b->kdc_options.forwardable = 0;
2005 		str = "";
2006 	    }
2007 	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2008 		    "service %s %s", cpn, tpn, spn, str);
2009 	}
2010     }
2011 
2012     /*
2013      * Constrained delegation
2014      */
2015 
2016     if (client != NULL
2017 	&& b->additional_tickets != NULL
2018 	&& b->additional_tickets->len != 0
2019 	&& b->kdc_options.enc_tkt_in_skey == 0)
2020     {
2021 	int ad_signedpath = 0;
2022 	Key *clientkey;
2023 	Ticket *t;
2024 
2025 	/*
2026 	 * Require that the KDC have issued the service's krbtgt (not
2027 	 * self-issued ticket with kimpersonate(1).
2028 	 */
2029 	if (!signedpath) {
2030 	    ret = KRB5KDC_ERR_BADOPTION;
2031 	    kdc_log(context, config, 0,
2032 		    "Constrained delegation done on service ticket %s/%s",
2033 		    cpn, spn);
2034 	    goto out;
2035 	}
2036 
2037 	t = &b->additional_tickets->val[0];
2038 
2039 	ret = hdb_enctype2key(context, &client->entry,
2040 			      t->enc_part.etype, &clientkey);
2041 	if(ret){
2042 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2043 	    goto out;
2044 	}
2045 
2046 	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2047 	if (ret) {
2048 	    kdc_log(context, config, 0,
2049 		    "failed to decrypt ticket for "
2050 		    "constrained delegation from %s to %s ", cpn, spn);
2051 	    goto out;
2052 	}
2053 
2054 	ret = _krb5_principalname2krb5_principal(context,
2055 						 &tp,
2056 						 adtkt.cname,
2057 						 adtkt.crealm);
2058 	if (ret)
2059 	    goto out;
2060 
2061 	ret = krb5_unparse_name(context, tp, &tpn);
2062 	if (ret)
2063 	    goto out;
2064 
2065 	ret = _krb5_principalname2krb5_principal(context,
2066 						 &dp,
2067 						 t->sname,
2068 						 t->realm);
2069 	if (ret)
2070 	    goto out;
2071 
2072 	ret = krb5_unparse_name(context, dp, &dpn);
2073 	if (ret)
2074 	    goto out;
2075 
2076 	/* check that ticket is valid */
2077 	if (adtkt.flags.forwardable == 0) {
2078 	    kdc_log(context, config, 0,
2079 		    "Missing forwardable flag on ticket for "
2080 		    "constrained delegation from %s (%s) as %s to %s ",
2081 		    cpn, dpn, tpn, spn);
2082 	    ret = KRB5KDC_ERR_BADOPTION;
2083 	    goto out;
2084 	}
2085 
2086 	ret = check_constrained_delegation(context, config, clientdb,
2087 					   client, server, sp);
2088 	if (ret) {
2089 	    kdc_log(context, config, 0,
2090 		    "constrained delegation from %s (%s) as %s to %s not allowed",
2091 		    cpn, dpn, tpn, spn);
2092 	    goto out;
2093 	}
2094 
2095 	ret = verify_flags(context, config, &adtkt, tpn);
2096 	if (ret) {
2097 	    goto out;
2098 	}
2099 
2100 	krb5_data_free(&rspac);
2101 
2102 	/*
2103 	 * generate the PAC for the user.
2104 	 *
2105 	 * TODO: pass in t->sname and t->realm and build
2106 	 * a S4U_DELEGATION_INFO blob to the PAC.
2107 	 */
2108 	ret = check_PAC(context, config, tp, dp,
2109 			client, server, krbtgt,
2110 			&clientkey->key, &tkey_check->key,
2111 			ekey, &tkey_sign->key,
2112 			&adtkt, &rspac, &ad_signedpath);
2113 	if (ret) {
2114 	    const char *msg = krb5_get_error_message(context, ret);
2115 	    kdc_log(context, config, 0,
2116 		    "Verify delegated PAC failed to %s for client"
2117 		    "%s (%s) as %s from %s with %s",
2118 		    spn, cpn, dpn, tpn, from, msg);
2119 	    krb5_free_error_message(context, msg);
2120 	    goto out;
2121 	}
2122 
2123 	/*
2124 	 * Check that the KDC issued the user's ticket.
2125 	 */
2126 	ret = check_KRB5SignedPath(context,
2127 				   config,
2128 				   krbtgt,
2129 				   cp,
2130 				   &adtkt,
2131 				   NULL,
2132 				   &ad_signedpath);
2133 	if (ret) {
2134 	    const char *msg = krb5_get_error_message(context, ret);
2135 	    kdc_log(context, config, 0,
2136 		    "KRB5SignedPath check from service %s failed "
2137 		    "for delegation to %s for client %s (%s)"
2138 		    "from %s failed with %s",
2139 		    spn, tpn, dpn, cpn, from, msg);
2140 	    krb5_free_error_message(context, msg);
2141 	    goto out;
2142 	}
2143 
2144 	if (!ad_signedpath) {
2145 	    ret = KRB5KDC_ERR_BADOPTION;
2146 	    kdc_log(context, config, 0,
2147 		    "Ticket not signed with PAC nor SignedPath service %s failed "
2148 		    "for delegation to %s for client %s (%s)"
2149 		    "from %s",
2150 		    spn, tpn, dpn, cpn, from);
2151 	    goto out;
2152 	}
2153 
2154 	kdc_log(context, config, 0, "constrained delegation for %s "
2155 		"from %s (%s) to %s", tpn, cpn, dpn, spn);
2156     }
2157 
2158     /*
2159      * Check flags
2160      */
2161 
2162     ret = kdc_check_flags(context, config,
2163 			  client, cpn,
2164 			  server, spn,
2165 			  FALSE);
2166     if(ret)
2167 	goto out;
2168 
2169     if((b->kdc_options.validate || b->kdc_options.renew) &&
2170        !krb5_principal_compare(context,
2171 			       krbtgt->entry.principal,
2172 			       server->entry.principal)){
2173 	kdc_log(context, config, 0, "Inconsistent request.");
2174 	ret = KRB5KDC_ERR_SERVER_NOMATCH;
2175 	goto out;
2176     }
2177 
2178     /* check for valid set of addresses */
2179     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2180 	ret = KRB5KRB_AP_ERR_BADADDR;
2181 	kdc_log(context, config, 0, "Request from wrong address");
2182 	goto out;
2183     }
2184 
2185     /*
2186      * If this is an referral, add server referral data to the
2187      * auth_data reply .
2188      */
2189     if (ref_realm) {
2190 	PA_DATA pa;
2191 	krb5_crypto crypto;
2192 
2193 	kdc_log(context, config, 0,
2194 		"Adding server referral to %s", ref_realm);
2195 
2196 	ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2197 	if (ret)
2198 	    goto out;
2199 
2200 	ret = build_server_referral(context, config, crypto, ref_realm,
2201 				    NULL, s, &pa.padata_value);
2202 	krb5_crypto_destroy(context, crypto);
2203 	if (ret) {
2204 	    kdc_log(context, config, 0,
2205 		    "Failed building server referral");
2206 	    goto out;
2207 	}
2208 	pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2209 
2210 	ret = add_METHOD_DATA(&enc_pa_data, &pa);
2211 	krb5_data_free(&pa.padata_value);
2212 	if (ret) {
2213 	    kdc_log(context, config, 0,
2214 		    "Add server referral METHOD-DATA failed");
2215 	    goto out;
2216 	}
2217     }
2218 
2219     /*
2220      *
2221      */
2222 
2223     ret = tgs_make_reply(context,
2224 			 config,
2225 			 b,
2226 			 tp,
2227 			 tgt,
2228 			 replykey,
2229 			 rk_is_subkey,
2230 			 ekey,
2231 			 &sessionkey,
2232 			 kvno,
2233 			 *auth_data,
2234 			 server,
2235 			 rsp,
2236 			 spn,
2237 			 client,
2238 			 cp,
2239 			 krbtgt_out,
2240 			 krbtgt_etype,
2241 			 spp,
2242 			 &rspac,
2243 			 &enc_pa_data,
2244 			 e_text,
2245 			 reply);
2246 
2247 out:
2248     if (tpn != cpn)
2249 	    free(tpn);
2250     free(spn);
2251     free(cpn);
2252     if (dpn)
2253 	free(dpn);
2254 
2255     krb5_data_free(&rspac);
2256     krb5_free_keyblock_contents(context, &sessionkey);
2257     if(krbtgt_out)
2258 	_kdc_free_ent(context, krbtgt_out);
2259     if(server)
2260 	_kdc_free_ent(context, server);
2261     if(client)
2262 	_kdc_free_ent(context, client);
2263     if(s4u2self_impersonated_client)
2264 	_kdc_free_ent(context, s4u2self_impersonated_client);
2265 
2266     if (tp && tp != cp)
2267 	krb5_free_principal(context, tp);
2268     if (cp)
2269 	krb5_free_principal(context, cp);
2270     if (dp)
2271 	krb5_free_principal(context, dp);
2272     if (sp)
2273 	krb5_free_principal(context, sp);
2274     if (ref_realm)
2275 	free(ref_realm);
2276     free_METHOD_DATA(&enc_pa_data);
2277 
2278     free_EncTicketPart(&adtkt);
2279 
2280     return ret;
2281 }
2282 
2283 /*
2284  *
2285  */
2286 
2287 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)2288 _kdc_tgs_rep(krb5_context context,
2289 	     krb5_kdc_configuration *config,
2290 	     KDC_REQ *req,
2291 	     krb5_data *data,
2292 	     const char *from,
2293 	     struct sockaddr *from_addr,
2294 	     int datagram_reply)
2295 {
2296     AuthorizationData *auth_data = NULL;
2297     krb5_error_code ret;
2298     int i = 0;
2299     const PA_DATA *tgs_req;
2300 
2301     hdb_entry_ex *krbtgt = NULL;
2302     krb5_ticket *ticket = NULL;
2303     const char *e_text = NULL;
2304     krb5_enctype krbtgt_etype = ETYPE_NULL;
2305 
2306     krb5_keyblock *replykey = NULL;
2307     int rk_is_subkey = 0;
2308     time_t *csec = NULL;
2309     int *cusec = NULL;
2310 
2311     if(req->padata == NULL){
2312 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2313 	kdc_log(context, config, 0,
2314 		"TGS-REQ from %s without PA-DATA", from);
2315 	goto out;
2316     }
2317 
2318     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2319 
2320     if(tgs_req == NULL){
2321 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2322 
2323 	kdc_log(context, config, 0,
2324 		"TGS-REQ from %s without PA-TGS-REQ", from);
2325 	goto out;
2326     }
2327     ret = tgs_parse_request(context, config,
2328 			    &req->req_body, tgs_req,
2329 			    &krbtgt,
2330 			    &krbtgt_etype,
2331 			    &ticket,
2332 			    &e_text,
2333 			    from, from_addr,
2334 			    &csec, &cusec,
2335 			    &auth_data,
2336 			    &replykey,
2337 			    &rk_is_subkey);
2338     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2339 	/* kdc_log() is called in tgs_parse_request() */
2340 	goto out;
2341     }
2342     if (ret) {
2343 	kdc_log(context, config, 0,
2344 		"Failed parsing TGS-REQ from %s", from);
2345 	goto out;
2346     }
2347 
2348     ret = tgs_build_reply(context,
2349 			  config,
2350 			  req,
2351 			  &req->req_body,
2352 			  krbtgt,
2353 			  krbtgt_etype,
2354 			  replykey,
2355 			  rk_is_subkey,
2356 			  ticket,
2357 			  data,
2358 			  from,
2359 			  &e_text,
2360 			  &auth_data,
2361 			  from_addr);
2362     if (ret) {
2363 	kdc_log(context, config, 0,
2364 		"Failed building TGS-REP to %s", from);
2365 	goto out;
2366     }
2367 
2368     /* */
2369     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2370 	krb5_data_free(data);
2371 	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2372 	e_text = "Reply packet too large";
2373     }
2374 
2375 out:
2376     if (replykey)
2377 	krb5_free_keyblock(context, replykey);
2378     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2379 	krb5_mk_error(context,
2380 		      ret,
2381 		      NULL,
2382 		      NULL,
2383 		      NULL,
2384 		      NULL,
2385 		      csec,
2386 		      cusec,
2387 		      data);
2388 	ret = 0;
2389     }
2390     free(csec);
2391     free(cusec);
2392     if (ticket)
2393 	krb5_free_ticket(context, ticket);
2394     if(krbtgt)
2395 	_kdc_free_ent(context, krbtgt);
2396 
2397     if (auth_data) {
2398 	free_AuthorizationData(auth_data);
2399 	free(auth_data);
2400     }
2401 
2402     return ret;
2403 }
2404