xref: /freebsd/crypto/heimdal/kdc/krb5tgs.c (revision 39beb93c3f8bdbf72a61fda42300b5ebed7390c8)
1 /*
2  * Copyright (c) 1997-2007 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "kdc_locl.h"
35 
36 RCSID("$Id: krb5tgs.c 22071 2007-11-14 20:04:50Z lha $");
37 
38 /*
39  * return the realm of a krbtgt-ticket or NULL
40  */
41 
42 static Realm
43 get_krbtgt_realm(const PrincipalName *p)
44 {
45     if(p->name_string.len == 2
46        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
47 	return p->name_string.val[1];
48     else
49 	return NULL;
50 }
51 
52 /*
53  * The KDC might add a signed path to the ticket authorization data
54  * field. This is to avoid server impersonating clients and the
55  * request constrained delegation.
56  *
57  * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58  * entry of type KRB5SignedPath.
59  */
60 
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context,
63 		    const AuthorizationData *ad,
64 		    krb5_data *data)
65 {
66     AuthorizationData child;
67     krb5_error_code ret;
68     int pos;
69 
70     if (ad == NULL || ad->len == 0)
71 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
72 
73     pos = ad->len - 1;
74 
75     if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
76 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
77 
78     ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
79 				   ad->val[pos].ad_data.length,
80 				   &child,
81 				   NULL);
82     if (ret) {
83 	krb5_set_error_string(context, "Failed to decode "
84 			      "IF_RELEVANT with %d", ret);
85 	return ret;
86     }
87 
88     if (child.len != 1) {
89 	free_AuthorizationData(&child);
90 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91     }
92 
93     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94 	free_AuthorizationData(&child);
95 	return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
96     }
97 
98     if (data)
99 	ret = der_copy_octet_string(&child.val[0].ad_data, data);
100     free_AuthorizationData(&child);
101     return ret;
102 }
103 
104 krb5_error_code
105 _kdc_add_KRB5SignedPath(krb5_context context,
106 			krb5_kdc_configuration *config,
107 			hdb_entry_ex *krbtgt,
108 			krb5_enctype enctype,
109 			krb5_const_principal server,
110 			KRB5SignedPathPrincipals *principals,
111 			EncTicketPart *tkt)
112 {
113     krb5_error_code ret;
114     KRB5SignedPath sp;
115     krb5_data data;
116     krb5_crypto crypto = NULL;
117     size_t size;
118 
119     if (server && principals) {
120 	ret = add_KRB5SignedPathPrincipals(principals, server);
121 	if (ret)
122 	    return ret;
123     }
124 
125     {
126 	KRB5SignedPathData spd;
127 
128 	spd.encticket = *tkt;
129 	spd.delegated = principals;
130 
131 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
132 			   &spd, &size, ret);
133 	if (ret)
134 	    return ret;
135 	if (data.length != size)
136 	    krb5_abortx(context, "internal asn.1 encoder error");
137     }
138 
139     {
140 	Key *key;
141 	ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
142 	if (ret == 0)
143 	    ret = krb5_crypto_init(context, &key->key, 0, &crypto);
144 	if (ret) {
145 	    free(data.data);
146 	    return ret;
147 	}
148     }
149 
150     /*
151      * Fill in KRB5SignedPath
152      */
153 
154     sp.etype = enctype;
155     sp.delegated = principals;
156 
157     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
158 			       data.data, data.length, &sp.cksum);
159     krb5_crypto_destroy(context, crypto);
160     free(data.data);
161     if (ret)
162 	return ret;
163 
164     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
165     free_Checksum(&sp.cksum);
166     if (ret)
167 	return ret;
168     if (data.length != size)
169 	krb5_abortx(context, "internal asn.1 encoder error");
170 
171 
172     /*
173      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
174      * authorization data field.
175      */
176 
177     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
178 				      KRB5_AUTHDATA_SIGNTICKET, &data);
179     krb5_data_free(&data);
180 
181     return ret;
182 }
183 
184 static krb5_error_code
185 check_KRB5SignedPath(krb5_context context,
186 		     krb5_kdc_configuration *config,
187 		     hdb_entry_ex *krbtgt,
188 		     EncTicketPart *tkt,
189 		     KRB5SignedPathPrincipals **delegated,
190 		     int require_signedpath)
191 {
192     krb5_error_code ret;
193     krb5_data data;
194     krb5_crypto crypto = NULL;
195 
196     *delegated = NULL;
197 
198     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
199     if (ret == 0) {
200 	KRB5SignedPathData spd;
201 	KRB5SignedPath sp;
202 	AuthorizationData *ad;
203 	size_t size;
204 
205 	ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
206 	krb5_data_free(&data);
207 	if (ret)
208 	    return ret;
209 
210 	spd.encticket = *tkt;
211 	/* the KRB5SignedPath is the last entry */
212 	ad = spd.encticket.authorization_data;
213 	if (--ad->len == 0)
214 	    spd.encticket.authorization_data = NULL;
215 	spd.delegated = sp.delegated;
216 
217 	ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
218 			   &spd, &size, ret);
219 	ad->len++;
220 	spd.encticket.authorization_data = ad;
221 	if (ret) {
222 	    free_KRB5SignedPath(&sp);
223 	    return ret;
224 	}
225 	if (data.length != size)
226 	    krb5_abortx(context, "internal asn.1 encoder error");
227 
228 	{
229 	    Key *key;
230 	    ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
231 	    if (ret == 0)
232 		ret = krb5_crypto_init(context, &key->key, 0, &crypto);
233 	    if (ret) {
234 		free(data.data);
235 		free_KRB5SignedPath(&sp);
236 		return ret;
237 	    }
238 	}
239 	ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
240 				   data.data, data.length,
241 				   &sp.cksum);
242 	krb5_crypto_destroy(context, crypto);
243 	free(data.data);
244 	if (ret) {
245 	    free_KRB5SignedPath(&sp);
246 	    return ret;
247 	}
248 
249 	if (sp.delegated) {
250 
251 	    *delegated = malloc(sizeof(*sp.delegated));
252 	    if (*delegated == NULL) {
253 		free_KRB5SignedPath(&sp);
254 		return ENOMEM;
255 	    }
256 
257 	    ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
258 	    if (ret) {
259 		free_KRB5SignedPath(&sp);
260 		free(*delegated);
261 		*delegated = NULL;
262 		return ret;
263 	    }
264 	}
265 	free_KRB5SignedPath(&sp);
266 
267     } else {
268 	if (require_signedpath)
269 	    return KRB5KDC_ERR_BADOPTION;
270     }
271 
272     return 0;
273 }
274 
275 /*
276  *
277  */
278 
279 static krb5_error_code
280 check_PAC(krb5_context context,
281 	  krb5_kdc_configuration *config,
282 	  const krb5_principal client_principal,
283 	  hdb_entry_ex *client,
284 	  hdb_entry_ex *server,
285 	  const EncryptionKey *server_key,
286 	  const EncryptionKey *krbtgt_key,
287 	  EncTicketPart *tkt,
288 	  krb5_data *rspac,
289 	  int *require_signedpath)
290 {
291     AuthorizationData *ad = tkt->authorization_data;
292     unsigned i, j;
293     krb5_error_code ret;
294 
295     if (ad == NULL || ad->len == 0)
296 	return 0;
297 
298     for (i = 0; i < ad->len; i++) {
299 	AuthorizationData child;
300 
301 	if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
302 	    continue;
303 
304 	ret = decode_AuthorizationData(ad->val[i].ad_data.data,
305 				       ad->val[i].ad_data.length,
306 				       &child,
307 				       NULL);
308 	if (ret) {
309 	    krb5_set_error_string(context, "Failed to decode "
310 				  "IF_RELEVANT with %d", ret);
311 	    return ret;
312 	}
313 	for (j = 0; j < child.len; j++) {
314 
315 	    if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
316 		krb5_pac pac;
317 
318 		/* Found PAC */
319 		ret = krb5_pac_parse(context,
320 				     child.val[j].ad_data.data,
321 				     child.val[j].ad_data.length,
322 				     &pac);
323 		free_AuthorizationData(&child);
324 		if (ret)
325 		    return ret;
326 
327 		ret = krb5_pac_verify(context, pac, tkt->authtime,
328 				      client_principal,
329 				      krbtgt_key, NULL);
330 		if (ret) {
331 		    krb5_pac_free(context, pac);
332 		    return ret;
333 		}
334 
335 		ret = _kdc_pac_verify(context, client_principal,
336 				      client, server, &pac);
337 		if (ret) {
338 		    krb5_pac_free(context, pac);
339 		    return ret;
340 		}
341 		*require_signedpath = 0;
342 
343 		ret = _krb5_pac_sign(context, pac, tkt->authtime,
344 				     client_principal,
345 				     server_key, krbtgt_key, rspac);
346 
347 		krb5_pac_free(context, pac);
348 
349 		return ret;
350 	    }
351 	}
352 	free_AuthorizationData(&child);
353     }
354     return 0;
355 }
356 
357 /*
358  *
359  */
360 
361 static krb5_error_code
362 check_tgs_flags(krb5_context context,
363 		krb5_kdc_configuration *config,
364 		KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
365 {
366     KDCOptions f = b->kdc_options;
367 
368     if(f.validate){
369 	if(!tgt->flags.invalid || tgt->starttime == NULL){
370 	    kdc_log(context, config, 0,
371 		    "Bad request to validate ticket");
372 	    return KRB5KDC_ERR_BADOPTION;
373 	}
374 	if(*tgt->starttime > kdc_time){
375 	    kdc_log(context, config, 0,
376 		    "Early request to validate ticket");
377 	    return KRB5KRB_AP_ERR_TKT_NYV;
378 	}
379 	/* XXX  tkt = tgt */
380 	et->flags.invalid = 0;
381     }else if(tgt->flags.invalid){
382 	kdc_log(context, config, 0,
383 		"Ticket-granting ticket has INVALID flag set");
384 	return KRB5KRB_AP_ERR_TKT_INVALID;
385     }
386 
387     if(f.forwardable){
388 	if(!tgt->flags.forwardable){
389 	    kdc_log(context, config, 0,
390 		    "Bad request for forwardable ticket");
391 	    return KRB5KDC_ERR_BADOPTION;
392 	}
393 	et->flags.forwardable = 1;
394     }
395     if(f.forwarded){
396 	if(!tgt->flags.forwardable){
397 	    kdc_log(context, config, 0,
398 		    "Request to forward non-forwardable ticket");
399 	    return KRB5KDC_ERR_BADOPTION;
400 	}
401 	et->flags.forwarded = 1;
402 	et->caddr = b->addresses;
403     }
404     if(tgt->flags.forwarded)
405 	et->flags.forwarded = 1;
406 
407     if(f.proxiable){
408 	if(!tgt->flags.proxiable){
409 	    kdc_log(context, config, 0,
410 		    "Bad request for proxiable ticket");
411 	    return KRB5KDC_ERR_BADOPTION;
412 	}
413 	et->flags.proxiable = 1;
414     }
415     if(f.proxy){
416 	if(!tgt->flags.proxiable){
417 	    kdc_log(context, config, 0,
418 		    "Request to proxy non-proxiable ticket");
419 	    return KRB5KDC_ERR_BADOPTION;
420 	}
421 	et->flags.proxy = 1;
422 	et->caddr = b->addresses;
423     }
424     if(tgt->flags.proxy)
425 	et->flags.proxy = 1;
426 
427     if(f.allow_postdate){
428 	if(!tgt->flags.may_postdate){
429 	    kdc_log(context, config, 0,
430 		    "Bad request for post-datable ticket");
431 	    return KRB5KDC_ERR_BADOPTION;
432 	}
433 	et->flags.may_postdate = 1;
434     }
435     if(f.postdated){
436 	if(!tgt->flags.may_postdate){
437 	    kdc_log(context, config, 0,
438 		    "Bad request for postdated ticket");
439 	    return KRB5KDC_ERR_BADOPTION;
440 	}
441 	if(b->from)
442 	    *et->starttime = *b->from;
443 	et->flags.postdated = 1;
444 	et->flags.invalid = 1;
445     }else if(b->from && *b->from > kdc_time + context->max_skew){
446 	kdc_log(context, config, 0, "Ticket cannot be postdated");
447 	return KRB5KDC_ERR_CANNOT_POSTDATE;
448     }
449 
450     if(f.renewable){
451 	if(!tgt->flags.renewable){
452 	    kdc_log(context, config, 0,
453 		    "Bad request for renewable ticket");
454 	    return KRB5KDC_ERR_BADOPTION;
455 	}
456 	et->flags.renewable = 1;
457 	ALLOC(et->renew_till);
458 	_kdc_fix_time(&b->rtime);
459 	*et->renew_till = *b->rtime;
460     }
461     if(f.renew){
462 	time_t old_life;
463 	if(!tgt->flags.renewable || tgt->renew_till == NULL){
464 	    kdc_log(context, config, 0,
465 		    "Request to renew non-renewable ticket");
466 	    return KRB5KDC_ERR_BADOPTION;
467 	}
468 	old_life = tgt->endtime;
469 	if(tgt->starttime)
470 	    old_life -= *tgt->starttime;
471 	else
472 	    old_life -= tgt->authtime;
473 	et->endtime = *et->starttime + old_life;
474 	if (et->renew_till != NULL)
475 	    et->endtime = min(*et->renew_till, et->endtime);
476     }
477 
478 #if 0
479     /* checks for excess flags */
480     if(f.request_anonymous && !config->allow_anonymous){
481 	kdc_log(context, config, 0,
482 		"Request for anonymous ticket");
483 	return KRB5KDC_ERR_BADOPTION;
484     }
485 #endif
486     return 0;
487 }
488 
489 /*
490  *
491  */
492 
493 static krb5_error_code
494 check_constrained_delegation(krb5_context context,
495 			     krb5_kdc_configuration *config,
496 			     hdb_entry_ex *client,
497 			     krb5_const_principal server)
498 {
499     const HDB_Ext_Constrained_delegation_acl *acl;
500     krb5_error_code ret;
501     int i;
502 
503     ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
504     if (ret) {
505 	krb5_clear_error_string(context);
506 	return ret;
507     }
508 
509     if (acl) {
510 	for (i = 0; i < acl->len; i++) {
511 	    if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
512 		return 0;
513 	}
514     }
515     kdc_log(context, config, 0,
516 	    "Bad request for constrained delegation");
517     return KRB5KDC_ERR_BADOPTION;
518 }
519 
520 /*
521  *
522  */
523 
524 static krb5_error_code
525 verify_flags (krb5_context context,
526 	      krb5_kdc_configuration *config,
527 	      const EncTicketPart *et,
528 	      const char *pstr)
529 {
530     if(et->endtime < kdc_time){
531 	kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
532 	return KRB5KRB_AP_ERR_TKT_EXPIRED;
533     }
534     if(et->flags.invalid){
535 	kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
536 	return KRB5KRB_AP_ERR_TKT_NYV;
537     }
538     return 0;
539 }
540 
541 /*
542  *
543  */
544 
545 static krb5_error_code
546 fix_transited_encoding(krb5_context context,
547 		       krb5_kdc_configuration *config,
548 		       krb5_boolean check_policy,
549 		       const TransitedEncoding *tr,
550 		       EncTicketPart *et,
551 		       const char *client_realm,
552 		       const char *server_realm,
553 		       const char *tgt_realm)
554 {
555     krb5_error_code ret = 0;
556     char **realms, **tmp;
557     int num_realms;
558     int i;
559 
560     switch (tr->tr_type) {
561     case DOMAIN_X500_COMPRESS:
562 	break;
563     case 0:
564 	/*
565 	 * Allow empty content of type 0 because that is was Microsoft
566 	 * generates in their TGT.
567 	 */
568 	if (tr->contents.length == 0)
569 	    break;
570 	kdc_log(context, config, 0,
571 		"Transited type 0 with non empty content");
572 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
573     default:
574 	kdc_log(context, config, 0,
575 		"Unknown transited type: %u", tr->tr_type);
576 	return KRB5KDC_ERR_TRTYPE_NOSUPP;
577     }
578 
579     ret = krb5_domain_x500_decode(context,
580 				  tr->contents,
581 				  &realms,
582 				  &num_realms,
583 				  client_realm,
584 				  server_realm);
585     if(ret){
586 	krb5_warn(context, ret,
587 		  "Decoding transited encoding");
588 	return ret;
589     }
590     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
591 	/* not us, so add the previous realm to transited set */
592 	if (num_realms < 0 || num_realms + 1 > UINT_MAX/sizeof(*realms)) {
593 	    ret = ERANGE;
594 	    goto free_realms;
595 	}
596 	tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
597 	if(tmp == NULL){
598 	    ret = ENOMEM;
599 	    goto free_realms;
600 	}
601 	realms = tmp;
602 	realms[num_realms] = strdup(tgt_realm);
603 	if(realms[num_realms] == NULL){
604 	    ret = ENOMEM;
605 	    goto free_realms;
606 	}
607 	num_realms++;
608     }
609     if(num_realms == 0) {
610 	if(strcmp(client_realm, server_realm))
611 	    kdc_log(context, config, 0,
612 		    "cross-realm %s -> %s", client_realm, server_realm);
613     } else {
614 	size_t l = 0;
615 	char *rs;
616 	for(i = 0; i < num_realms; i++)
617 	    l += strlen(realms[i]) + 2;
618 	rs = malloc(l);
619 	if(rs != NULL) {
620 	    *rs = '\0';
621 	    for(i = 0; i < num_realms; i++) {
622 		if(i > 0)
623 		    strlcat(rs, ", ", l);
624 		strlcat(rs, realms[i], l);
625 	    }
626 	    kdc_log(context, config, 0,
627 		    "cross-realm %s -> %s via [%s]",
628 		    client_realm, server_realm, rs);
629 	    free(rs);
630 	}
631     }
632     if(check_policy) {
633 	ret = krb5_check_transited(context, client_realm,
634 				   server_realm,
635 				   realms, num_realms, NULL);
636 	if(ret) {
637 	    krb5_warn(context, ret, "cross-realm %s -> %s",
638 		      client_realm, server_realm);
639 	    goto free_realms;
640 	}
641 	et->flags.transited_policy_checked = 1;
642     }
643     et->transited.tr_type = DOMAIN_X500_COMPRESS;
644     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
645     if(ret)
646 	krb5_warn(context, ret, "Encoding transited encoding");
647   free_realms:
648     for(i = 0; i < num_realms; i++)
649 	free(realms[i]);
650     free(realms);
651     return ret;
652 }
653 
654 
655 static krb5_error_code
656 tgs_make_reply(krb5_context context,
657 	       krb5_kdc_configuration *config,
658 	       KDC_REQ_BODY *b,
659 	       krb5_const_principal tgt_name,
660 	       const EncTicketPart *tgt,
661 	       const EncryptionKey *serverkey,
662 	       const krb5_keyblock *sessionkey,
663 	       krb5_kvno kvno,
664 	       AuthorizationData *auth_data,
665 	       hdb_entry_ex *server,
666 	       const char *server_name,
667 	       hdb_entry_ex *client,
668 	       krb5_principal client_principal,
669 	       hdb_entry_ex *krbtgt,
670 	       krb5_enctype krbtgt_etype,
671 	       KRB5SignedPathPrincipals *spp,
672 	       const krb5_data *rspac,
673 	       const char **e_text,
674 	       krb5_data *reply)
675 {
676     KDC_REP rep;
677     EncKDCRepPart ek;
678     EncTicketPart et;
679     KDCOptions f = b->kdc_options;
680     krb5_error_code ret;
681 
682     memset(&rep, 0, sizeof(rep));
683     memset(&et, 0, sizeof(et));
684     memset(&ek, 0, sizeof(ek));
685 
686     rep.pvno = 5;
687     rep.msg_type = krb_tgs_rep;
688 
689     et.authtime = tgt->authtime;
690     _kdc_fix_time(&b->till);
691     et.endtime = min(tgt->endtime, *b->till);
692     ALLOC(et.starttime);
693     *et.starttime = kdc_time;
694 
695     ret = check_tgs_flags(context, config, b, tgt, &et);
696     if(ret)
697 	goto out;
698 
699     /* We should check the transited encoding if:
700        1) the request doesn't ask not to be checked
701        2) globally enforcing a check
702        3) principal requires checking
703        4) we allow non-check per-principal, but principal isn't marked as allowing this
704        5) we don't globally allow this
705     */
706 
707 #define GLOBAL_FORCE_TRANSITED_CHECK		\
708     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
709 #define GLOBAL_ALLOW_PER_PRINCIPAL			\
710     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
711 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK			\
712     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
713 
714 /* these will consult the database in future release */
715 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)		0
716 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)	0
717 
718     ret = fix_transited_encoding(context, config,
719 				 !f.disable_transited_check ||
720 				 GLOBAL_FORCE_TRANSITED_CHECK ||
721 				 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
722 				 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
723 				    PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
724 				   GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
725 				 &tgt->transited, &et,
726 				 *krb5_princ_realm(context, client_principal),
727 				 *krb5_princ_realm(context, server->entry.principal),
728 				 *krb5_princ_realm(context, krbtgt->entry.principal));
729     if(ret)
730 	goto out;
731 
732     copy_Realm(krb5_princ_realm(context, server->entry.principal),
733 	       &rep.ticket.realm);
734     _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal);
735     copy_Realm(&tgt_name->realm, &rep.crealm);
736 /*
737     if (f.request_anonymous)
738 	_kdc_make_anonymous_principalname (&rep.cname);
739     else */
740 
741     copy_PrincipalName(&tgt_name->name, &rep.cname);
742     rep.ticket.tkt_vno = 5;
743 
744     ek.caddr = et.caddr;
745     if(et.caddr == NULL)
746 	et.caddr = tgt->caddr;
747 
748     {
749 	time_t life;
750 	life = et.endtime - *et.starttime;
751 	if(client && client->entry.max_life)
752 	    life = min(life, *client->entry.max_life);
753 	if(server->entry.max_life)
754 	    life = min(life, *server->entry.max_life);
755 	et.endtime = *et.starttime + life;
756     }
757     if(f.renewable_ok && tgt->flags.renewable &&
758        et.renew_till == NULL && et.endtime < *b->till){
759 	et.flags.renewable = 1;
760 	ALLOC(et.renew_till);
761 	*et.renew_till = *b->till;
762     }
763     if(et.renew_till){
764 	time_t renew;
765 	renew = *et.renew_till - et.authtime;
766 	if(client && client->entry.max_renew)
767 	    renew = min(renew, *client->entry.max_renew);
768 	if(server->entry.max_renew)
769 	    renew = min(renew, *server->entry.max_renew);
770 	*et.renew_till = et.authtime + renew;
771     }
772 
773     if(et.renew_till){
774 	*et.renew_till = min(*et.renew_till, *tgt->renew_till);
775 	*et.starttime = min(*et.starttime, *et.renew_till);
776 	et.endtime = min(et.endtime, *et.renew_till);
777     }
778 
779     *et.starttime = min(*et.starttime, et.endtime);
780 
781     if(*et.starttime == et.endtime){
782 	ret = KRB5KDC_ERR_NEVER_VALID;
783 	goto out;
784     }
785     if(et.renew_till && et.endtime == *et.renew_till){
786 	free(et.renew_till);
787 	et.renew_till = NULL;
788 	et.flags.renewable = 0;
789     }
790 
791     et.flags.pre_authent = tgt->flags.pre_authent;
792     et.flags.hw_authent  = tgt->flags.hw_authent;
793     et.flags.anonymous   = tgt->flags.anonymous;
794     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
795 
796     if (auth_data) {
797 	/* XXX Check enc-authorization-data */
798 	et.authorization_data = calloc(1, sizeof(*et.authorization_data));
799 	if (et.authorization_data == NULL) {
800 	    ret = ENOMEM;
801 	    goto out;
802 	}
803 	ret = copy_AuthorizationData(auth_data, et.authorization_data);
804 	if (ret)
805 	    goto out;
806 
807 	/* Filter out type KRB5SignedPath */
808 	ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
809 	if (ret == 0) {
810 	    if (et.authorization_data->len == 1) {
811 		free_AuthorizationData(et.authorization_data);
812 		free(et.authorization_data);
813 		et.authorization_data = NULL;
814 	    } else {
815 		AuthorizationData *ad = et.authorization_data;
816 		free_AuthorizationDataElement(&ad->val[ad->len - 1]);
817 		ad->len--;
818 	    }
819 	}
820     }
821 
822     if(rspac->length) {
823 	/*
824 	 * No not need to filter out the any PAC from the
825 	 * auth_data since it's signed by the KDC.
826 	 */
827 	ret = _kdc_tkt_add_if_relevant_ad(context, &et,
828 					  KRB5_AUTHDATA_WIN2K_PAC,
829 					  rspac);
830 	if (ret)
831 	    goto out;
832     }
833 
834     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
835     if (ret)
836 	goto out;
837     et.crealm = tgt->crealm;
838     et.cname = tgt_name->name;
839 
840     ek.key = et.key;
841     /* MIT must have at least one last_req */
842     ek.last_req.len = 1;
843     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
844     if (ek.last_req.val == NULL) {
845 	ret = ENOMEM;
846 	goto out;
847     }
848     ek.nonce = b->nonce;
849     ek.flags = et.flags;
850     ek.authtime = et.authtime;
851     ek.starttime = et.starttime;
852     ek.endtime = et.endtime;
853     ek.renew_till = et.renew_till;
854     ek.srealm = rep.ticket.realm;
855     ek.sname = rep.ticket.sname;
856 
857     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
858 		       et.endtime, et.renew_till);
859 
860     /* Don't sign cross realm tickets, they can't be checked anyway */
861     {
862 	char *r = get_krbtgt_realm(&ek.sname);
863 
864 	if (r == NULL || strcmp(r, ek.srealm) == 0) {
865 	    ret = _kdc_add_KRB5SignedPath(context,
866 					  config,
867 					  krbtgt,
868 					  krbtgt_etype,
869 					  NULL,
870 					  spp,
871 					  &et);
872 	    if (ret)
873 		goto out;
874 	}
875     }
876 
877     /* It is somewhat unclear where the etype in the following
878        encryption should come from. What we have is a session
879        key in the passed tgt, and a list of preferred etypes
880        *for the new ticket*. Should we pick the best possible
881        etype, given the keytype in the tgt, or should we look
882        at the etype list here as well?  What if the tgt
883        session key is DES3 and we want a ticket with a (say)
884        CAST session key. Should the DES3 etype be added to the
885        etype list, even if we don't want a session key with
886        DES3? */
887     ret = _kdc_encode_reply(context, config,
888 			    &rep, &et, &ek, et.key.keytype,
889 			    kvno,
890 			    serverkey, 0, &tgt->key, e_text, reply);
891 out:
892     free_TGS_REP(&rep);
893     free_TransitedEncoding(&et.transited);
894     if(et.starttime)
895 	free(et.starttime);
896     if(et.renew_till)
897 	free(et.renew_till);
898     if(et.authorization_data) {
899 	free_AuthorizationData(et.authorization_data);
900 	free(et.authorization_data);
901     }
902     free_LastReq(&ek.last_req);
903     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
904     free_EncryptionKey(&et.key);
905     return ret;
906 }
907 
908 static krb5_error_code
909 tgs_check_authenticator(krb5_context context,
910 			krb5_kdc_configuration *config,
911 	                krb5_auth_context ac,
912 			KDC_REQ_BODY *b,
913 			const char **e_text,
914 			krb5_keyblock *key)
915 {
916     krb5_authenticator auth;
917     size_t len;
918     unsigned char *buf;
919     size_t buf_size;
920     krb5_error_code ret;
921     krb5_crypto crypto;
922 
923     krb5_auth_con_getauthenticator(context, ac, &auth);
924     if(auth->cksum == NULL){
925 	kdc_log(context, config, 0, "No authenticator in request");
926 	ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
927 	goto out;
928     }
929     /*
930      * according to RFC1510 it doesn't need to be keyed,
931      * but according to the latest draft it needs to.
932      */
933     if (
934 #if 0
935 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
936 	||
937 #endif
938  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
939 	kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
940 		auth->cksum->cksumtype);
941 	ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
942 	goto out;
943     }
944 
945     /* XXX should not re-encode this */
946     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
947     if(ret){
948 	kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
949 		krb5_get_err_text(context, ret));
950 	goto out;
951     }
952     if(buf_size != len) {
953 	free(buf);
954 	kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
955 	*e_text = "KDC internal error";
956 	ret = KRB5KRB_ERR_GENERIC;
957 	goto out;
958     }
959     ret = krb5_crypto_init(context, key, 0, &crypto);
960     if (ret) {
961 	free(buf);
962 	kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
963 		krb5_get_err_text(context, ret));
964 	goto out;
965     }
966     ret = krb5_verify_checksum(context,
967 			       crypto,
968 			       KRB5_KU_TGS_REQ_AUTH_CKSUM,
969 			       buf,
970 			       len,
971 			       auth->cksum);
972     free(buf);
973     krb5_crypto_destroy(context, crypto);
974     if(ret){
975 	kdc_log(context, config, 0,
976 		"Failed to verify authenticator checksum: %s",
977 		krb5_get_err_text(context, ret));
978     }
979 out:
980     free_Authenticator(auth);
981     free(auth);
982     return ret;
983 }
984 
985 /*
986  *
987  */
988 
989 static const char *
990 find_rpath(krb5_context context, Realm crealm, Realm srealm)
991 {
992     const char *new_realm = krb5_config_get_string(context,
993 						   NULL,
994 						   "capaths",
995 						   crealm,
996 						   srealm,
997 						   NULL);
998     return new_realm;
999 }
1000 
1001 
1002 static krb5_boolean
1003 need_referral(krb5_context context, krb5_principal server, krb5_realm **realms)
1004 {
1005     if(server->name.name_type != KRB5_NT_SRV_INST ||
1006        server->name.name_string.len != 2)
1007 	return FALSE;
1008 
1009     return _krb5_get_host_realm_int(context, server->name.name_string.val[1],
1010 				    FALSE, realms) == 0;
1011 }
1012 
1013 static krb5_error_code
1014 tgs_parse_request(krb5_context context,
1015 		  krb5_kdc_configuration *config,
1016 		  KDC_REQ_BODY *b,
1017 		  const PA_DATA *tgs_req,
1018 		  hdb_entry_ex **krbtgt,
1019 		  krb5_enctype *krbtgt_etype,
1020 		  krb5_ticket **ticket,
1021 		  const char **e_text,
1022 		  const char *from,
1023 		  const struct sockaddr *from_addr,
1024 		  time_t **csec,
1025 		  int **cusec,
1026 		  AuthorizationData **auth_data)
1027 {
1028     krb5_ap_req ap_req;
1029     krb5_error_code ret;
1030     krb5_principal princ;
1031     krb5_auth_context ac = NULL;
1032     krb5_flags ap_req_options;
1033     krb5_flags verify_ap_req_flags;
1034     krb5_crypto crypto;
1035     Key *tkey;
1036 
1037     *auth_data = NULL;
1038     *csec  = NULL;
1039     *cusec = NULL;
1040 
1041     memset(&ap_req, 0, sizeof(ap_req));
1042     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1043     if(ret){
1044 	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1045 		krb5_get_err_text(context, ret));
1046 	goto out;
1047     }
1048 
1049     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1050 	/* XXX check for ticket.sname == req.sname */
1051 	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1052 	ret = KRB5KDC_ERR_POLICY; /* ? */
1053 	goto out;
1054     }
1055 
1056     _krb5_principalname2krb5_principal(context,
1057 				       &princ,
1058 				       ap_req.ticket.sname,
1059 				       ap_req.ticket.realm);
1060 
1061     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1062 
1063     if(ret) {
1064 	char *p;
1065 	ret = krb5_unparse_name(context, princ, &p);
1066 	if (ret != 0)
1067 	    p = "<unparse_name failed>";
1068 	krb5_free_principal(context, princ);
1069 	kdc_log(context, config, 0,
1070 		"Ticket-granting ticket not found in database: %s: %s",
1071 		p, krb5_get_err_text(context, ret));
1072 	if (ret == 0)
1073 	    free(p);
1074 	ret = KRB5KRB_AP_ERR_NOT_US;
1075 	goto out;
1076     }
1077 
1078     if(ap_req.ticket.enc_part.kvno &&
1079        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1080 	char *p;
1081 
1082 	ret = krb5_unparse_name (context, princ, &p);
1083 	krb5_free_principal(context, princ);
1084 	if (ret != 0)
1085 	    p = "<unparse_name failed>";
1086 	kdc_log(context, config, 0,
1087 		"Ticket kvno = %d, DB kvno = %d (%s)",
1088 		*ap_req.ticket.enc_part.kvno,
1089 		(*krbtgt)->entry.kvno,
1090 		p);
1091 	if (ret == 0)
1092 	    free (p);
1093 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1094 	goto out;
1095     }
1096 
1097     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1098 
1099     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1100 			  ap_req.ticket.enc_part.etype, &tkey);
1101     if(ret){
1102 	char *str = NULL, *p = NULL;
1103 
1104 	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1105 	krb5_unparse_name(context, princ, &p);
1106  	kdc_log(context, config, 0,
1107 		"No server key with enctype %s found for %s",
1108 		str ? str : "<unknown enctype>",
1109 		p ? p : "<unparse_name failed>");
1110 	free(str);
1111 	free(p);
1112 	ret = KRB5KRB_AP_ERR_BADKEYVER;
1113 	goto out;
1114     }
1115 
1116     if (b->kdc_options.validate)
1117 	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1118     else
1119 	verify_ap_req_flags = 0;
1120 
1121     ret = krb5_verify_ap_req2(context,
1122 			      &ac,
1123 			      &ap_req,
1124 			      princ,
1125 			      &tkey->key,
1126 			      verify_ap_req_flags,
1127 			      &ap_req_options,
1128 			      ticket,
1129 			      KRB5_KU_TGS_REQ_AUTH);
1130 
1131     krb5_free_principal(context, princ);
1132     if(ret) {
1133 	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1134 		krb5_get_err_text(context, ret));
1135 	goto out;
1136     }
1137 
1138     {
1139 	krb5_authenticator auth;
1140 
1141 	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1142 	if (ret == 0) {
1143 	    *csec   = malloc(sizeof(**csec));
1144 	    if (*csec == NULL) {
1145 		krb5_free_authenticator(context, &auth);
1146 		kdc_log(context, config, 0, "malloc failed");
1147 		goto out;
1148 	    }
1149 	    **csec  = auth->ctime;
1150 	    *cusec  = malloc(sizeof(**cusec));
1151 	    if (*cusec == NULL) {
1152 		krb5_free_authenticator(context, &auth);
1153 		kdc_log(context, config, 0, "malloc failed");
1154 		goto out;
1155 	    }
1156 	    **cusec  = auth->cusec;
1157 	    krb5_free_authenticator(context, &auth);
1158 	}
1159     }
1160 
1161     ret = tgs_check_authenticator(context, config,
1162 				  ac, b, e_text, &(*ticket)->ticket.key);
1163     if (ret) {
1164 	krb5_auth_con_free(context, ac);
1165 	goto out;
1166     }
1167 
1168     if (b->enc_authorization_data) {
1169 	unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1170 	krb5_keyblock *subkey;
1171 	krb5_data ad;
1172 
1173 	ret = krb5_auth_con_getremotesubkey(context,
1174 					    ac,
1175 					    &subkey);
1176 	if(ret){
1177 	    krb5_auth_con_free(context, ac);
1178 	    kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1179 		    krb5_get_err_text(context, ret));
1180 	    goto out;
1181 	}
1182 	if(subkey == NULL){
1183 	    usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1184 	    ret = krb5_auth_con_getkey(context, ac, &subkey);
1185 	    if(ret) {
1186 		krb5_auth_con_free(context, ac);
1187 		kdc_log(context, config, 0, "Failed to get session key: %s",
1188 			krb5_get_err_text(context, ret));
1189 		goto out;
1190 	    }
1191 	}
1192 	if(subkey == NULL){
1193 	    krb5_auth_con_free(context, ac);
1194 	    kdc_log(context, config, 0,
1195 		    "Failed to get key for enc-authorization-data");
1196 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1197 	    goto out;
1198 	}
1199 	ret = krb5_crypto_init(context, subkey, 0, &crypto);
1200 	if (ret) {
1201 	    krb5_auth_con_free(context, ac);
1202 	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1203 		    krb5_get_err_text(context, ret));
1204 	    goto out;
1205 	}
1206 	ret = krb5_decrypt_EncryptedData (context,
1207 					  crypto,
1208 					  usage,
1209 					  b->enc_authorization_data,
1210 					  &ad);
1211 	krb5_crypto_destroy(context, crypto);
1212 	if(ret){
1213 	    krb5_auth_con_free(context, ac);
1214 	    kdc_log(context, config, 0,
1215 		    "Failed to decrypt enc-authorization-data");
1216 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1217 	    goto out;
1218 	}
1219 	krb5_free_keyblock(context, subkey);
1220 	ALLOC(*auth_data);
1221 	if (*auth_data == NULL) {
1222 	    krb5_auth_con_free(context, ac);
1223 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1224 	    goto out;
1225 	}
1226 	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1227 	if(ret){
1228 	    krb5_auth_con_free(context, ac);
1229 	    free(*auth_data);
1230 	    *auth_data = NULL;
1231 	    kdc_log(context, config, 0, "Failed to decode authorization data");
1232 	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1233 	    goto out;
1234 	}
1235     }
1236 
1237     krb5_auth_con_free(context, ac);
1238 
1239 out:
1240     free_AP_REQ(&ap_req);
1241 
1242     return ret;
1243 }
1244 
1245 static krb5_error_code
1246 tgs_build_reply(krb5_context context,
1247 		krb5_kdc_configuration *config,
1248 		KDC_REQ *req,
1249 		KDC_REQ_BODY *b,
1250 		hdb_entry_ex *krbtgt,
1251 		krb5_enctype krbtgt_etype,
1252 		krb5_ticket *ticket,
1253 		krb5_data *reply,
1254 		const char *from,
1255 		const char **e_text,
1256 		AuthorizationData *auth_data,
1257 		const struct sockaddr *from_addr,
1258 		int datagram_reply)
1259 {
1260     krb5_error_code ret;
1261     krb5_principal cp = NULL, sp = NULL;
1262     krb5_principal client_principal = NULL;
1263     char *spn = NULL, *cpn = NULL;
1264     hdb_entry_ex *server = NULL, *client = NULL;
1265     EncTicketPart *tgt = &ticket->ticket;
1266     KRB5SignedPathPrincipals *spp = NULL;
1267     const EncryptionKey *ekey;
1268     krb5_keyblock sessionkey;
1269     krb5_kvno kvno;
1270     krb5_data rspac;
1271     int cross_realm = 0;
1272 
1273     PrincipalName *s;
1274     Realm r;
1275     int nloop = 0;
1276     EncTicketPart adtkt;
1277     char opt_str[128];
1278     int require_signedpath = 0;
1279 
1280     memset(&sessionkey, 0, sizeof(sessionkey));
1281     memset(&adtkt, 0, sizeof(adtkt));
1282     krb5_data_zero(&rspac);
1283 
1284     s = b->sname;
1285     r = b->realm;
1286 
1287     if(b->kdc_options.enc_tkt_in_skey){
1288 	Ticket *t;
1289 	hdb_entry_ex *uu;
1290 	krb5_principal p;
1291 	Key *uukey;
1292 
1293 	if(b->additional_tickets == NULL ||
1294 	   b->additional_tickets->len == 0){
1295 	    ret = KRB5KDC_ERR_BADOPTION; /* ? */
1296 	    kdc_log(context, config, 0,
1297 		    "No second ticket present in request");
1298 	    goto out;
1299 	}
1300 	t = &b->additional_tickets->val[0];
1301 	if(!get_krbtgt_realm(&t->sname)){
1302 	    kdc_log(context, config, 0,
1303 		    "Additional ticket is not a ticket-granting ticket");
1304 	    ret = KRB5KDC_ERR_POLICY;
1305 	    goto out;
1306 	}
1307 	_krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1308 	ret = _kdc_db_fetch(context, config, p,
1309 			    HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1310 			    NULL, &uu);
1311 	krb5_free_principal(context, p);
1312 	if(ret){
1313 	    if (ret == HDB_ERR_NOENTRY)
1314 		ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1315 	    goto out;
1316 	}
1317 	ret = hdb_enctype2key(context, &uu->entry,
1318 			      t->enc_part.etype, &uukey);
1319 	if(ret){
1320 	    _kdc_free_ent(context, uu);
1321 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1322 	    goto out;
1323 	}
1324 	ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1325 	_kdc_free_ent(context, uu);
1326 	if(ret)
1327 	    goto out;
1328 
1329 	ret = verify_flags(context, config, &adtkt, spn);
1330 	if (ret)
1331 	    goto out;
1332 
1333 	s = &adtkt.cname;
1334 	r = adtkt.crealm;
1335     }
1336 
1337     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1338     ret = krb5_unparse_name(context, sp, &spn);
1339     if (ret)
1340 	goto out;
1341     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1342     ret = krb5_unparse_name(context, cp, &cpn);
1343     if (ret)
1344 	goto out;
1345     unparse_flags (KDCOptions2int(b->kdc_options),
1346 		   asn1_KDCOptions_units(),
1347 		   opt_str, sizeof(opt_str));
1348     if(*opt_str)
1349 	kdc_log(context, config, 0,
1350 		"TGS-REQ %s from %s for %s [%s]",
1351 		cpn, from, spn, opt_str);
1352     else
1353 	kdc_log(context, config, 0,
1354 		"TGS-REQ %s from %s for %s", cpn, from, spn);
1355 
1356     /*
1357      * Fetch server
1358      */
1359 
1360 server_lookup:
1361     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);
1362 
1363     if(ret){
1364 	const char *new_rlm;
1365 	Realm req_rlm;
1366 	krb5_realm *realms;
1367 
1368 	if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1369 	    if(nloop++ < 2) {
1370 		new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1371 		if(new_rlm) {
1372 		    kdc_log(context, config, 5, "krbtgt for realm %s "
1373 			    "not found, trying %s",
1374 			    req_rlm, new_rlm);
1375 		    krb5_free_principal(context, sp);
1376 		    free(spn);
1377 		    krb5_make_principal(context, &sp, r,
1378 					KRB5_TGS_NAME, new_rlm, NULL);
1379 		    ret = krb5_unparse_name(context, sp, &spn);
1380 		    if (ret)
1381 			goto out;
1382 		    auth_data = NULL; /* ms don't handle AD in referals */
1383 		    goto server_lookup;
1384 		}
1385 	    }
1386 	} else if(need_referral(context, sp, &realms)) {
1387 	    if (strcmp(realms[0], sp->realm) != 0) {
1388 		kdc_log(context, config, 5,
1389 			"Returning a referral to realm %s for "
1390 			"server %s that was not found",
1391 			realms[0], spn);
1392 		krb5_free_principal(context, sp);
1393 		free(spn);
1394 		krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1395 				    realms[0], NULL);
1396 		ret = krb5_unparse_name(context, sp, &spn);
1397 		if (ret)
1398 		    goto out;
1399 		krb5_free_host_realm(context, realms);
1400 		auth_data = NULL; /* ms don't handle AD in referals */
1401 		goto server_lookup;
1402 	    }
1403 	    krb5_free_host_realm(context, realms);
1404 	}
1405 	kdc_log(context, config, 0,
1406 		"Server not found in database: %s: %s", spn,
1407 		krb5_get_err_text(context, ret));
1408 	if (ret == HDB_ERR_NOENTRY)
1409 	    ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1410 	goto out;
1411     }
1412 
1413     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
1414     if(ret) {
1415 	const char *krbtgt_realm;
1416 
1417 	/*
1418 	 * If the client belongs to the same realm as our krbtgt, it
1419 	 * should exist in the local database.
1420 	 *
1421 	 */
1422 
1423 	krbtgt_realm =
1424 	    krb5_principal_get_comp_string(context,
1425 					   krbtgt->entry.principal, 1);
1426 
1427 	if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1428 	    if (ret == HDB_ERR_NOENTRY)
1429 		ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1430 	    kdc_log(context, config, 1, "Client no longer in database: %s",
1431 		    cpn);
1432 	    goto out;
1433 	}
1434 
1435 	kdc_log(context, config, 1, "Client not found in database: %s: %s",
1436 		cpn, krb5_get_err_text(context, ret));
1437 
1438 	cross_realm = 1;
1439     }
1440 
1441     /*
1442      * Check that service is in the same realm as the krbtgt. If it's
1443      * not the same, it's someone that is using a uni-directional trust
1444      * backward.
1445      */
1446 
1447     if (strcmp(krb5_principal_get_realm(context, sp),
1448 	       krb5_principal_get_comp_string(context,
1449 					      krbtgt->entry.principal,
1450 					      1)) != 0) {
1451 	char *tpn;
1452 	ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1453 	kdc_log(context, config, 0,
1454 		"Request with wrong krbtgt: %s",
1455 		(ret == 0) ? tpn : "<unknown>");
1456 	if(ret == 0)
1457 	    free(tpn);
1458 	ret = KRB5KRB_AP_ERR_NOT_US;
1459 	goto out;
1460     }
1461 
1462     /*
1463      *
1464      */
1465 
1466     client_principal = cp;
1467 
1468     if (client) {
1469 	const PA_DATA *sdata;
1470 	int i = 0;
1471 
1472 	sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
1473 	if (sdata) {
1474 	    krb5_crypto crypto;
1475 	    krb5_data datack;
1476 	    PA_S4U2Self self;
1477 	    char *selfcpn = NULL;
1478 	    const char *str;
1479 
1480 	    ret = decode_PA_S4U2Self(sdata->padata_value.data,
1481 				     sdata->padata_value.length,
1482 				     &self, NULL);
1483 	    if (ret) {
1484 		kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1485 		goto out;
1486 	    }
1487 
1488 	    ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1489 	    if (ret)
1490 		goto out;
1491 
1492 	    ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1493 	    if (ret) {
1494 		free_PA_S4U2Self(&self);
1495 		krb5_data_free(&datack);
1496 		kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1497 			krb5_get_err_text(context, ret));
1498 		goto out;
1499 	    }
1500 
1501 	    ret = krb5_verify_checksum(context,
1502 				       crypto,
1503 				       KRB5_KU_OTHER_CKSUM,
1504 				       datack.data,
1505 				       datack.length,
1506 				       &self.cksum);
1507 	    krb5_data_free(&datack);
1508 	    krb5_crypto_destroy(context, crypto);
1509 	    if (ret) {
1510 		free_PA_S4U2Self(&self);
1511 		kdc_log(context, config, 0,
1512 			"krb5_verify_checksum failed for S4U2Self: %s",
1513 			krb5_get_err_text(context, ret));
1514 		goto out;
1515 	    }
1516 
1517 	    ret = _krb5_principalname2krb5_principal(context,
1518 						     &client_principal,
1519 						     self.name,
1520 						     self.realm);
1521 	    free_PA_S4U2Self(&self);
1522 	    if (ret)
1523 		goto out;
1524 
1525 	    ret = krb5_unparse_name(context, client_principal, &selfcpn);
1526 	    if (ret)
1527 		goto out;
1528 
1529 	    /*
1530 	     * Check that service doing the impersonating is
1531 	     * requesting a ticket to it-self.
1532 	     */
1533 	    if (krb5_principal_compare(context, cp, sp) != TRUE) {
1534 		kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1535 			"to impersonate some other user "
1536 			"(tried for user %s to service %s)",
1537 			cpn, selfcpn, spn);
1538 		free(selfcpn);
1539 		ret = KRB5KDC_ERR_BADOPTION; /* ? */
1540 		goto out;
1541 	    }
1542 
1543 	    /*
1544 	     * If the service isn't trusted for authentication to
1545 	     * delegation, remove the forward flag.
1546 	     */
1547 
1548 	    if (client->entry.flags.trusted_for_delegation) {
1549 		str = "[forwardable]";
1550 	    } else {
1551 		b->kdc_options.forwardable = 0;
1552 		str = "";
1553 	    }
1554 	    kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1555 		    "service %s %s", cpn, selfcpn, spn, str);
1556 	    free(selfcpn);
1557 	}
1558     }
1559 
1560     /*
1561      * Constrained delegation
1562      */
1563 
1564     if (client != NULL
1565 	&& b->additional_tickets != NULL
1566 	&& b->additional_tickets->len != 0
1567 	&& b->kdc_options.enc_tkt_in_skey == 0)
1568     {
1569 	Key *clientkey;
1570 	Ticket *t;
1571 	char *str;
1572 
1573 	t = &b->additional_tickets->val[0];
1574 
1575 	ret = hdb_enctype2key(context, &client->entry,
1576 			      t->enc_part.etype, &clientkey);
1577 	if(ret){
1578 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1579 	    goto out;
1580 	}
1581 
1582 	ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1583 	if (ret) {
1584 	    kdc_log(context, config, 0,
1585 		    "failed to decrypt ticket for "
1586 		    "constrained delegation from %s to %s ", spn, cpn);
1587 	    goto out;
1588 	}
1589 
1590 	/* check that ticket is valid */
1591 
1592 	if (adtkt.flags.forwardable == 0) {
1593 	    kdc_log(context, config, 0,
1594 		    "Missing forwardable flag on ticket for "
1595 		    "constrained delegation from %s to %s ", spn, cpn);
1596 	    ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1597 	    goto out;
1598 	}
1599 
1600 	ret = check_constrained_delegation(context, config, client, sp);
1601 	if (ret) {
1602 	    kdc_log(context, config, 0,
1603 		    "constrained delegation from %s to %s not allowed",
1604 		    spn, cpn);
1605 	    goto out;
1606 	}
1607 
1608 	ret = _krb5_principalname2krb5_principal(context,
1609 						 &client_principal,
1610 						 adtkt.cname,
1611 						 adtkt.crealm);
1612 	if (ret)
1613 	    goto out;
1614 
1615 	ret = krb5_unparse_name(context, client_principal, &str);
1616 	if (ret)
1617 	    goto out;
1618 
1619 	ret = verify_flags(context, config, &adtkt, str);
1620 	if (ret) {
1621 	    free(str);
1622 	    goto out;
1623 	}
1624 
1625 	/*
1626 	 * Check KRB5SignedPath in authorization data and add new entry to
1627 	 * make sure servers can't fake a ticket to us.
1628 	 */
1629 
1630 	ret = check_KRB5SignedPath(context,
1631 				   config,
1632 				   krbtgt,
1633 				   &adtkt,
1634 				   &spp,
1635 				   1);
1636 	if (ret) {
1637 	    kdc_log(context, config, 0,
1638 		    "KRB5SignedPath check from service %s failed "
1639 		    "for delegation to %s for client %s "
1640 		    "from %s failed with %s",
1641 		    spn, str, cpn, from, krb5_get_err_text(context, ret));
1642 	    free(str);
1643 	    goto out;
1644 	}
1645 
1646 	kdc_log(context, config, 0, "constrained delegation for %s "
1647 		"from %s to %s", str, cpn, spn);
1648 	free(str);
1649 
1650 	/*
1651 	 * Also require that the KDC have issue the service's krbtgt
1652 	 * used to do the request.
1653 	 */
1654 	require_signedpath = 1;
1655     }
1656 
1657     /*
1658      * Check flags
1659      */
1660 
1661     ret = _kdc_check_flags(context, config,
1662 			   client, cpn,
1663 			   server, spn,
1664 			   FALSE);
1665     if(ret)
1666 	goto out;
1667 
1668     if((b->kdc_options.validate || b->kdc_options.renew) &&
1669        !krb5_principal_compare(context,
1670 			       krbtgt->entry.principal,
1671 			       server->entry.principal)){
1672 	kdc_log(context, config, 0, "Inconsistent request.");
1673 	ret = KRB5KDC_ERR_SERVER_NOMATCH;
1674 	goto out;
1675     }
1676 
1677     /* check for valid set of addresses */
1678     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1679 	ret = KRB5KRB_AP_ERR_BADADDR;
1680 	kdc_log(context, config, 0, "Request from wrong address");
1681 	goto out;
1682     }
1683 
1684     /*
1685      * Select enctype, return key and kvno.
1686      */
1687 
1688     {
1689 	krb5_enctype etype;
1690 
1691 	if(b->kdc_options.enc_tkt_in_skey) {
1692 	    int i;
1693 	    ekey = &adtkt.key;
1694 	    for(i = 0; i < b->etype.len; i++)
1695 		if (b->etype.val[i] == adtkt.key.keytype)
1696 		    break;
1697 	    if(i == b->etype.len) {
1698 		krb5_clear_error_string(context);
1699 		return KRB5KDC_ERR_ETYPE_NOSUPP;
1700 	    }
1701 	    etype = b->etype.val[i];
1702 	    kvno = 0;
1703 	} else {
1704 	    Key *skey;
1705 
1706 	    ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1707 				  &skey, &etype);
1708 	    if(ret) {
1709 		kdc_log(context, config, 0,
1710 			"Server (%s) has no support for etypes", spp);
1711 		return ret;
1712 	    }
1713 	    ekey = &skey->key;
1714 	    kvno = server->entry.kvno;
1715 	}
1716 
1717 	ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1718 	if (ret)
1719 	    goto out;
1720     }
1721 
1722     /* check PAC if not cross realm and if there is one */
1723     if (!cross_realm) {
1724 	Key *tkey;
1725 
1726 	ret = hdb_enctype2key(context, &krbtgt->entry,
1727 			      krbtgt_etype, &tkey);
1728 	if(ret) {
1729 	    kdc_log(context, config, 0,
1730 		    "Failed to find key for krbtgt PAC check");
1731 	    goto out;
1732 	}
1733 
1734 	ret = check_PAC(context, config, client_principal,
1735 			client, server, ekey, &tkey->key,
1736 			tgt, &rspac, &require_signedpath);
1737 	if (ret) {
1738 	    kdc_log(context, config, 0,
1739 		    "Verify PAC failed for %s (%s) from %s with %s",
1740 		    spn, cpn, from, krb5_get_err_text(context, ret));
1741 	    goto out;
1742 	}
1743     }
1744 
1745     /* also check the krbtgt for signature */
1746     ret = check_KRB5SignedPath(context,
1747 			       config,
1748 			       krbtgt,
1749 			       tgt,
1750 			       &spp,
1751 			       require_signedpath);
1752     if (ret) {
1753 	kdc_log(context, config, 0,
1754 		"KRB5SignedPath check failed for %s (%s) from %s with %s",
1755 		spn, cpn, from, krb5_get_err_text(context, ret));
1756 	goto out;
1757     }
1758 
1759     /*
1760      *
1761      */
1762 
1763     ret = tgs_make_reply(context,
1764 			 config,
1765 			 b,
1766 			 client_principal,
1767 			 tgt,
1768 			 ekey,
1769 			 &sessionkey,
1770 			 kvno,
1771 			 auth_data,
1772 			 server,
1773 			 spn,
1774 			 client,
1775 			 cp,
1776 			 krbtgt,
1777 			 krbtgt_etype,
1778 			 spp,
1779 			 &rspac,
1780 			 e_text,
1781 			 reply);
1782 
1783 out:
1784     free(spn);
1785     free(cpn);
1786 
1787     krb5_data_free(&rspac);
1788     krb5_free_keyblock_contents(context, &sessionkey);
1789     if(server)
1790 	_kdc_free_ent(context, server);
1791     if(client)
1792 	_kdc_free_ent(context, client);
1793 
1794     if (client_principal && client_principal != cp)
1795 	krb5_free_principal(context, client_principal);
1796     if (cp)
1797 	krb5_free_principal(context, cp);
1798     if (sp)
1799 	krb5_free_principal(context, sp);
1800 
1801     free_EncTicketPart(&adtkt);
1802 
1803     return ret;
1804 }
1805 
1806 /*
1807  *
1808  */
1809 
1810 krb5_error_code
1811 _kdc_tgs_rep(krb5_context context,
1812 	     krb5_kdc_configuration *config,
1813 	     KDC_REQ *req,
1814 	     krb5_data *data,
1815 	     const char *from,
1816 	     struct sockaddr *from_addr,
1817 	     int datagram_reply)
1818 {
1819     AuthorizationData *auth_data = NULL;
1820     krb5_error_code ret;
1821     int i = 0;
1822     const PA_DATA *tgs_req;
1823 
1824     hdb_entry_ex *krbtgt = NULL;
1825     krb5_ticket *ticket = NULL;
1826     const char *e_text = NULL;
1827     krb5_enctype krbtgt_etype = ETYPE_NULL;
1828 
1829     time_t *csec = NULL;
1830     int *cusec = NULL;
1831 
1832     if(req->padata == NULL){
1833 	ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1834 	kdc_log(context, config, 0,
1835 		"TGS-REQ from %s without PA-DATA", from);
1836 	goto out;
1837     }
1838 
1839     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
1840 
1841     if(tgs_req == NULL){
1842 	ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
1843 
1844 	kdc_log(context, config, 0,
1845 		"TGS-REQ from %s without PA-TGS-REQ", from);
1846 	goto out;
1847     }
1848     ret = tgs_parse_request(context, config,
1849 			    &req->req_body, tgs_req,
1850 			    &krbtgt,
1851 			    &krbtgt_etype,
1852 			    &ticket,
1853 			    &e_text,
1854 			    from, from_addr,
1855 			    &csec, &cusec,
1856 			    &auth_data);
1857     if (ret) {
1858 	kdc_log(context, config, 0,
1859 		"Failed parsing TGS-REQ from %s", from);
1860 	goto out;
1861     }
1862 
1863     ret = tgs_build_reply(context,
1864 			  config,
1865 			  req,
1866 			  &req->req_body,
1867 			  krbtgt,
1868 			  krbtgt_etype,
1869 			  ticket,
1870 			  data,
1871 			  from,
1872 			  &e_text,
1873 			  auth_data,
1874 			  from_addr,
1875 			  datagram_reply);
1876     if (ret) {
1877 	kdc_log(context, config, 0,
1878 		"Failed building TGS-REP to %s", from);
1879 	goto out;
1880     }
1881 
1882     /* */
1883     if (datagram_reply && data->length > config->max_datagram_reply_length) {
1884 	krb5_data_free(data);
1885 	ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
1886 	e_text = "Reply packet too large";
1887     }
1888 
1889 out:
1890     if(ret && data->data == NULL){
1891 	krb5_mk_error(context,
1892 		      ret,
1893 		      NULL,
1894 		      NULL,
1895 		      NULL,
1896 		      NULL,
1897 		      csec,
1898 		      cusec,
1899 		      data);
1900     }
1901     free(csec);
1902     free(cusec);
1903     if (ticket)
1904 	krb5_free_ticket(context, ticket);
1905     if(krbtgt)
1906 	_kdc_free_ent(context, krbtgt);
1907 
1908     if (auth_data) {
1909 	free_AuthorizationData(auth_data);
1910 	free(auth_data);
1911     }
1912 
1913     return 0;
1914 }
1915