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