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