4cf93e5a54be2dc0691677b3d8794d3fb0cbe419
[amitay/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$");
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_message(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                krb5_principal server_principal,
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 METHOD_DATA *enc_pa_data,
674                const char **e_text,
675                krb5_data *reply)
676 {
677     KDC_REP rep;
678     EncKDCRepPart ek;
679     EncTicketPart et;
680     KDCOptions f = b->kdc_options;
681     krb5_error_code ret;
682     int is_weak = 0;
683
684     memset(&rep, 0, sizeof(rep));
685     memset(&et, 0, sizeof(et));
686     memset(&ek, 0, sizeof(ek));
687
688     rep.pvno = 5;
689     rep.msg_type = krb_tgs_rep;
690
691     et.authtime = tgt->authtime;
692     _kdc_fix_time(&b->till);
693     et.endtime = min(tgt->endtime, *b->till);
694     ALLOC(et.starttime);
695     *et.starttime = kdc_time;
696
697     ret = check_tgs_flags(context, config, b, tgt, &et);
698     if(ret)
699         goto out;
700
701     /* We should check the transited encoding if:
702        1) the request doesn't ask not to be checked
703        2) globally enforcing a check
704        3) principal requires checking
705        4) we allow non-check per-principal, but principal isn't marked as allowing this
706        5) we don't globally allow this
707     */
708
709 #define GLOBAL_FORCE_TRANSITED_CHECK            \
710     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
711 #define GLOBAL_ALLOW_PER_PRINCIPAL                      \
712     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
713 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                    \
714     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
715
716 /* these will consult the database in future release */
717 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
718 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
719
720     ret = fix_transited_encoding(context, config,
721                                  !f.disable_transited_check ||
722                                  GLOBAL_FORCE_TRANSITED_CHECK ||
723                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
724                                  !((GLOBAL_ALLOW_PER_PRINCIPAL &&
725                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
726                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
727                                  &tgt->transited, &et,
728                                  *krb5_princ_realm(context, client_principal),
729                                  *krb5_princ_realm(context, server->entry.principal),
730                                  *krb5_princ_realm(context, krbtgt->entry.principal));
731     if(ret)
732         goto out;
733
734     copy_Realm(krb5_princ_realm(context, server_principal),
735                &rep.ticket.realm);
736     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
737     copy_Realm(&tgt_name->realm, &rep.crealm);
738 /*
739     if (f.request_anonymous)
740         _kdc_make_anonymous_principalname (&rep.cname);
741     else */
742
743     copy_PrincipalName(&tgt_name->name, &rep.cname);
744     rep.ticket.tkt_vno = 5;
745
746     ek.caddr = et.caddr;
747     if(et.caddr == NULL)
748         et.caddr = tgt->caddr;
749
750     {
751         time_t life;
752         life = et.endtime - *et.starttime;
753         if(client && client->entry.max_life)
754             life = min(life, *client->entry.max_life);
755         if(server->entry.max_life)
756             life = min(life, *server->entry.max_life);
757         et.endtime = *et.starttime + life;
758     }
759     if(f.renewable_ok && tgt->flags.renewable &&
760        et.renew_till == NULL && et.endtime < *b->till){
761         et.flags.renewable = 1;
762         ALLOC(et.renew_till);
763         *et.renew_till = *b->till;
764     }
765     if(et.renew_till){
766         time_t renew;
767         renew = *et.renew_till - et.authtime;
768         if(client && client->entry.max_renew)
769             renew = min(renew, *client->entry.max_renew);
770         if(server->entry.max_renew)
771             renew = min(renew, *server->entry.max_renew);
772         *et.renew_till = et.authtime + renew;
773     }
774         
775     if(et.renew_till){
776         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
777         *et.starttime = min(*et.starttime, *et.renew_till);
778         et.endtime = min(et.endtime, *et.renew_till);
779     }
780
781     *et.starttime = min(*et.starttime, et.endtime);
782
783     if(*et.starttime == et.endtime){
784         ret = KRB5KDC_ERR_NEVER_VALID;
785         goto out;
786     }
787     if(et.renew_till && et.endtime == *et.renew_till){
788         free(et.renew_till);
789         et.renew_till = NULL;
790         et.flags.renewable = 0;
791     }
792
793     et.flags.pre_authent = tgt->flags.pre_authent;
794     et.flags.hw_authent  = tgt->flags.hw_authent;
795     et.flags.anonymous   = tgt->flags.anonymous;
796     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
797         
798     if (auth_data) {
799         /* XXX Check enc-authorization-data */
800         et.authorization_data = calloc(1, sizeof(*et.authorization_data));
801         if (et.authorization_data == NULL) {
802             ret = ENOMEM;
803             goto out;
804         }
805         ret = copy_AuthorizationData(auth_data, et.authorization_data);
806         if (ret)
807             goto out;
808
809         /* Filter out type KRB5SignedPath */
810         ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
811         if (ret == 0) {
812             if (et.authorization_data->len == 1) {
813                 free_AuthorizationData(et.authorization_data);
814                 free(et.authorization_data);
815                 et.authorization_data = NULL;
816             } else {
817                 AuthorizationData *ad = et.authorization_data;
818                 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
819                 ad->len--;
820             }
821         }
822     }
823
824     if(rspac->length) {
825         /*
826          * No not need to filter out the any PAC from the
827          * auth_data since it's signed by the KDC.
828          */
829         ret = _kdc_tkt_add_if_relevant_ad(context, &et,
830                                           KRB5_AUTHDATA_WIN2K_PAC,
831                                           rspac);
832         if (ret)
833             goto out;
834     }
835
836     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
837     if (ret)
838         goto out;
839     et.crealm = tgt->crealm;
840     et.cname = tgt_name->name;
841         
842     ek.key = et.key;
843     /* MIT must have at least one last_req */
844     ek.last_req.len = 1;
845     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
846     if (ek.last_req.val == NULL) {
847         ret = ENOMEM;
848         goto out;
849     }
850     ek.nonce = b->nonce;
851     ek.flags = et.flags;
852     ek.authtime = et.authtime;
853     ek.starttime = et.starttime;
854     ek.endtime = et.endtime;
855     ek.renew_till = et.renew_till;
856     ek.srealm = rep.ticket.realm;
857     ek.sname = rep.ticket.sname;
858
859     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
860                        et.endtime, et.renew_till);
861
862     /* Don't sign cross realm tickets, they can't be checked anyway */
863     {
864         char *r = get_krbtgt_realm(&ek.sname);
865
866         if (r == NULL || strcmp(r, ek.srealm) == 0) {
867             ret = _kdc_add_KRB5SignedPath(context,
868                                           config,
869                                           krbtgt,
870                                           krbtgt_etype,
871                                           NULL,
872                                           spp,
873                                           &et);
874             if (ret)
875                 goto out;
876         }
877     }
878
879     if (enc_pa_data->len) {
880         rep.padata = calloc(1, sizeof(*rep.padata));
881         if (rep.padata == NULL) {
882             ret = ENOMEM;
883             goto out;
884         }
885         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
886         if (ret)
887             goto out;
888     }
889
890     if (krb5_enctype_valid(context, et.key.keytype) != 0
891         && _kdc_is_weak_expection(server->entry.principal, et.key.keytype))
892     {
893         krb5_enctype_enable(context, et.key.keytype);
894         is_weak = 1;
895     }
896
897
898     /* It is somewhat unclear where the etype in the following
899        encryption should come from. What we have is a session
900        key in the passed tgt, and a list of preferred etypes
901        *for the new ticket*. Should we pick the best possible
902        etype, given the keytype in the tgt, or should we look
903        at the etype list here as well?  What if the tgt
904        session key is DES3 and we want a ticket with a (say)
905        CAST session key. Should the DES3 etype be added to the
906        etype list, even if we don't want a session key with
907        DES3? */
908     ret = _kdc_encode_reply(context, config,
909                             &rep, &et, &ek, et.key.keytype,
910                             kvno,
911                             serverkey, 0, &tgt->key, e_text, reply);
912     if (is_weak)
913         krb5_enctype_disable(context, et.key.keytype);
914
915 out:
916     free_TGS_REP(&rep);
917     free_TransitedEncoding(&et.transited);
918     if(et.starttime)
919         free(et.starttime);
920     if(et.renew_till)
921         free(et.renew_till);
922     if(et.authorization_data) {
923         free_AuthorizationData(et.authorization_data);
924         free(et.authorization_data);
925     }
926     free_LastReq(&ek.last_req);
927     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
928     free_EncryptionKey(&et.key);
929     return ret;
930 }
931
932 static krb5_error_code
933 tgs_check_authenticator(krb5_context context,
934                         krb5_kdc_configuration *config,
935                         krb5_auth_context ac,
936                         KDC_REQ_BODY *b,
937                         const char **e_text,
938                         krb5_keyblock *key)
939 {
940     krb5_authenticator auth;
941     size_t len;
942     unsigned char *buf;
943     size_t buf_size;
944     krb5_error_code ret;
945     krb5_crypto crypto;
946
947     krb5_auth_con_getauthenticator(context, ac, &auth);
948     if(auth->cksum == NULL){
949         kdc_log(context, config, 0, "No authenticator in request");
950         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
951         goto out;
952     }
953     /*
954      * according to RFC1510 it doesn't need to be keyed,
955      * but according to the latest draft it needs to.
956      */
957     if (
958 #if 0
959 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
960         ||
961 #endif
962  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
963         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
964                 auth->cksum->cksumtype);
965         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
966         goto out;
967     }
968                 
969     /* XXX should not re-encode this */
970     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
971     if(ret){
972         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
973                 krb5_get_err_text(context, ret));
974         goto out;
975     }
976     if(buf_size != len) {
977         free(buf);
978         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
979         *e_text = "KDC internal error";
980         ret = KRB5KRB_ERR_GENERIC;
981         goto out;
982     }
983     ret = krb5_crypto_init(context, key, 0, &crypto);
984     if (ret) {
985         free(buf);
986         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
987                 krb5_get_err_text(context, ret));
988         goto out;
989     }
990     ret = krb5_verify_checksum(context,
991                                crypto,
992                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
993                                buf,
994                                len,
995                                auth->cksum);
996     free(buf);
997     krb5_crypto_destroy(context, crypto);
998     if(ret){
999         kdc_log(context, config, 0,
1000                 "Failed to verify authenticator checksum: %s",
1001                 krb5_get_err_text(context, ret));
1002     }
1003 out:
1004     free_Authenticator(auth);
1005     free(auth);
1006     return ret;
1007 }
1008
1009 /*
1010  *
1011  */
1012
1013 static const char *
1014 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1015 {
1016     const char *new_realm = krb5_config_get_string(context,
1017                                                    NULL,
1018                                                    "capaths",
1019                                                    crealm,
1020                                                    srealm,
1021                                                    NULL);
1022     return new_realm;
1023 }
1024         
1025
1026 static krb5_boolean
1027 need_referral(krb5_context context, krb5_kdc_configuration *config,
1028               const KDCOptions * const options, krb5_principal server,
1029               krb5_realm **realms)
1030 {
1031     const char *name;
1032
1033     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1034         return FALSE;
1035
1036     if (server->name.name_string.len == 1)
1037         name = server->name.name_string.val[0];
1038     if (server->name.name_string.len > 1)
1039         name = server->name.name_string.val[1];
1040     else
1041         return FALSE;
1042
1043     kdc_log(context, config, 0, "Searching referral for %s", name);
1044
1045     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1046 }
1047
1048 static krb5_error_code
1049 tgs_parse_request(krb5_context context,
1050                   krb5_kdc_configuration *config,
1051                   KDC_REQ_BODY *b,
1052                   const PA_DATA *tgs_req,
1053                   hdb_entry_ex **krbtgt,
1054                   krb5_enctype *krbtgt_etype,
1055                   krb5_ticket **ticket,
1056                   const char **e_text,
1057                   const char *from,
1058                   const struct sockaddr *from_addr,
1059                   time_t **csec,
1060                   int **cusec,
1061                   AuthorizationData **auth_data)
1062 {
1063     krb5_ap_req ap_req;
1064     krb5_error_code ret;
1065     krb5_principal princ;
1066     krb5_auth_context ac = NULL;
1067     krb5_flags ap_req_options;
1068     krb5_flags verify_ap_req_flags;
1069     krb5_crypto crypto;
1070     Key *tkey;
1071
1072     *auth_data = NULL;
1073     *csec  = NULL;
1074     *cusec = NULL;
1075
1076     memset(&ap_req, 0, sizeof(ap_req));
1077     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1078     if(ret){
1079         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1080                 krb5_get_err_text(context, ret));
1081         goto out;
1082     }
1083
1084     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1085         /* XXX check for ticket.sname == req.sname */
1086         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1087         ret = KRB5KDC_ERR_POLICY; /* ? */
1088         goto out;
1089     }
1090
1091     _krb5_principalname2krb5_principal(context,
1092                                        &princ,
1093                                        ap_req.ticket.sname,
1094                                        ap_req.ticket.realm);
1095
1096     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1097
1098     if(ret) {
1099         char *p;
1100         ret = krb5_unparse_name(context, princ, &p);
1101         if (ret != 0)
1102             p = "<unparse_name failed>";
1103         krb5_free_principal(context, princ);
1104         kdc_log(context, config, 0,
1105                 "Ticket-granting ticket not found in database: %s: %s",
1106                 p, krb5_get_err_text(context, ret));
1107         if (ret == 0)
1108             free(p);
1109         ret = KRB5KRB_AP_ERR_NOT_US;
1110         goto out;
1111     }
1112
1113     if(ap_req.ticket.enc_part.kvno &&
1114        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1115         char *p;
1116
1117         ret = krb5_unparse_name (context, princ, &p);
1118         krb5_free_principal(context, princ);
1119         if (ret != 0)
1120             p = "<unparse_name failed>";
1121         kdc_log(context, config, 0,
1122                 "Ticket kvno = %d, DB kvno = %d (%s)",
1123                 *ap_req.ticket.enc_part.kvno,
1124                 (*krbtgt)->entry.kvno,
1125                 p);
1126         if (ret == 0)
1127             free (p);
1128         ret = KRB5KRB_AP_ERR_BADKEYVER;
1129         goto out;
1130     }
1131
1132     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1133
1134     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1135                           ap_req.ticket.enc_part.etype, &tkey);
1136     if(ret){
1137         char *str = NULL, *p = NULL;
1138
1139         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1140         krb5_unparse_name(context, princ, &p);
1141         kdc_log(context, config, 0,
1142                 "No server key with enctype %s found for %s",
1143                 str ? str : "<unknown enctype>",
1144                 p ? p : "<unparse_name failed>");
1145         free(str);
1146         free(p);
1147         ret = KRB5KRB_AP_ERR_BADKEYVER;
1148         goto out;
1149     }
1150
1151     if (b->kdc_options.validate)
1152         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1153     else
1154         verify_ap_req_flags = 0;
1155
1156     ret = krb5_verify_ap_req2(context,
1157                               &ac,
1158                               &ap_req,
1159                               princ,
1160                               &tkey->key,
1161                               verify_ap_req_flags,
1162                               &ap_req_options,
1163                               ticket,
1164                               KRB5_KU_TGS_REQ_AUTH);
1165                         
1166     krb5_free_principal(context, princ);
1167     if(ret) {
1168         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1169                 krb5_get_err_text(context, ret));
1170         goto out;
1171     }
1172
1173     {
1174         krb5_authenticator auth;
1175
1176         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1177         if (ret == 0) {
1178             *csec   = malloc(sizeof(**csec));
1179             if (*csec == NULL) {
1180                 krb5_free_authenticator(context, &auth);
1181                 kdc_log(context, config, 0, "malloc failed");
1182                 goto out;
1183             }
1184             **csec  = auth->ctime;
1185             *cusec  = malloc(sizeof(**cusec));
1186             if (*cusec == NULL) {
1187                 krb5_free_authenticator(context, &auth);
1188                 kdc_log(context, config, 0, "malloc failed");
1189                 goto out;
1190             }
1191             **cusec  = auth->cusec;
1192             krb5_free_authenticator(context, &auth);
1193         }
1194     }
1195
1196     ret = tgs_check_authenticator(context, config,
1197                                   ac, b, e_text, &(*ticket)->ticket.key);
1198     if (ret) {
1199         krb5_auth_con_free(context, ac);
1200         goto out;
1201     }
1202
1203     if (b->enc_authorization_data) {
1204         unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1205         krb5_keyblock *subkey;
1206         krb5_data ad;
1207
1208         ret = krb5_auth_con_getremotesubkey(context,
1209                                             ac,
1210                                             &subkey);
1211         if(ret){
1212             krb5_auth_con_free(context, ac);
1213             kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1214                     krb5_get_err_text(context, ret));
1215             goto out;
1216         }
1217         if(subkey == NULL){
1218             usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1219             ret = krb5_auth_con_getkey(context, ac, &subkey);
1220             if(ret) {
1221                 krb5_auth_con_free(context, ac);
1222                 kdc_log(context, config, 0, "Failed to get session key: %s",
1223                         krb5_get_err_text(context, ret));
1224                 goto out;
1225             }
1226         }
1227         if(subkey == NULL){
1228             krb5_auth_con_free(context, ac);
1229             kdc_log(context, config, 0,
1230                     "Failed to get key for enc-authorization-data");
1231             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1232             goto out;
1233         }
1234         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1235         if (ret) {
1236             krb5_auth_con_free(context, ac);
1237             kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1238                     krb5_get_err_text(context, ret));
1239             goto out;
1240         }
1241         ret = krb5_decrypt_EncryptedData (context,
1242                                           crypto,
1243                                           usage,
1244                                           b->enc_authorization_data,
1245                                           &ad);
1246         krb5_crypto_destroy(context, crypto);
1247         if(ret){
1248             krb5_auth_con_free(context, ac);
1249             kdc_log(context, config, 0,
1250                     "Failed to decrypt enc-authorization-data");
1251             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1252             goto out;
1253         }
1254         krb5_free_keyblock(context, subkey);
1255         ALLOC(*auth_data);
1256         if (*auth_data == NULL) {
1257             krb5_auth_con_free(context, ac);
1258             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1259             goto out;
1260         }
1261         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1262         if(ret){
1263             krb5_auth_con_free(context, ac);
1264             free(*auth_data);
1265             *auth_data = NULL;
1266             kdc_log(context, config, 0, "Failed to decode authorization data");
1267             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1268             goto out;
1269         }
1270     }
1271
1272     krb5_auth_con_free(context, ac);
1273
1274 out:
1275     free_AP_REQ(&ap_req);
1276
1277     return ret;
1278 }
1279
1280 static krb5_error_code
1281 build_server_referral(krb5_context context,
1282                       krb5_kdc_configuration *config,
1283                       krb5_crypto session,
1284                       krb5_const_realm referred_realm,
1285                       const PrincipalName *true_principal_name,
1286                       const PrincipalName *requested_principal,
1287                       krb5_data *outdata)
1288 {               
1289     PA_ServerReferralData ref;
1290     krb5_error_code ret;
1291     EncryptedData ed;
1292     krb5_data data;
1293     size_t size;
1294
1295     memset(&ref, 0, sizeof(ref));
1296
1297     if (referred_realm) {
1298         ALLOC(ref.referred_realm);
1299         if (ref.referred_realm == NULL)
1300             goto eout;
1301         *ref.referred_realm = strdup(referred_realm);
1302         if (*ref.referred_realm == NULL)
1303             goto eout;
1304     }
1305     if (true_principal_name) {
1306         ALLOC(ref.true_principal_name);
1307         if (ref.true_principal_name == NULL)
1308             goto eout;
1309         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1310         if (ret)
1311             goto eout;
1312     }
1313     if (requested_principal) {
1314         ALLOC(ref.requested_principal_name);
1315         if (ref.requested_principal_name == NULL)
1316             goto eout;
1317         ret = copy_PrincipalName(requested_principal,
1318                                  ref.requested_principal_name);
1319         if (ret)
1320             goto eout;
1321     }
1322
1323     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1324                        data.data, data.length,
1325                        &ref, &size, ret);
1326     free_PA_ServerReferralData(&ref);
1327     if (ret)
1328         return ret;
1329     if (data.length != size)
1330         krb5_abortx(context, "internal asn.1 encoder error");
1331
1332     ret = krb5_encrypt_EncryptedData(context, session,
1333                                      KRB5_KU_PA_SERVER_REFERRAL,
1334                                      data.data, data.length,
1335                                      0 /* kvno */, &ed);
1336     free(data.data);
1337     if (ret)
1338         return ret;
1339
1340     ASN1_MALLOC_ENCODE(EncryptedData,
1341                        outdata->data, outdata->length,
1342                        &ed, &size, ret);
1343     free_EncryptedData(&ed);
1344     if (ret)
1345         return ret;
1346     if (outdata->length != size)
1347         krb5_abortx(context, "internal asn.1 encoder error");
1348
1349     return 0;
1350 eout:
1351     free_PA_ServerReferralData(&ref);
1352     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1353     return ENOMEM;
1354 }
1355
1356 static krb5_error_code
1357 tgs_build_reply(krb5_context context,
1358                 krb5_kdc_configuration *config,
1359                 KDC_REQ *req,
1360                 KDC_REQ_BODY *b,
1361                 hdb_entry_ex *krbtgt,
1362                 krb5_enctype krbtgt_etype,
1363                 krb5_ticket *ticket,
1364                 krb5_data *reply,
1365                 const char *from,
1366                 const char **e_text,
1367                 AuthorizationData **auth_data,
1368                 const struct sockaddr *from_addr,
1369                 int datagram_reply)
1370 {
1371     krb5_error_code ret;
1372     krb5_principal cp = NULL, sp = NULL;
1373     krb5_principal client_principal = NULL;
1374     char *spn = NULL, *cpn = NULL;
1375     hdb_entry_ex *server = NULL, *client = NULL;
1376     krb5_realm ref_realm = NULL;
1377     EncTicketPart *tgt = &ticket->ticket;
1378     KRB5SignedPathPrincipals *spp = NULL;
1379     Key *tkey;
1380     const EncryptionKey *ekey;
1381     krb5_keyblock sessionkey;
1382     krb5_kvno kvno;
1383     krb5_data rspac;
1384     int cross_realm = 0;
1385
1386     METHOD_DATA enc_pa_data;
1387
1388     PrincipalName *s;
1389     Realm r;
1390     int nloop = 0;
1391     EncTicketPart adtkt;
1392     char opt_str[128];
1393     int signedpath = 0;
1394
1395     memset(&sessionkey, 0, sizeof(sessionkey));
1396     memset(&adtkt, 0, sizeof(adtkt));
1397     krb5_data_zero(&rspac);
1398     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1399
1400     s = b->sname;
1401     r = b->realm;
1402
1403     if(b->kdc_options.enc_tkt_in_skey){
1404         Ticket *t;
1405         hdb_entry_ex *uu;
1406         krb5_principal p;
1407         Key *uukey;
1408         
1409         if(b->additional_tickets == NULL ||
1410            b->additional_tickets->len == 0){
1411             ret = KRB5KDC_ERR_BADOPTION; /* ? */
1412             kdc_log(context, config, 0,
1413                     "No second ticket present in request");
1414             goto out;
1415         }
1416         t = &b->additional_tickets->val[0];
1417         if(!get_krbtgt_realm(&t->sname)){
1418             kdc_log(context, config, 0,
1419                     "Additional ticket is not a ticket-granting ticket");
1420             ret = KRB5KDC_ERR_POLICY;
1421             goto out;
1422         }
1423         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1424         ret = _kdc_db_fetch(context, config, p,
1425                             HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1426                             NULL, &uu);
1427         krb5_free_principal(context, p);
1428         if(ret){
1429             if (ret == HDB_ERR_NOENTRY)
1430                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1431             goto out;
1432         }
1433         ret = hdb_enctype2key(context, &uu->entry,
1434                               t->enc_part.etype, &uukey);
1435         if(ret){
1436             _kdc_free_ent(context, uu);
1437             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1438             goto out;
1439         }
1440         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1441         _kdc_free_ent(context, uu);
1442         if(ret)
1443             goto out;
1444
1445         ret = verify_flags(context, config, &adtkt, spn);
1446         if (ret)
1447             goto out;
1448
1449         s = &adtkt.cname;
1450         r = adtkt.crealm;
1451     }
1452
1453     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1454     ret = krb5_unparse_name(context, sp, &spn); 
1455     if (ret)
1456         goto out;
1457     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1458     ret = krb5_unparse_name(context, cp, &cpn);
1459     if (ret)
1460         goto out;
1461     unparse_flags (KDCOptions2int(b->kdc_options),
1462                    asn1_KDCOptions_units(),
1463                    opt_str, sizeof(opt_str));
1464     if(*opt_str)
1465         kdc_log(context, config, 0,
1466                 "TGS-REQ %s from %s for %s [%s]",
1467                 cpn, from, spn, opt_str);
1468     else
1469         kdc_log(context, config, 0,
1470                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1471
1472     /*
1473      * Fetch server
1474      */
1475
1476 server_lookup:
1477     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1478                         NULL, &server);
1479
1480     if(ret){
1481         const char *new_rlm;
1482         Realm req_rlm;
1483         krb5_realm *realms;
1484
1485         if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1486             if(nloop++ < 2) {
1487                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1488                 if(new_rlm) {
1489                     kdc_log(context, config, 5, "krbtgt for realm %s "
1490                             "not found, trying %s",
1491                             req_rlm, new_rlm);
1492                     krb5_free_principal(context, sp);
1493                     free(spn);
1494                     krb5_make_principal(context, &sp, r,
1495                                         KRB5_TGS_NAME, new_rlm, NULL);
1496                     ret = krb5_unparse_name(context, sp, &spn); 
1497                     if (ret)
1498                         goto out;
1499
1500                     if (ref_realm)
1501                         free(ref_realm);
1502                     ref_realm = strdup(new_rlm);
1503                     goto server_lookup;
1504                 }
1505             }
1506         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1507             if (strcmp(realms[0], sp->realm) != 0) {
1508                 kdc_log(context, config, 5,
1509                         "Returning a referral to realm %s for "
1510                         "server %s that was not found",
1511                         realms[0], spn);
1512                 krb5_free_principal(context, sp);
1513                 free(spn);
1514                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1515                                     realms[0], NULL);
1516                 ret = krb5_unparse_name(context, sp, &spn);
1517                 if (ret)
1518                     goto out;
1519
1520                 if (ref_realm)
1521                     free(ref_realm);
1522                 ref_realm = strdup(realms[0]);
1523
1524                 krb5_free_host_realm(context, realms);
1525                 goto server_lookup;
1526             }
1527             krb5_free_host_realm(context, realms);
1528         }
1529         kdc_log(context, config, 0,
1530                 "Server not found in database: %s: %s", spn,
1531                 krb5_get_err_text(context, ret));
1532         if (ret == HDB_ERR_NOENTRY)
1533             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1534         goto out;
1535     }
1536
1537     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1538                         NULL, &client);
1539     if(ret) {
1540         const char *krbtgt_realm;
1541
1542         /*
1543          * If the client belongs to the same realm as our krbtgt, it
1544          * should exist in the local database.
1545          *
1546          */
1547
1548         krbtgt_realm =
1549             krb5_principal_get_comp_string(context,
1550                                            krbtgt->entry.principal, 1);
1551
1552         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1553             if (ret == HDB_ERR_NOENTRY)
1554                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1555             kdc_log(context, config, 1, "Client no longer in database: %s",
1556                     cpn);
1557             goto out;
1558         }
1559         
1560         kdc_log(context, config, 1, "Client not found in database: %s: %s",
1561                 cpn, krb5_get_err_text(context, ret));
1562
1563         cross_realm = 1;
1564     }
1565
1566     /*
1567      * Select enctype, return key and kvno.
1568      */
1569
1570     {
1571         krb5_enctype etype;
1572
1573         if(b->kdc_options.enc_tkt_in_skey) {
1574             int i;
1575             ekey = &adtkt.key;
1576             for(i = 0; i < b->etype.len; i++)
1577                 if (b->etype.val[i] == adtkt.key.keytype)
1578                     break;
1579             if(i == b->etype.len) {
1580                 kdc_log(context, config, 0,
1581                         "Addition ticket have not matching etypes", spp);
1582                 krb5_clear_error_message(context);
1583                 return KRB5KDC_ERR_ETYPE_NOSUPP;
1584             }
1585             etype = b->etype.val[i];
1586             kvno = 0;
1587         } else {
1588             Key *skey;
1589         
1590             ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1591                                   &skey, &etype);
1592             if(ret) {
1593                 kdc_log(context, config, 0,
1594                         "Server (%s) has no support for etypes", spn);
1595                 return ret;
1596             }
1597             ekey = &skey->key;
1598             kvno = server->entry.kvno;
1599         }
1600         
1601         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1602         if (ret)
1603             goto out;
1604     }
1605
1606     /*
1607      * Validate authoriation data
1608      */
1609
1610     /*
1611      * Check that service is in the same realm as the krbtgt. If it's
1612      * not the same, it's someone that is using a uni-directional trust
1613      * backward.
1614      */
1615
1616     if (strcmp(krb5_principal_get_realm(context, sp),
1617                krb5_principal_get_comp_string(context,
1618                                               krbtgt->entry.principal,
1619                                               1)) != 0) {
1620         char *tpn;
1621         ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1622         kdc_log(context, config, 0,
1623                 "Request with wrong krbtgt: %s",
1624                 (ret == 0) ? tpn : "<unknown>");
1625         if(ret == 0)
1626             free(tpn);
1627         ret = KRB5KRB_AP_ERR_NOT_US;
1628         goto out;
1629     }
1630
1631     /* check PAC if there is one */
1632
1633     ret = hdb_enctype2key(context, &krbtgt->entry,
1634                           krbtgt_etype, &tkey);
1635     if(ret) {
1636         kdc_log(context, config, 0,
1637                 "Failed to find key for krbtgt PAC check");
1638         goto out;
1639     }
1640
1641     ret = check_PAC(context, config, cp,
1642                     client, server, ekey, &tkey->key,
1643                     tgt, &rspac, &signedpath);
1644     if (ret) {
1645         kdc_log(context, config, 0,
1646                 "Verify PAC failed for %s (%s) from %s with %s",
1647                 spn, cpn, from, krb5_get_err_text(context, ret));
1648         goto out;
1649     }
1650
1651     /* also check the krbtgt for signature */
1652     ret = check_KRB5SignedPath(context,
1653                                config,
1654                                krbtgt,
1655                                tgt,
1656                                &spp,
1657                                &signedpath);
1658     if (ret) {
1659         kdc_log(context, config, 0,
1660                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1661                 spn, cpn, from, krb5_get_err_text(context, ret));
1662         goto out;
1663     }
1664
1665     /*
1666      * Process request
1667      */
1668
1669     client_principal = cp;
1670
1671     if (client) {
1672         const PA_DATA *sdata;
1673         int i = 0;
1674
1675         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
1676         if (sdata) {
1677             krb5_crypto crypto;
1678             krb5_data datack;
1679             PA_S4U2Self self;
1680             char *selfcpn = NULL;
1681             const char *str;
1682
1683             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1684                                      sdata->padata_value.length,
1685                                      &self, NULL);
1686             if (ret) {
1687                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1688                 goto out;
1689             }
1690
1691             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1692             if (ret)
1693                 goto out;
1694
1695             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1696             if (ret) {
1697                 free_PA_S4U2Self(&self);
1698                 krb5_data_free(&datack);
1699                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1700                         krb5_get_err_text(context, ret));
1701                 goto out;
1702             }
1703
1704             ret = krb5_verify_checksum(context,
1705                                        crypto,
1706                                        KRB5_KU_OTHER_CKSUM,
1707                                        datack.data,
1708                                        datack.length,
1709                                        &self.cksum);
1710             krb5_data_free(&datack);
1711             krb5_crypto_destroy(context, crypto);
1712             if (ret) {
1713                 free_PA_S4U2Self(&self);
1714                 kdc_log(context, config, 0,
1715                         "krb5_verify_checksum failed for S4U2Self: %s",
1716                         krb5_get_err_text(context, ret));
1717                 goto out;
1718             }
1719
1720             ret = _krb5_principalname2krb5_principal(context,
1721                                                      &client_principal,
1722                                                      self.name,
1723                                                      self.realm);
1724             free_PA_S4U2Self(&self);
1725             if (ret)
1726                 goto out;
1727
1728             ret = krb5_unparse_name(context, client_principal, &selfcpn);       
1729             if (ret)
1730                 goto out;
1731
1732             /*
1733              * Check that service doing the impersonating is
1734              * requesting a ticket to it-self.
1735              */
1736             if (krb5_principal_compare(context, cp, sp) != TRUE) {
1737                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1738                         "to impersonate some other user "
1739                         "(tried for user %s to service %s)",
1740                         cpn, selfcpn, spn);
1741                 free(selfcpn);
1742                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1743                 goto out;
1744             }
1745
1746             /*
1747              * If the service isn't trusted for authentication to
1748              * delegation, remove the forward flag.
1749              */
1750
1751             if (client->entry.flags.trusted_for_delegation) {
1752                 str = "[forwardable]";
1753             } else {
1754                 b->kdc_options.forwardable = 0;
1755                 str = "";
1756             }
1757             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1758                     "service %s %s", cpn, selfcpn, spn, str);
1759             free(selfcpn);
1760         }
1761     }
1762
1763     /*
1764      * Constrained delegation
1765      */
1766
1767     if (client != NULL
1768         && b->additional_tickets != NULL
1769         && b->additional_tickets->len != 0
1770         && b->kdc_options.enc_tkt_in_skey == 0)
1771     {
1772         int ad_signedpath = 0;
1773         Key *clientkey;
1774         Ticket *t;
1775         char *str;
1776
1777         /*
1778          * Require that the KDC have issued the service's krbtgt (not
1779          * self-issued ticket with kimpersonate(1).
1780          */
1781         if (!signedpath) {
1782             ret = KRB5KDC_ERR_BADOPTION;
1783             kdc_log(context, config, 0,
1784                     "Constrained delegation done on service ticket %s/%s",
1785                     cpn, spn);
1786             goto out;
1787         }
1788
1789         t = &b->additional_tickets->val[0];
1790
1791         ret = hdb_enctype2key(context, &client->entry,
1792                               t->enc_part.etype, &clientkey);
1793         if(ret){
1794             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1795             goto out;
1796         }
1797
1798         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1799         if (ret) {
1800             kdc_log(context, config, 0,
1801                     "failed to decrypt ticket for "
1802                     "constrained delegation from %s to %s ", spn, cpn);
1803             goto out;
1804         }
1805
1806         /* check that ticket is valid */
1807         if (adtkt.flags.forwardable == 0) {
1808             kdc_log(context, config, 0,
1809                     "Missing forwardable flag on ticket for "
1810                     "constrained delegation from %s to %s ", spn, cpn);
1811             ret = KRB5KDC_ERR_BADOPTION;
1812             goto out;
1813         }
1814
1815         ret = check_constrained_delegation(context, config, client, sp);
1816         if (ret) {
1817             kdc_log(context, config, 0,
1818                     "constrained delegation from %s to %s not allowed",
1819                     spn, cpn);
1820             goto out;
1821         }
1822
1823         ret = _krb5_principalname2krb5_principal(context,
1824                                                  &client_principal,
1825                                                  adtkt.cname,
1826                                                  adtkt.crealm);
1827         if (ret)
1828             goto out;
1829
1830         ret = krb5_unparse_name(context, client_principal, &str);
1831         if (ret)
1832             goto out;
1833
1834         ret = verify_flags(context, config, &adtkt, str);
1835         if (ret) {
1836             free(str);
1837             goto out;
1838         }
1839
1840         /*
1841          * Check that the KDC issued the user's ticket.
1842          */
1843         ret = check_KRB5SignedPath(context,
1844                                    config,
1845                                    krbtgt,
1846                                    &adtkt,
1847                                    NULL,
1848                                    &ad_signedpath);
1849         if (ret == 0 && !ad_signedpath)
1850             ret = KRB5KDC_ERR_BADOPTION;
1851         if (ret) {
1852             kdc_log(context, config, 0,
1853                     "KRB5SignedPath check from service %s failed "
1854                     "for delegation to %s for client %s "
1855                     "from %s failed with %s",
1856                     spn, str, cpn, from, krb5_get_err_text(context, ret));
1857             free(str);
1858             goto out;
1859         }
1860
1861         kdc_log(context, config, 0, "constrained delegation for %s "
1862                 "from %s to %s", str, cpn, spn);
1863         free(str);
1864     }
1865
1866     /*
1867      * Check flags
1868      */
1869
1870     ret = _kdc_check_flags(context, config,
1871                            client, cpn,
1872                            server, spn,
1873                            FALSE);
1874     if(ret)
1875         goto out;
1876
1877     if((b->kdc_options.validate || b->kdc_options.renew) &&
1878        !krb5_principal_compare(context,
1879                                krbtgt->entry.principal,
1880                                server->entry.principal)){
1881         kdc_log(context, config, 0, "Inconsistent request.");
1882         ret = KRB5KDC_ERR_SERVER_NOMATCH;
1883         goto out;
1884     }
1885
1886     /* check for valid set of addresses */
1887     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1888         ret = KRB5KRB_AP_ERR_BADADDR;
1889         kdc_log(context, config, 0, "Request from wrong address");
1890         goto out;
1891     }
1892         
1893     /*
1894      * If this is an referral, add server referral data to the
1895      * auth_data reply .
1896      */
1897     if (ref_realm) {
1898         PA_DATA pa;
1899         krb5_crypto crypto;
1900
1901         kdc_log(context, config, 0,
1902                 "Adding server referral to %s", ref_realm);
1903
1904         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1905         if (ret)
1906             goto out;
1907
1908         ret = build_server_referral(context, config, crypto, ref_realm,
1909                                     NULL, s, &pa.padata_value);
1910         krb5_crypto_destroy(context, crypto);
1911         if (ret) {
1912             kdc_log(context, config, 0,
1913                     "Failed building server referral");
1914             goto out;
1915         }
1916         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1917
1918         ret = add_METHOD_DATA(&enc_pa_data, &pa);
1919         krb5_data_free(&pa.padata_value);
1920         if (ret) {
1921             kdc_log(context, config, 0,
1922                     "Add server referral METHOD-DATA failed");
1923             goto out;
1924         }
1925     }
1926
1927     /*
1928      *
1929      */
1930
1931     ret = tgs_make_reply(context,
1932                          config,
1933                          b,
1934                          client_principal,
1935                          tgt,
1936                          ekey,
1937                          &sessionkey,
1938                          kvno,
1939                          *auth_data,
1940                          server,
1941                          sp,
1942                          spn,
1943                          client,
1944                          cp,
1945                          krbtgt,
1946                          krbtgt_etype,
1947                          spp,
1948                          &rspac,
1949                          &enc_pa_data,
1950                          e_text,
1951                          reply);
1952         
1953 out:
1954     free(spn);
1955     free(cpn);
1956         
1957     krb5_data_free(&rspac);
1958     krb5_free_keyblock_contents(context, &sessionkey);
1959     if(server)
1960         _kdc_free_ent(context, server);
1961     if(client)
1962         _kdc_free_ent(context, client);
1963
1964     if (client_principal && client_principal != cp)
1965         krb5_free_principal(context, client_principal);
1966     if (cp)
1967         krb5_free_principal(context, cp);
1968     if (sp)
1969         krb5_free_principal(context, sp);
1970     if (ref_realm)
1971         free(ref_realm);
1972     free_METHOD_DATA(&enc_pa_data);
1973
1974     free_EncTicketPart(&adtkt);
1975
1976     return ret;
1977 }
1978
1979 /*
1980  *
1981  */
1982
1983 krb5_error_code
1984 _kdc_tgs_rep(krb5_context context,
1985              krb5_kdc_configuration *config,
1986              KDC_REQ *req,
1987              krb5_data *data,
1988              const char *from,
1989              struct sockaddr *from_addr,
1990              int datagram_reply)
1991 {
1992     AuthorizationData *auth_data = NULL;
1993     krb5_error_code ret;
1994     int i = 0;
1995     const PA_DATA *tgs_req;
1996
1997     hdb_entry_ex *krbtgt = NULL;
1998     krb5_ticket *ticket = NULL;
1999     const char *e_text = NULL;
2000     krb5_enctype krbtgt_etype = ETYPE_NULL;
2001
2002     time_t *csec = NULL;
2003     int *cusec = NULL;
2004
2005     if(req->padata == NULL){
2006         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2007         kdc_log(context, config, 0,
2008                 "TGS-REQ from %s without PA-DATA", from);
2009         goto out;
2010     }
2011
2012     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2013
2014     if(tgs_req == NULL){
2015         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2016         
2017         kdc_log(context, config, 0,
2018                 "TGS-REQ from %s without PA-TGS-REQ", from);
2019         goto out;
2020     }
2021     ret = tgs_parse_request(context, config,
2022                             &req->req_body, tgs_req,
2023                             &krbtgt,
2024                             &krbtgt_etype,
2025                             &ticket,
2026                             &e_text,
2027                             from, from_addr,
2028                             &csec, &cusec,
2029                             &auth_data);
2030     if (ret) {
2031         kdc_log(context, config, 0,
2032                 "Failed parsing TGS-REQ from %s", from);
2033         goto out;
2034     }
2035
2036     ret = tgs_build_reply(context,
2037                           config,
2038                           req,
2039                           &req->req_body,
2040                           krbtgt,
2041                           krbtgt_etype,
2042                           ticket,
2043                           data,
2044                           from,
2045                           &e_text,
2046                           &auth_data,
2047                           from_addr,
2048                           datagram_reply);
2049     if (ret) {
2050         kdc_log(context, config, 0,
2051                 "Failed building TGS-REP to %s", from);
2052         goto out;
2053     }
2054
2055     /* */
2056     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2057         krb5_data_free(data);
2058         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2059         e_text = "Reply packet too large";
2060     }
2061
2062 out:
2063     if(ret && data->data == NULL){
2064         krb5_mk_error(context,
2065                       ret,
2066                       NULL,
2067                       NULL,
2068                       NULL,
2069                       NULL,
2070                       csec,
2071                       cusec,
2072                       data);
2073     }
2074     free(csec);
2075     free(cusec);
2076     if (ticket)
2077         krb5_free_ticket(context, ticket);
2078     if(krbtgt)
2079         _kdc_free_ent(context, krbtgt);
2080
2081     if (auth_data) {
2082         free_AuthorizationData(auth_data);
2083         free(auth_data);
2084     }
2085
2086     return 0;
2087 }