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