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