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