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