]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/kdc/krb5tgs.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / kdc / krb5tgs.c
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
36 RCSID("$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
42 static Realm 
43 get_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
61 static krb5_error_code
62 find_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
104 krb5_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
184 static krb5_error_code
185 check_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
279 static krb5_error_code
280 check_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
361 static krb5_error_code
362 check_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
493 static krb5_error_code
494 check_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
524 static krb5_error_code
525 verify_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
545 static krb5_error_code
546 fix_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
655 static krb5_error_code
656 tgs_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);
891 out:
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
908 static krb5_error_code
909 tgs_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     }
979 out:
980     free_Authenticator(auth);
981     free(auth);
982     return ret;
983 }
984
985 /*
986  *
987  */
988
989 static const char *
990 find_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
1002 static krb5_boolean
1003 need_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
1013 static krb5_error_code
1014 tgs_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     
1239 out:
1240     free_AP_REQ(&ap_req);
1241     
1242     return ret;
1243 }
1244
1245 static krb5_error_code
1246 tgs_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
1360 server_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         
1783 out:
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
1810 krb5_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
1889 out:
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 }