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