071a30d5a78a674d1ce126683f4dc5e3185c7615
[samba.git] / source4 / heimdal / kdc / krb5tgs.c
1 /*
2  * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "kdc_locl.h"
35
36 RCSID("$Id: krb5tgs.c 23316 2008-06-23 04:32:32Z 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_message(context, ret, "Failed to decode "
84                                "IF_RELEVANT with %d", ret);
85         return ret;
86     }
87
88     if (child.len != 1) {
89         free_AuthorizationData(&child);
90         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91     }
92
93     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94         free_AuthorizationData(&child);
95         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
96     }
97
98     if (data)
99         ret = der_copy_octet_string(&child.val[0].ad_data, data);
100     free_AuthorizationData(&child);
101     return ret;
102 }
103
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 *signedpath)
191 {
192     krb5_error_code ret;
193     krb5_data data;
194     krb5_crypto crypto = NULL;
195
196     if (delegated)
197         *delegated = NULL;
198
199     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
200     if (ret == 0) {
201         KRB5SignedPathData spd;
202         KRB5SignedPath sp;
203         AuthorizationData *ad;
204         size_t size;
205
206         ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
207         krb5_data_free(&data);
208         if (ret)
209             return ret;
210
211         spd.encticket = *tkt;
212         /* the KRB5SignedPath is the last entry */
213         ad = spd.encticket.authorization_data;
214         if (--ad->len == 0)
215             spd.encticket.authorization_data = NULL;
216         spd.delegated = sp.delegated;
217
218         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219                            &spd, &size, ret);
220         ad->len++;
221         spd.encticket.authorization_data = ad;
222         if (ret) {
223             free_KRB5SignedPath(&sp);
224             return ret;
225         }
226         if (data.length != size)
227             krb5_abortx(context, "internal asn.1 encoder error");
228
229         {
230             Key *key;
231             ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
232             if (ret == 0)
233                 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234             if (ret) {
235                 free(data.data);
236                 free_KRB5SignedPath(&sp);
237                 return ret;
238             }
239         }
240         ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
241                                    data.data, data.length,
242                                    &sp.cksum);
243         krb5_crypto_destroy(context, crypto);
244         free(data.data);
245         if (ret) {
246             free_KRB5SignedPath(&sp);
247             return ret;
248         }
249
250         if (delegated && sp.delegated) {
251
252             *delegated = malloc(sizeof(*sp.delegated));
253             if (*delegated == NULL) {
254                 free_KRB5SignedPath(&sp);
255                 return ENOMEM;
256             }
257
258             ret = copy_KRB5SignedPathPrincipals(*delegated, sp.delegated);
259             if (ret) {
260                 free_KRB5SignedPath(&sp);
261                 free(*delegated);
262                 *delegated = NULL;
263                 return ret;
264             }
265         }
266         free_KRB5SignedPath(&sp);
267
268         *signedpath = 1;
269     }
270
271     return 0;
272 }
273
274 /*
275  *
276  */
277
278 static krb5_error_code
279 check_PAC(krb5_context context,
280           krb5_kdc_configuration *config,
281           const krb5_principal client_principal,
282           hdb_entry_ex *client,
283           hdb_entry_ex *server,
284           const EncryptionKey *server_key,
285           const EncryptionKey *krbtgt_key,
286           EncTicketPart *tkt,
287           krb5_data *rspac,
288           int *signedpath)
289 {
290     AuthorizationData *ad = tkt->authorization_data;
291     unsigned i, j;
292     krb5_error_code ret;
293
294     if (ad == NULL || ad->len == 0)
295         return 0;
296
297     for (i = 0; i < ad->len; i++) {
298         AuthorizationData child;
299
300         if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
301             continue;
302
303         ret = decode_AuthorizationData(ad->val[i].ad_data.data,
304                                        ad->val[i].ad_data.length,
305                                        &child,
306                                        NULL);
307         if (ret) {
308             krb5_set_error_message(context, ret, "Failed to decode "
309                                    "IF_RELEVANT with %d", ret);
310             return ret;
311         }
312         for (j = 0; j < child.len; j++) {
313
314             if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
315                 krb5_pac pac;
316
317                 /* Found PAC */
318                 ret = krb5_pac_parse(context,
319                                      child.val[j].ad_data.data,
320                                      child.val[j].ad_data.length,
321                                      &pac);
322                 free_AuthorizationData(&child);
323                 if (ret)
324                     return ret;
325
326                 ret = krb5_pac_verify(context, pac, tkt->authtime,
327                                       client_principal,
328                                       krbtgt_key, NULL);
329                 if (ret) {
330                     krb5_pac_free(context, pac);
331                     return ret;
332                 }
333
334                 ret = _kdc_pac_verify(context, client_principal,
335                                       client, server, &pac);
336                 if (ret) {
337                     krb5_pac_free(context, pac);
338                     return ret;
339                 }
340                 *signedpath = 1;
341
342                 ret = _krb5_pac_sign(context, pac, tkt->authtime,
343                                      client_principal,
344                                      server_key, krbtgt_key, rspac);
345
346                 krb5_pac_free(context, pac);
347
348                 return ret;
349             }
350         }
351         free_AuthorizationData(&child);
352     }
353     return 0;
354 }
355
356 /*
357  *
358  */
359
360 static krb5_error_code
361 check_tgs_flags(krb5_context context,
362                 krb5_kdc_configuration *config,
363                 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
364 {
365     KDCOptions f = b->kdc_options;
366         
367     if(f.validate){
368         if(!tgt->flags.invalid || tgt->starttime == NULL){
369             kdc_log(context, config, 0,
370                     "Bad request to validate ticket");
371             return KRB5KDC_ERR_BADOPTION;
372         }
373         if(*tgt->starttime > kdc_time){
374             kdc_log(context, config, 0,
375                     "Early request to validate ticket");
376             return KRB5KRB_AP_ERR_TKT_NYV;
377         }
378         /* XXX  tkt = tgt */
379         et->flags.invalid = 0;
380     }else if(tgt->flags.invalid){
381         kdc_log(context, config, 0,
382                 "Ticket-granting ticket has INVALID flag set");
383         return KRB5KRB_AP_ERR_TKT_INVALID;
384     }
385
386     if(f.forwardable){
387         if(!tgt->flags.forwardable){
388             kdc_log(context, config, 0,
389                     "Bad request for forwardable ticket");
390             return KRB5KDC_ERR_BADOPTION;
391         }
392         et->flags.forwardable = 1;
393     }
394     if(f.forwarded){
395         if(!tgt->flags.forwardable){
396             kdc_log(context, config, 0,
397                     "Request to forward non-forwardable ticket");
398             return KRB5KDC_ERR_BADOPTION;
399         }
400         et->flags.forwarded = 1;
401         et->caddr = b->addresses;
402     }
403     if(tgt->flags.forwarded)
404         et->flags.forwarded = 1;
405         
406     if(f.proxiable){
407         if(!tgt->flags.proxiable){
408             kdc_log(context, config, 0,
409                     "Bad request for proxiable ticket");
410             return KRB5KDC_ERR_BADOPTION;
411         }
412         et->flags.proxiable = 1;
413     }
414     if(f.proxy){
415         if(!tgt->flags.proxiable){
416             kdc_log(context, config, 0,
417                     "Request to proxy non-proxiable ticket");
418             return KRB5KDC_ERR_BADOPTION;
419         }
420         et->flags.proxy = 1;
421         et->caddr = b->addresses;
422     }
423     if(tgt->flags.proxy)
424         et->flags.proxy = 1;
425
426     if(f.allow_postdate){
427         if(!tgt->flags.may_postdate){
428             kdc_log(context, config, 0,
429                     "Bad request for post-datable ticket");
430             return KRB5KDC_ERR_BADOPTION;
431         }
432         et->flags.may_postdate = 1;
433     }
434     if(f.postdated){
435         if(!tgt->flags.may_postdate){
436             kdc_log(context, config, 0,
437                     "Bad request for postdated ticket");
438             return KRB5KDC_ERR_BADOPTION;
439         }
440         if(b->from)
441             *et->starttime = *b->from;
442         et->flags.postdated = 1;
443         et->flags.invalid = 1;
444     }else if(b->from && *b->from > kdc_time + context->max_skew){
445         kdc_log(context, config, 0, "Ticket cannot be postdated");
446         return KRB5KDC_ERR_CANNOT_POSTDATE;
447     }
448
449     if(f.renewable){
450         if(!tgt->flags.renewable){
451             kdc_log(context, config, 0,
452                     "Bad request for renewable ticket");
453             return KRB5KDC_ERR_BADOPTION;
454         }
455         et->flags.renewable = 1;
456         ALLOC(et->renew_till);
457         _kdc_fix_time(&b->rtime);
458         *et->renew_till = *b->rtime;
459     }
460     if(f.renew){
461         time_t old_life;
462         if(!tgt->flags.renewable || tgt->renew_till == NULL){
463             kdc_log(context, config, 0,
464                     "Request to renew non-renewable ticket");
465             return KRB5KDC_ERR_BADOPTION;
466         }
467         old_life = tgt->endtime;
468         if(tgt->starttime)
469             old_life -= *tgt->starttime;
470         else
471             old_life -= tgt->authtime;
472         et->endtime = *et->starttime + old_life;
473         if (et->renew_till != NULL)
474             et->endtime = min(*et->renew_till, et->endtime);
475     }   
476
477 #if 0
478     /* checks for excess flags */
479     if(f.request_anonymous && !config->allow_anonymous){
480         kdc_log(context, config, 0,
481                 "Request for anonymous ticket");
482         return KRB5KDC_ERR_BADOPTION;
483     }
484 #endif
485     return 0;
486 }
487
488 /*
489  *
490  */
491
492 static krb5_error_code
493 check_constrained_delegation(krb5_context context,
494                              krb5_kdc_configuration *config,
495                              hdb_entry_ex *client,
496                              krb5_const_principal server)
497 {
498     const HDB_Ext_Constrained_delegation_acl *acl;
499     krb5_error_code ret;
500     int i;
501
502     ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
503     if (ret) {
504         krb5_clear_error_string(context);
505         return ret;
506     }
507
508     if (acl) {
509         for (i = 0; i < acl->len; i++) {
510             if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
511                 return 0;
512         }
513     }
514     kdc_log(context, config, 0,
515             "Bad request for constrained delegation");
516     return KRB5KDC_ERR_BADOPTION;
517 }
518
519 /*
520  *
521  */
522
523 static krb5_error_code
524 verify_flags (krb5_context context,
525               krb5_kdc_configuration *config,
526               const EncTicketPart *et,
527               const char *pstr)
528 {
529     if(et->endtime < kdc_time){
530         kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
531         return KRB5KRB_AP_ERR_TKT_EXPIRED;
532     }
533     if(et->flags.invalid){
534         kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
535         return KRB5KRB_AP_ERR_TKT_NYV;
536     }
537     return 0;
538 }
539
540 /*
541  *
542  */
543
544 static krb5_error_code
545 fix_transited_encoding(krb5_context context,
546                        krb5_kdc_configuration *config,
547                        krb5_boolean check_policy,
548                        const TransitedEncoding *tr,
549                        EncTicketPart *et,
550                        const char *client_realm,
551                        const char *server_realm,
552                        const char *tgt_realm)
553 {
554     krb5_error_code ret = 0;
555     char **realms, **tmp;
556     unsigned int num_realms;
557     int i;
558
559     switch (tr->tr_type) {
560     case DOMAIN_X500_COMPRESS:
561         break;
562     case 0:
563         /*
564          * Allow empty content of type 0 because that is was Microsoft
565          * generates in their TGT.
566          */
567         if (tr->contents.length == 0)
568             break;
569         kdc_log(context, config, 0,
570                 "Transited type 0 with non empty content");
571         return KRB5KDC_ERR_TRTYPE_NOSUPP;
572     default:
573         kdc_log(context, config, 0,
574                 "Unknown transited type: %u", tr->tr_type);
575         return KRB5KDC_ERR_TRTYPE_NOSUPP;
576     }
577
578     ret = krb5_domain_x500_decode(context,
579                                   tr->contents,
580                                   &realms,
581                                   &num_realms,
582                                   client_realm,
583                                   server_realm);
584     if(ret){
585         krb5_warn(context, ret,
586                   "Decoding transited encoding");
587         return ret;
588     }
589     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
590         /* not us, so add the previous realm to transited set */
591         if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
592             ret = ERANGE;
593             goto free_realms;
594         }
595         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
596         if(tmp == NULL){
597             ret = ENOMEM;
598             goto free_realms;
599         }
600         realms = tmp;
601         realms[num_realms] = strdup(tgt_realm);
602         if(realms[num_realms] == NULL){
603             ret = ENOMEM;
604             goto free_realms;
605         }
606         num_realms++;
607     }
608     if(num_realms == 0) {
609         if(strcmp(client_realm, server_realm))
610             kdc_log(context, config, 0,
611                     "cross-realm %s -> %s", client_realm, server_realm);
612     } else {
613         size_t l = 0;
614         char *rs;
615         for(i = 0; i < num_realms; i++)
616             l += strlen(realms[i]) + 2;
617         rs = malloc(l);
618         if(rs != NULL) {
619             *rs = '\0';
620             for(i = 0; i < num_realms; i++) {
621                 if(i > 0)
622                     strlcat(rs, ", ", l);
623                 strlcat(rs, realms[i], l);
624             }
625             kdc_log(context, config, 0,
626                     "cross-realm %s -> %s via [%s]",
627                     client_realm, server_realm, rs);
628             free(rs);
629         }
630     }
631     if(check_policy) {
632         ret = krb5_check_transited(context, client_realm,
633                                    server_realm,
634                                    realms, num_realms, NULL);
635         if(ret) {
636             krb5_warn(context, ret, "cross-realm %s -> %s",
637                       client_realm, server_realm);
638             goto free_realms;
639         }
640         et->flags.transited_policy_checked = 1;
641     }
642     et->transited.tr_type = DOMAIN_X500_COMPRESS;
643     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
644     if(ret)
645         krb5_warn(context, ret, "Encoding transited encoding");
646   free_realms:
647     for(i = 0; i < num_realms; i++)
648         free(realms[i]);
649     free(realms);
650     return ret;
651 }
652
653
654 static krb5_error_code
655 tgs_make_reply(krb5_context context,
656                krb5_kdc_configuration *config,
657                KDC_REQ_BODY *b,
658                krb5_const_principal tgt_name,
659                const EncTicketPart *tgt,
660                const EncryptionKey *serverkey,
661                const krb5_keyblock *sessionkey,
662                krb5_kvno kvno,
663                AuthorizationData *auth_data,
664                hdb_entry_ex *server,
665                const char *server_name,
666                hdb_entry_ex *client,
667                krb5_principal client_principal,
668                hdb_entry_ex *krbtgt,
669                krb5_enctype krbtgt_etype,
670                KRB5SignedPathPrincipals *spp,
671                const krb5_data *rspac,
672                const METHOD_DATA *enc_pa_data,
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     if (enc_pa_data->len) {
878         rep.padata = calloc(1, sizeof(*rep.padata));
879         if (rep.padata == NULL) {
880             ret = ENOMEM;
881             goto out;
882         }
883         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
884         if (ret)
885             goto out;
886     }
887
888     /* It is somewhat unclear where the etype in the following
889        encryption should come from. What we have is a session
890        key in the passed tgt, and a list of preferred etypes
891        *for the new ticket*. Should we pick the best possible
892        etype, given the keytype in the tgt, or should we look
893        at the etype list here as well?  What if the tgt
894        session key is DES3 and we want a ticket with a (say)
895        CAST session key. Should the DES3 etype be added to the
896        etype list, even if we don't want a session key with
897        DES3? */
898     ret = _kdc_encode_reply(context, config,
899                             &rep, &et, &ek, et.key.keytype,
900                             kvno,
901                             serverkey, 0, &tgt->key, e_text, reply);
902 out:
903     free_TGS_REP(&rep);
904     free_TransitedEncoding(&et.transited);
905     if(et.starttime)
906         free(et.starttime);
907     if(et.renew_till)
908         free(et.renew_till);
909     if(et.authorization_data) {
910         free_AuthorizationData(et.authorization_data);
911         free(et.authorization_data);
912     }
913     free_LastReq(&ek.last_req);
914     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
915     free_EncryptionKey(&et.key);
916     return ret;
917 }
918
919 static krb5_error_code
920 tgs_check_authenticator(krb5_context context,
921                         krb5_kdc_configuration *config,
922                         krb5_auth_context ac,
923                         KDC_REQ_BODY *b,
924                         const char **e_text,
925                         krb5_keyblock *key)
926 {
927     krb5_authenticator auth;
928     size_t len;
929     unsigned char *buf;
930     size_t buf_size;
931     krb5_error_code ret;
932     krb5_crypto crypto;
933
934     krb5_auth_con_getauthenticator(context, ac, &auth);
935     if(auth->cksum == NULL){
936         kdc_log(context, config, 0, "No authenticator in request");
937         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
938         goto out;
939     }
940     /*
941      * according to RFC1510 it doesn't need to be keyed,
942      * but according to the latest draft it needs to.
943      */
944     if (
945 #if 0
946 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
947         ||
948 #endif
949  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
950         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
951                 auth->cksum->cksumtype);
952         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
953         goto out;
954     }
955                 
956     /* XXX should not re-encode this */
957     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
958     if(ret){
959         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
960                 krb5_get_err_text(context, ret));
961         goto out;
962     }
963     if(buf_size != len) {
964         free(buf);
965         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
966         *e_text = "KDC internal error";
967         ret = KRB5KRB_ERR_GENERIC;
968         goto out;
969     }
970     ret = krb5_crypto_init(context, key, 0, &crypto);
971     if (ret) {
972         free(buf);
973         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
974                 krb5_get_err_text(context, ret));
975         goto out;
976     }
977     ret = krb5_verify_checksum(context,
978                                crypto,
979                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
980                                buf,
981                                len,
982                                auth->cksum);
983     free(buf);
984     krb5_crypto_destroy(context, crypto);
985     if(ret){
986         kdc_log(context, config, 0,
987                 "Failed to verify authenticator checksum: %s",
988                 krb5_get_err_text(context, ret));
989     }
990 out:
991     free_Authenticator(auth);
992     free(auth);
993     return ret;
994 }
995
996 /*
997  *
998  */
999
1000 static const char *
1001 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1002 {
1003     const char *new_realm = krb5_config_get_string(context,
1004                                                    NULL,
1005                                                    "capaths",
1006                                                    crealm,
1007                                                    srealm,
1008                                                    NULL);
1009     return new_realm;
1010 }
1011         
1012
1013 static krb5_boolean
1014 need_referral(krb5_context context, krb5_kdc_configuration *config,
1015               const KDCOptions * const options, krb5_principal server,
1016               krb5_realm **realms)
1017 {
1018     const char *name;
1019
1020     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1021         return FALSE;
1022
1023     if (server->name.name_string.len == 1)
1024         name = server->name.name_string.val[0];
1025     if (server->name.name_string.len > 1)
1026         name = server->name.name_string.val[1];
1027     else
1028         return FALSE;
1029
1030     kdc_log(context, config, 0, "Searching referral for %s", name);
1031
1032     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1033 }
1034
1035 static krb5_error_code
1036 tgs_parse_request(krb5_context context,
1037                   krb5_kdc_configuration *config,
1038                   KDC_REQ_BODY *b,
1039                   const PA_DATA *tgs_req,
1040                   hdb_entry_ex **krbtgt,
1041                   krb5_enctype *krbtgt_etype,
1042                   krb5_ticket **ticket,
1043                   const char **e_text,
1044                   const char *from,
1045                   const struct sockaddr *from_addr,
1046                   time_t **csec,
1047                   int **cusec,
1048                   AuthorizationData **auth_data)
1049 {
1050     krb5_ap_req ap_req;
1051     krb5_error_code ret;
1052     krb5_principal princ;
1053     krb5_auth_context ac = NULL;
1054     krb5_flags ap_req_options;
1055     krb5_flags verify_ap_req_flags;
1056     krb5_crypto crypto;
1057     Key *tkey;
1058
1059     *auth_data = NULL;
1060     *csec  = NULL;
1061     *cusec = NULL;
1062
1063     memset(&ap_req, 0, sizeof(ap_req));
1064     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1065     if(ret){
1066         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1067                 krb5_get_err_text(context, ret));
1068         goto out;
1069     }
1070
1071     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1072         /* XXX check for ticket.sname == req.sname */
1073         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1074         ret = KRB5KDC_ERR_POLICY; /* ? */
1075         goto out;
1076     }
1077
1078     _krb5_principalname2krb5_principal(context,
1079                                        &princ,
1080                                        ap_req.ticket.sname,
1081                                        ap_req.ticket.realm);
1082
1083     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1084
1085     if(ret) {
1086         char *p;
1087         ret = krb5_unparse_name(context, princ, &p);
1088         if (ret != 0)
1089             p = "<unparse_name failed>";
1090         krb5_free_principal(context, princ);
1091         kdc_log(context, config, 0,
1092                 "Ticket-granting ticket not found in database: %s: %s",
1093                 p, krb5_get_err_text(context, ret));
1094         if (ret == 0)
1095             free(p);
1096         ret = KRB5KRB_AP_ERR_NOT_US;
1097         goto out;
1098     }
1099
1100     if(ap_req.ticket.enc_part.kvno &&
1101        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1102         char *p;
1103
1104         ret = krb5_unparse_name (context, princ, &p);
1105         krb5_free_principal(context, princ);
1106         if (ret != 0)
1107             p = "<unparse_name failed>";
1108         kdc_log(context, config, 0,
1109                 "Ticket kvno = %d, DB kvno = %d (%s)",
1110                 *ap_req.ticket.enc_part.kvno,
1111                 (*krbtgt)->entry.kvno,
1112                 p);
1113         if (ret == 0)
1114             free (p);
1115         ret = KRB5KRB_AP_ERR_BADKEYVER;
1116         goto out;
1117     }
1118
1119     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1120
1121     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1122                           ap_req.ticket.enc_part.etype, &tkey);
1123     if(ret){
1124         char *str = NULL, *p = NULL;
1125
1126         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1127         krb5_unparse_name(context, princ, &p);
1128         kdc_log(context, config, 0,
1129                 "No server key with enctype %s found for %s",
1130                 str ? str : "<unknown enctype>",
1131                 p ? p : "<unparse_name failed>");
1132         free(str);
1133         free(p);
1134         ret = KRB5KRB_AP_ERR_BADKEYVER;
1135         goto out;
1136     }
1137
1138     if (b->kdc_options.validate)
1139         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1140     else
1141         verify_ap_req_flags = 0;
1142
1143     ret = krb5_verify_ap_req2(context,
1144                               &ac,
1145                               &ap_req,
1146                               princ,
1147                               &tkey->key,
1148                               verify_ap_req_flags,
1149                               &ap_req_options,
1150                               ticket,
1151                               KRB5_KU_TGS_REQ_AUTH);
1152                         
1153     krb5_free_principal(context, princ);
1154     if(ret) {
1155         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1156                 krb5_get_err_text(context, ret));
1157         goto out;
1158     }
1159
1160     {
1161         krb5_authenticator auth;
1162
1163         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1164         if (ret == 0) {
1165             *csec   = malloc(sizeof(**csec));
1166             if (*csec == NULL) {
1167                 krb5_free_authenticator(context, &auth);
1168                 kdc_log(context, config, 0, "malloc failed");
1169                 goto out;
1170             }
1171             **csec  = auth->ctime;
1172             *cusec  = malloc(sizeof(**cusec));
1173             if (*cusec == NULL) {
1174                 krb5_free_authenticator(context, &auth);
1175                 kdc_log(context, config, 0, "malloc failed");
1176                 goto out;
1177             }
1178             **cusec  = auth->cusec;
1179             krb5_free_authenticator(context, &auth);
1180         }
1181     }
1182
1183     ret = tgs_check_authenticator(context, config,
1184                                   ac, b, e_text, &(*ticket)->ticket.key);
1185     if (ret) {
1186         krb5_auth_con_free(context, ac);
1187         goto out;
1188     }
1189
1190     if (b->enc_authorization_data) {
1191         unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1192         krb5_keyblock *subkey;
1193         krb5_data ad;
1194
1195         ret = krb5_auth_con_getremotesubkey(context,
1196                                             ac,
1197                                             &subkey);
1198         if(ret){
1199             krb5_auth_con_free(context, ac);
1200             kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1201                     krb5_get_err_text(context, ret));
1202             goto out;
1203         }
1204         if(subkey == NULL){
1205             usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1206             ret = krb5_auth_con_getkey(context, ac, &subkey);
1207             if(ret) {
1208                 krb5_auth_con_free(context, ac);
1209                 kdc_log(context, config, 0, "Failed to get session key: %s",
1210                         krb5_get_err_text(context, ret));
1211                 goto out;
1212             }
1213         }
1214         if(subkey == NULL){
1215             krb5_auth_con_free(context, ac);
1216             kdc_log(context, config, 0,
1217                     "Failed to get key for enc-authorization-data");
1218             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1219             goto out;
1220         }
1221         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1222         if (ret) {
1223             krb5_auth_con_free(context, ac);
1224             kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1225                     krb5_get_err_text(context, ret));
1226             goto out;
1227         }
1228         ret = krb5_decrypt_EncryptedData (context,
1229                                           crypto,
1230                                           usage,
1231                                           b->enc_authorization_data,
1232                                           &ad);
1233         krb5_crypto_destroy(context, crypto);
1234         if(ret){
1235             krb5_auth_con_free(context, ac);
1236             kdc_log(context, config, 0,
1237                     "Failed to decrypt enc-authorization-data");
1238             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1239             goto out;
1240         }
1241         krb5_free_keyblock(context, subkey);
1242         ALLOC(*auth_data);
1243         if (*auth_data == NULL) {
1244             krb5_auth_con_free(context, ac);
1245             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1246             goto out;
1247         }
1248         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1249         if(ret){
1250             krb5_auth_con_free(context, ac);
1251             free(*auth_data);
1252             *auth_data = NULL;
1253             kdc_log(context, config, 0, "Failed to decode authorization data");
1254             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1255             goto out;
1256         }
1257     }
1258
1259     krb5_auth_con_free(context, ac);
1260
1261 out:
1262     free_AP_REQ(&ap_req);
1263
1264     return ret;
1265 }
1266
1267 static krb5_error_code
1268 build_server_referral(krb5_context context,
1269                       krb5_kdc_configuration *config,
1270                       krb5_crypto session,
1271                       krb5_const_realm referred_realm,
1272                       const PrincipalName *true_principal_name,
1273                       const PrincipalName *requested_principal,
1274                       krb5_data *outdata)
1275 {               
1276     PA_ServerReferralData ref;
1277     krb5_error_code ret;
1278     EncryptedData ed;
1279     krb5_data data;
1280     size_t size;
1281
1282     memset(&ref, 0, sizeof(ref));
1283
1284     if (referred_realm) {
1285         ref.referred_realm = malloc(sizeof(ref.referred_realm));
1286         if (ref.referred_realm == NULL)
1287             goto eout;
1288         *ref.referred_realm = strdup(referred_realm);
1289         if (*ref.referred_realm == NULL)
1290             goto eout;
1291     }
1292     if (true_principal_name) {
1293         ref.true_principal_name =
1294             malloc(sizeof(ref.true_principal_name));
1295         if (ref.true_principal_name == NULL)
1296             goto eout;
1297         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1298         if (ret)
1299             goto eout;
1300     }
1301     if (requested_principal) {
1302         ref.requested_principal_name =
1303             malloc(sizeof(ref.requested_principal_name));
1304         if (ref.requested_principal_name == NULL)
1305             goto eout;
1306         ret = copy_PrincipalName(requested_principal,
1307                                  ref.requested_principal_name);
1308         if (ret)
1309             goto eout;
1310     }
1311
1312     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1313                        data.data, data.length,
1314                        &ref, &size, ret);
1315     free_PA_ServerReferralData(&ref);
1316     if (ret)
1317         return ret;
1318     if (data.length != size)
1319         krb5_abortx(context, "internal asn.1 encoder error");
1320
1321     ret = krb5_encrypt_EncryptedData(context, session,
1322                                      KRB5_KU_PA_SERVER_REFERRAL,
1323                                      data.data, data.length,
1324                                      0 /* kvno */, &ed);
1325     free(data.data);
1326     if (ret)
1327         return ret;
1328
1329     ASN1_MALLOC_ENCODE(EncryptedData,
1330                        outdata->data, outdata->length,
1331                        &ed, &size, ret);
1332     free_EncryptedData(&ed);
1333     if (ret)
1334         return ret;
1335     if (outdata->length != size)
1336         krb5_abortx(context, "internal asn.1 encoder error");
1337
1338     return 0;
1339 eout:
1340     free_PA_ServerReferralData(&ref);
1341     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1342     return ENOMEM;
1343 }
1344
1345 static krb5_error_code
1346 tgs_build_reply(krb5_context context,
1347                 krb5_kdc_configuration *config,
1348                 KDC_REQ *req,
1349                 KDC_REQ_BODY *b,
1350                 hdb_entry_ex *krbtgt,
1351                 krb5_enctype krbtgt_etype,
1352                 krb5_ticket *ticket,
1353                 krb5_data *reply,
1354                 const char *from,
1355                 const char **e_text,
1356                 AuthorizationData **auth_data,
1357                 const struct sockaddr *from_addr,
1358                 int datagram_reply)
1359 {
1360     krb5_error_code ret;
1361     krb5_principal cp = NULL, sp = NULL;
1362     krb5_principal client_principal = NULL;
1363     char *spn = NULL, *cpn = NULL;
1364     hdb_entry_ex *server = NULL, *client = NULL;
1365     krb5_realm ref_realm = NULL;
1366     EncTicketPart *tgt = &ticket->ticket;
1367     KRB5SignedPathPrincipals *spp = NULL;
1368     const EncryptionKey *ekey;
1369     krb5_keyblock sessionkey;
1370     krb5_kvno kvno;
1371     krb5_data rspac;
1372     int cross_realm = 0;
1373
1374     METHOD_DATA enc_pa_data;
1375
1376     PrincipalName *s;
1377     Realm r;
1378     int nloop = 0;
1379     EncTicketPart adtkt;
1380     char opt_str[128];
1381     int signedpath = 0;
1382
1383     memset(&sessionkey, 0, sizeof(sessionkey));
1384     memset(&adtkt, 0, sizeof(adtkt));
1385     krb5_data_zero(&rspac);
1386     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1387
1388     s = b->sname;
1389     r = b->realm;
1390
1391     if(b->kdc_options.enc_tkt_in_skey){
1392         Ticket *t;
1393         hdb_entry_ex *uu;
1394         krb5_principal p;
1395         Key *uukey;
1396         
1397         if(b->additional_tickets == NULL ||
1398            b->additional_tickets->len == 0){
1399             ret = KRB5KDC_ERR_BADOPTION; /* ? */
1400             kdc_log(context, config, 0,
1401                     "No second ticket present in request");
1402             goto out;
1403         }
1404         t = &b->additional_tickets->val[0];
1405         if(!get_krbtgt_realm(&t->sname)){
1406             kdc_log(context, config, 0,
1407                     "Additional ticket is not a ticket-granting ticket");
1408             ret = KRB5KDC_ERR_POLICY;
1409             goto out;
1410         }
1411         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1412         ret = _kdc_db_fetch(context, config, p,
1413                             HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1414                             NULL, &uu);
1415         krb5_free_principal(context, p);
1416         if(ret){
1417             if (ret == HDB_ERR_NOENTRY)
1418                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1419             goto out;
1420         }
1421         ret = hdb_enctype2key(context, &uu->entry,
1422                               t->enc_part.etype, &uukey);
1423         if(ret){
1424             _kdc_free_ent(context, uu);
1425             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1426             goto out;
1427         }
1428         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1429         _kdc_free_ent(context, uu);
1430         if(ret)
1431             goto out;
1432
1433         ret = verify_flags(context, config, &adtkt, spn);
1434         if (ret)
1435             goto out;
1436
1437         s = &adtkt.cname;
1438         r = adtkt.crealm;
1439     }
1440
1441     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1442     ret = krb5_unparse_name(context, sp, &spn); 
1443     if (ret)
1444         goto out;
1445     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1446     ret = krb5_unparse_name(context, cp, &cpn);
1447     if (ret)
1448         goto out;
1449     unparse_flags (KDCOptions2int(b->kdc_options),
1450                    asn1_KDCOptions_units(),
1451                    opt_str, sizeof(opt_str));
1452     if(*opt_str)
1453         kdc_log(context, config, 0,
1454                 "TGS-REQ %s from %s for %s [%s]",
1455                 cpn, from, spn, opt_str);
1456     else
1457         kdc_log(context, config, 0,
1458                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1459
1460     /*
1461      * Fetch server
1462      */
1463
1464 server_lookup:
1465     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER, NULL, &server);
1466
1467     if(ret){
1468         const char *new_rlm;
1469         Realm req_rlm;
1470         krb5_realm *realms;
1471
1472         if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1473             if(nloop++ < 2) {
1474                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1475                 if(new_rlm) {
1476                     kdc_log(context, config, 5, "krbtgt for realm %s "
1477                             "not found, trying %s",
1478                             req_rlm, new_rlm);
1479                     krb5_free_principal(context, sp);
1480                     free(spn);
1481                     krb5_make_principal(context, &sp, r,
1482                                         KRB5_TGS_NAME, new_rlm, NULL);
1483                     ret = krb5_unparse_name(context, sp, &spn); 
1484                     if (ret)
1485                         goto out;
1486
1487                     if (ref_realm)
1488                         free(ref_realm);
1489                     ref_realm = strdup(new_rlm);
1490                     goto server_lookup;
1491                 }
1492             }
1493         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1494             if (strcmp(realms[0], sp->realm) != 0) {
1495                 kdc_log(context, config, 5,
1496                         "Returning a referral to realm %s for "
1497                         "server %s that was not found",
1498                         realms[0], spn);
1499                 krb5_free_principal(context, sp);
1500                 free(spn);
1501                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1502                                     realms[0], NULL);
1503                 ret = krb5_unparse_name(context, sp, &spn);
1504                 if (ret)
1505                     goto out;
1506
1507                 if (ref_realm)
1508                     free(ref_realm);
1509                 ref_realm = strdup(realms[0]);
1510
1511                 krb5_free_host_realm(context, realms);
1512                 goto server_lookup;
1513             }
1514             krb5_free_host_realm(context, realms);
1515         }
1516         kdc_log(context, config, 0,
1517                 "Server not found in database: %s: %s", spn,
1518                 krb5_get_err_text(context, ret));
1519         if (ret == HDB_ERR_NOENTRY)
1520             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1521         goto out;
1522     }
1523
1524     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT, NULL, &client);
1525     if(ret) {
1526         const char *krbtgt_realm;
1527
1528         /*
1529          * If the client belongs to the same realm as our krbtgt, it
1530          * should exist in the local database.
1531          *
1532          */
1533
1534         krbtgt_realm =
1535             krb5_principal_get_comp_string(context,
1536                                            krbtgt->entry.principal, 1);
1537
1538         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1539             if (ret == HDB_ERR_NOENTRY)
1540                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1541             kdc_log(context, config, 1, "Client no longer in database: %s",
1542                     cpn);
1543             goto out;
1544         }
1545         
1546         kdc_log(context, config, 1, "Client not found in database: %s: %s",
1547                 cpn, krb5_get_err_text(context, ret));
1548
1549         cross_realm = 1;
1550     }
1551
1552     /*
1553      * Select enctype, return key and kvno.
1554      */
1555
1556     {
1557         krb5_enctype etype;
1558
1559         if(b->kdc_options.enc_tkt_in_skey) {
1560             int i;
1561             ekey = &adtkt.key;
1562             for(i = 0; i < b->etype.len; i++)
1563                 if (b->etype.val[i] == adtkt.key.keytype)
1564                     break;
1565             if(i == b->etype.len) {
1566                 kdc_log(context, config, 0,
1567                         "Addition ticket have not matching etypes", spp);
1568                 krb5_clear_error_string(context);
1569                 return KRB5KDC_ERR_ETYPE_NOSUPP;
1570             }
1571             etype = b->etype.val[i];
1572             kvno = 0;
1573         } else {
1574             Key *skey;
1575         
1576             ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1577                                   &skey, &etype);
1578             if(ret) {
1579                 kdc_log(context, config, 0,
1580                         "Server (%s) has no support for etypes", spn);
1581                 return ret;
1582             }
1583             ekey = &skey->key;
1584             kvno = server->entry.kvno;
1585         }
1586         
1587         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1588         if (ret)
1589             goto out;
1590     }
1591
1592     /*
1593      * Validate authoriation data
1594      */
1595
1596     /*
1597      * Check that service is in the same realm as the krbtgt. If it's
1598      * not the same, it's someone that is using a uni-directional trust
1599      * backward.
1600      */
1601
1602     if (strcmp(krb5_principal_get_realm(context, sp),
1603                krb5_principal_get_comp_string(context,
1604                                               krbtgt->entry.principal,
1605                                               1)) != 0) {
1606         char *tpn;
1607         ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1608         kdc_log(context, config, 0,
1609                 "Request with wrong krbtgt: %s",
1610                 (ret == 0) ? tpn : "<unknown>");
1611         if(ret == 0)
1612             free(tpn);
1613         ret = KRB5KRB_AP_ERR_NOT_US;
1614         goto out;
1615     }
1616
1617     /* check PAC if not cross realm and if there is one */
1618     if (!cross_realm) {
1619         Key *tkey;
1620
1621         ret = hdb_enctype2key(context, &krbtgt->entry,
1622                               krbtgt_etype, &tkey);
1623         if(ret) {
1624             kdc_log(context, config, 0,
1625                     "Failed to find key for krbtgt PAC check");
1626             goto out;
1627         }
1628
1629         ret = check_PAC(context, config, cp,
1630                         client, server, ekey, &tkey->key,
1631                         tgt, &rspac, &signedpath);
1632         if (ret) {
1633             kdc_log(context, config, 0,
1634                     "Verify PAC failed for %s (%s) from %s with %s",
1635                     spn, cpn, from, krb5_get_err_text(context, ret));
1636             goto out;
1637         }
1638     }
1639
1640     /* also check the krbtgt for signature */
1641     ret = check_KRB5SignedPath(context,
1642                                config,
1643                                krbtgt,
1644                                tgt,
1645                                &spp,
1646                                &signedpath);
1647     if (ret) {
1648         kdc_log(context, config, 0,
1649                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1650                 spn, cpn, from, krb5_get_err_text(context, ret));
1651         goto out;
1652     }
1653
1654     /*
1655      * Process request
1656      */
1657
1658     client_principal = cp;
1659
1660     if (client) {
1661         const PA_DATA *sdata;
1662         int i = 0;
1663
1664         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
1665         if (sdata) {
1666             krb5_crypto crypto;
1667             krb5_data datack;
1668             PA_S4U2Self self;
1669             char *selfcpn = NULL;
1670             const char *str;
1671
1672             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1673                                      sdata->padata_value.length,
1674                                      &self, NULL);
1675             if (ret) {
1676                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1677                 goto out;
1678             }
1679
1680             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1681             if (ret)
1682                 goto out;
1683
1684             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1685             if (ret) {
1686                 free_PA_S4U2Self(&self);
1687                 krb5_data_free(&datack);
1688                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1689                         krb5_get_err_text(context, ret));
1690                 goto out;
1691             }
1692
1693             ret = krb5_verify_checksum(context,
1694                                        crypto,
1695                                        KRB5_KU_OTHER_CKSUM,
1696                                        datack.data,
1697                                        datack.length,
1698                                        &self.cksum);
1699             krb5_data_free(&datack);
1700             krb5_crypto_destroy(context, crypto);
1701             if (ret) {
1702                 free_PA_S4U2Self(&self);
1703                 kdc_log(context, config, 0,
1704                         "krb5_verify_checksum failed for S4U2Self: %s",
1705                         krb5_get_err_text(context, ret));
1706                 goto out;
1707             }
1708
1709             ret = _krb5_principalname2krb5_principal(context,
1710                                                      &client_principal,
1711                                                      self.name,
1712                                                      self.realm);
1713             free_PA_S4U2Self(&self);
1714             if (ret)
1715                 goto out;
1716
1717             ret = krb5_unparse_name(context, client_principal, &selfcpn);       
1718             if (ret)
1719                 goto out;
1720
1721             /*
1722              * Check that service doing the impersonating is
1723              * requesting a ticket to it-self.
1724              */
1725             if (krb5_principal_compare(context, cp, sp) != TRUE) {
1726                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1727                         "to impersonate some other user "
1728                         "(tried for user %s to service %s)",
1729                         cpn, selfcpn, spn);
1730                 free(selfcpn);
1731                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1732                 goto out;
1733             }
1734
1735             /*
1736              * If the service isn't trusted for authentication to
1737              * delegation, remove the forward flag.
1738              */
1739
1740             if (client->entry.flags.trusted_for_delegation) {
1741                 str = "[forwardable]";
1742             } else {
1743                 b->kdc_options.forwardable = 0;
1744                 str = "";
1745             }
1746             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1747                     "service %s %s", cpn, selfcpn, spn, str);
1748             free(selfcpn);
1749         }
1750     }
1751
1752     /*
1753      * Constrained delegation
1754      */
1755
1756     if (client != NULL
1757         && b->additional_tickets != NULL
1758         && b->additional_tickets->len != 0
1759         && b->kdc_options.enc_tkt_in_skey == 0)
1760     {
1761         int ad_signedpath = 0;
1762         Key *clientkey;
1763         Ticket *t;
1764         char *str;
1765
1766         /*
1767          * Require that the KDC have issued the service's krbtgt (not
1768          * self-issued ticket with kimpersonate(1).
1769          */
1770         if (!signedpath) {
1771             ret = KRB5KDC_ERR_BADOPTION;
1772             kdc_log(context, config, 0,
1773                     "Constrained delegation done on service ticket %s/%s",
1774                     cpn, spn);
1775             goto out;
1776         }
1777
1778         t = &b->additional_tickets->val[0];
1779
1780         ret = hdb_enctype2key(context, &client->entry,
1781                               t->enc_part.etype, &clientkey);
1782         if(ret){
1783             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1784             goto out;
1785         }
1786
1787         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1788         if (ret) {
1789             kdc_log(context, config, 0,
1790                     "failed to decrypt ticket for "
1791                     "constrained delegation from %s to %s ", spn, cpn);
1792             goto out;
1793         }
1794
1795         /* check that ticket is valid */
1796         if (adtkt.flags.forwardable == 0) {
1797             kdc_log(context, config, 0,
1798                     "Missing forwardable flag on ticket for "
1799                     "constrained delegation from %s to %s ", spn, cpn);
1800             ret = KRB5KDC_ERR_BADOPTION;
1801             goto out;
1802         }
1803
1804         ret = check_constrained_delegation(context, config, client, sp);
1805         if (ret) {
1806             kdc_log(context, config, 0,
1807                     "constrained delegation from %s to %s not allowed",
1808                     spn, cpn);
1809             goto out;
1810         }
1811
1812         ret = _krb5_principalname2krb5_principal(context,
1813                                                  &client_principal,
1814                                                  adtkt.cname,
1815                                                  adtkt.crealm);
1816         if (ret)
1817             goto out;
1818
1819         ret = krb5_unparse_name(context, client_principal, &str);
1820         if (ret)
1821             goto out;
1822
1823         ret = verify_flags(context, config, &adtkt, str);
1824         if (ret) {
1825             free(str);
1826             goto out;
1827         }
1828
1829         /*
1830          * Check that the KDC issued the user's ticket.
1831          */
1832         ret = check_KRB5SignedPath(context,
1833                                    config,
1834                                    krbtgt,
1835                                    &adtkt,
1836                                    NULL,
1837                                    &ad_signedpath);
1838         if (ret == 0 && !ad_signedpath)
1839             ret = KRB5KDC_ERR_BADOPTION;
1840         if (ret) {
1841             kdc_log(context, config, 0,
1842                     "KRB5SignedPath check from service %s failed "
1843                     "for delegation to %s for client %s "
1844                     "from %s failed with %s",
1845                     spn, str, cpn, from, krb5_get_err_text(context, ret));
1846             free(str);
1847             goto out;
1848         }
1849
1850         kdc_log(context, config, 0, "constrained delegation for %s "
1851                 "from %s to %s", str, cpn, spn);
1852         free(str);
1853     }
1854
1855     /*
1856      * Check flags
1857      */
1858
1859     ret = _kdc_check_flags(context, config,
1860                            client, cpn,
1861                            server, spn,
1862                            FALSE);
1863     if(ret)
1864         goto out;
1865
1866     if((b->kdc_options.validate || b->kdc_options.renew) &&
1867        !krb5_principal_compare(context,
1868                                krbtgt->entry.principal,
1869                                server->entry.principal)){
1870         kdc_log(context, config, 0, "Inconsistent request.");
1871         ret = KRB5KDC_ERR_SERVER_NOMATCH;
1872         goto out;
1873     }
1874
1875     /* check for valid set of addresses */
1876     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1877         ret = KRB5KRB_AP_ERR_BADADDR;
1878         kdc_log(context, config, 0, "Request from wrong address");
1879         goto out;
1880     }
1881         
1882     /*
1883      * If this is an referral, add server referral data to the
1884      * auth_data reply .
1885      */
1886     if (ref_realm) {
1887         PA_DATA pa;
1888         krb5_crypto crypto;
1889
1890         kdc_log(context, config, 0,
1891                 "Adding server referral to %s", ref_realm);
1892
1893         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1894         if (ret)
1895             goto out;
1896
1897         ret = build_server_referral(context, config, crypto, ref_realm,
1898                                     NULL, s, &pa.padata_value);
1899         krb5_crypto_destroy(context, crypto);
1900         if (ret) {
1901             kdc_log(context, config, 0,
1902                     "Failed building server referral");
1903             goto out;
1904         }
1905         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1906
1907         ret = add_METHOD_DATA(&enc_pa_data, &pa);
1908         krb5_data_free(&pa.padata_value);
1909         if (ret) {
1910             kdc_log(context, config, 0,
1911                     "Add server referral METHOD-DATA failed");
1912             goto out;
1913         }
1914     }
1915
1916     /*
1917      *
1918      */
1919
1920     ret = tgs_make_reply(context,
1921                          config,
1922                          b,
1923                          client_principal,
1924                          tgt,
1925                          ekey,
1926                          &sessionkey,
1927                          kvno,
1928                          *auth_data,
1929                          server,
1930                          spn,
1931                          client,
1932                          cp,
1933                          krbtgt,
1934                          krbtgt_etype,
1935                          spp,
1936                          &rspac,
1937                          &enc_pa_data,
1938                          e_text,
1939                          reply);
1940         
1941 out:
1942     free(spn);
1943     free(cpn);
1944         
1945     krb5_data_free(&rspac);
1946     krb5_free_keyblock_contents(context, &sessionkey);
1947     if(server)
1948         _kdc_free_ent(context, server);
1949     if(client)
1950         _kdc_free_ent(context, client);
1951
1952     if (client_principal && client_principal != cp)
1953         krb5_free_principal(context, client_principal);
1954     if (cp)
1955         krb5_free_principal(context, cp);
1956     if (sp)
1957         krb5_free_principal(context, sp);
1958     if (ref_realm)
1959         free(ref_realm);
1960     free_METHOD_DATA(&enc_pa_data);
1961
1962     free_EncTicketPart(&adtkt);
1963
1964     return ret;
1965 }
1966
1967 /*
1968  *
1969  */
1970
1971 krb5_error_code
1972 _kdc_tgs_rep(krb5_context context,
1973              krb5_kdc_configuration *config,
1974              KDC_REQ *req,
1975              krb5_data *data,
1976              const char *from,
1977              struct sockaddr *from_addr,
1978              int datagram_reply)
1979 {
1980     AuthorizationData *auth_data = NULL;
1981     krb5_error_code ret;
1982     int i = 0;
1983     const PA_DATA *tgs_req;
1984
1985     hdb_entry_ex *krbtgt = NULL;
1986     krb5_ticket *ticket = NULL;
1987     const char *e_text = NULL;
1988     krb5_enctype krbtgt_etype = ETYPE_NULL;
1989
1990     time_t *csec = NULL;
1991     int *cusec = NULL;
1992
1993     if(req->padata == NULL){
1994         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
1995         kdc_log(context, config, 0,
1996                 "TGS-REQ from %s without PA-DATA", from);
1997         goto out;
1998     }
1999
2000     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2001
2002     if(tgs_req == NULL){
2003         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2004         
2005         kdc_log(context, config, 0,
2006                 "TGS-REQ from %s without PA-TGS-REQ", from);
2007         goto out;
2008     }
2009     ret = tgs_parse_request(context, config,
2010                             &req->req_body, tgs_req,
2011                             &krbtgt,
2012                             &krbtgt_etype,
2013                             &ticket,
2014                             &e_text,
2015                             from, from_addr,
2016                             &csec, &cusec,
2017                             &auth_data);
2018     if (ret) {
2019         kdc_log(context, config, 0,
2020                 "Failed parsing TGS-REQ from %s", from);
2021         goto out;
2022     }
2023
2024     ret = tgs_build_reply(context,
2025                           config,
2026                           req,
2027                           &req->req_body,
2028                           krbtgt,
2029                           krbtgt_etype,
2030                           ticket,
2031                           data,
2032                           from,
2033                           &e_text,
2034                           &auth_data,
2035                           from_addr,
2036                           datagram_reply);
2037     if (ret) {
2038         kdc_log(context, config, 0,
2039                 "Failed building TGS-REP to %s", from);
2040         goto out;
2041     }
2042
2043     /* */
2044     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2045         krb5_data_free(data);
2046         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2047         e_text = "Reply packet too large";
2048     }
2049
2050 out:
2051     if(ret && data->data == NULL){
2052         krb5_mk_error(context,
2053                       ret,
2054                       NULL,
2055                       NULL,
2056                       NULL,
2057                       NULL,
2058                       csec,
2059                       cusec,
2060                       data);
2061     }
2062     free(csec);
2063     free(cusec);
2064     if (ticket)
2065         krb5_free_ticket(context, ticket);
2066     if(krbtgt)
2067         _kdc_free_ent(context, krbtgt);
2068
2069     if (auth_data) {
2070         free_AuthorizationData(auth_data);
2071         free(auth_data);
2072     }
2073
2074     return 0;
2075 }