heimdal: remove checking of KDC PAC signature, delegate to wdc plugin
[kai/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 /*
37  * return the realm of a krbtgt-ticket or NULL
38  */
39
40 static Realm
41 get_krbtgt_realm(const PrincipalName *p)
42 {
43     if(p->name_string.len == 2
44        && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
45         return p->name_string.val[1];
46     else
47         return NULL;
48 }
49
50 /*
51  * The KDC might add a signed path to the ticket authorization data
52  * field. This is to avoid server impersonating clients and the
53  * request constrained delegation.
54  *
55  * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
56  * entry of type KRB5SignedPath.
57  */
58
59 static krb5_error_code
60 find_KRB5SignedPath(krb5_context context,
61                     const AuthorizationData *ad,
62                     krb5_data *data)
63 {
64     AuthorizationData child;
65     krb5_error_code ret;
66     int pos;
67
68     if (ad == NULL || ad->len == 0)
69         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
70
71     pos = ad->len - 1;
72
73     if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
74         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
75
76     ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
77                                    ad->val[pos].ad_data.length,
78                                    &child,
79                                    NULL);
80     if (ret) {
81         krb5_set_error_message(context, ret, "Failed to decode "
82                                "IF_RELEVANT with %d", ret);
83         return ret;
84     }
85
86     if (child.len != 1) {
87         free_AuthorizationData(&child);
88         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
89     }
90
91     if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
92         free_AuthorizationData(&child);
93         return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
94     }
95
96     if (data)
97         ret = der_copy_octet_string(&child.val[0].ad_data, data);
98     free_AuthorizationData(&child);
99     return ret;
100 }
101
102 krb5_error_code
103 _kdc_add_KRB5SignedPath(krb5_context context,
104                         krb5_kdc_configuration *config,
105                         hdb_entry_ex *krbtgt,
106                         krb5_enctype enctype,
107                         krb5_principal client,
108                         krb5_const_principal server,
109                         krb5_principals principals,
110                         EncTicketPart *tkt)
111 {
112     krb5_error_code ret;
113     KRB5SignedPath sp;
114     krb5_data data;
115     krb5_crypto crypto = NULL;
116     size_t size = 0;
117
118     if (server && principals) {
119         ret = add_Principals(principals, server);
120         if (ret)
121             return ret;
122     }
123
124     {
125         KRB5SignedPathData spd;
126
127         spd.client = client;
128         spd.authtime = tkt->authtime;
129         spd.delegated = principals;
130         spd.method_data = NULL;
131
132         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
133                            &spd, &size, ret);
134         if (ret)
135             return ret;
136         if (data.length != size)
137             krb5_abortx(context, "internal asn.1 encoder error");
138     }
139
140     {
141         Key *key;
142         ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
143         if (ret == 0)
144             ret = krb5_crypto_init(context, &key->key, 0, &crypto);
145         if (ret) {
146             free(data.data);
147             return ret;
148         }
149     }
150
151     /*
152      * Fill in KRB5SignedPath
153      */
154
155     sp.etype = enctype;
156     sp.delegated = principals;
157     sp.method_data = NULL;
158
159     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
160                                data.data, data.length, &sp.cksum);
161     krb5_crypto_destroy(context, crypto);
162     free(data.data);
163     if (ret)
164         return ret;
165
166     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
167     free_Checksum(&sp.cksum);
168     if (ret)
169         return ret;
170     if (data.length != size)
171         krb5_abortx(context, "internal asn.1 encoder error");
172
173
174     /*
175      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
176      * authorization data field.
177      */
178
179     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
180                                       KRB5_AUTHDATA_SIGNTICKET, &data);
181     krb5_data_free(&data);
182
183     return ret;
184 }
185
186 static krb5_error_code
187 check_KRB5SignedPath(krb5_context context,
188                      krb5_kdc_configuration *config,
189                      hdb_entry_ex *krbtgt,
190                      krb5_principal cp,
191                      EncTicketPart *tkt,
192                      krb5_principals *delegated,
193                      int *signedpath)
194 {
195     krb5_error_code ret;
196     krb5_data data;
197     krb5_crypto crypto = NULL;
198
199     if (delegated)
200         *delegated = NULL;
201
202     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
203     if (ret == 0) {
204         KRB5SignedPathData spd;
205         KRB5SignedPath sp;
206         size_t size = 0;
207
208         ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
209         krb5_data_free(&data);
210         if (ret)
211             return ret;
212
213         spd.client = cp;
214         spd.authtime = tkt->authtime;
215         spd.delegated = sp.delegated;
216         spd.method_data = sp.method_data;
217
218         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219                            &spd, &size, ret);
220         if (ret) {
221             free_KRB5SignedPath(&sp);
222             return ret;
223         }
224         if (data.length != size)
225             krb5_abortx(context, "internal asn.1 encoder error");
226
227         {
228             Key *key;
229             ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
230             if (ret == 0)
231                 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
232             if (ret) {
233                 free(data.data);
234                 free_KRB5SignedPath(&sp);
235                 return ret;
236             }
237         }
238         ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
239                                    data.data, data.length,
240                                    &sp.cksum);
241         krb5_crypto_destroy(context, crypto);
242         free(data.data);
243         if (ret) {
244             free_KRB5SignedPath(&sp);
245             kdc_log(context, config, 5,
246                     "KRB5SignedPath not signed correctly, not marking as signed");
247             return 0;
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_Principals(*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           const krb5_principal delegated_proxy_principal,
283           hdb_entry_ex *client,
284           hdb_entry_ex *server,
285           hdb_entry_ex *krbtgt,
286           const EncryptionKey *server_check_key,
287           const EncryptionKey *server_sign_key,
288           const EncryptionKey *krbtgt_sign_key,
289           EncTicketPart *tkt,
290           krb5_data *rspac,
291           int *signedpath)
292 {
293     AuthorizationData *ad = tkt->authorization_data;
294     unsigned i, j;
295     krb5_error_code ret;
296
297     if (ad == NULL || ad->len == 0)
298         return 0;
299
300     for (i = 0; i < ad->len; i++) {
301         AuthorizationData child;
302
303         if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
304             continue;
305
306         ret = decode_AuthorizationData(ad->val[i].ad_data.data,
307                                        ad->val[i].ad_data.length,
308                                        &child,
309                                        NULL);
310         if (ret) {
311             krb5_set_error_message(context, ret, "Failed to decode "
312                                    "IF_RELEVANT with %d", ret);
313             return ret;
314         }
315         for (j = 0; j < child.len; j++) {
316
317             if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
318                 int signed_pac = 0;
319                 krb5_pac pac;
320
321                 /* Found PAC */
322                 ret = krb5_pac_parse(context,
323                                      child.val[j].ad_data.data,
324                                      child.val[j].ad_data.length,
325                                      &pac);
326                 free_AuthorizationData(&child);
327                 if (ret)
328                     return ret;
329
330                 ret = krb5_pac_verify(context, pac, tkt->authtime,
331                                       client_principal,
332                                       server_check_key, NULL);
333                 if (ret) {
334                     krb5_pac_free(context, pac);
335                     return ret;
336                 }
337
338                 ret = _kdc_pac_verify(context, client_principal,
339                                       delegated_proxy_principal,
340                                       client, server, krbtgt, &pac, &signed_pac);
341                 if (ret) {
342                     krb5_pac_free(context, pac);
343                     return ret;
344                 }
345
346                 /*
347                  * Only re-sign PAC if we could verify it with the PAC
348                  * function. The no-verify case happens when we get in
349                  * a PAC from cross realm from a Windows domain and
350                  * that there is no PAC verification function.
351                  */
352                 if (signed_pac) {
353                     *signedpath = 1;
354                     ret = _krb5_pac_sign(context, pac, tkt->authtime,
355                                          client_principal,
356                                          server_sign_key, krbtgt_sign_key, rspac);
357                 }
358                 krb5_pac_free(context, pac);
359
360                 return ret;
361             }
362         }
363         free_AuthorizationData(&child);
364     }
365     return 0;
366 }
367
368 /*
369  *
370  */
371
372 static krb5_error_code
373 check_tgs_flags(krb5_context context,
374                 krb5_kdc_configuration *config,
375                 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
376 {
377     KDCOptions f = b->kdc_options;
378
379     if(f.validate){
380         if(!tgt->flags.invalid || tgt->starttime == NULL){
381             kdc_log(context, config, 0,
382                     "Bad request to validate ticket");
383             return KRB5KDC_ERR_BADOPTION;
384         }
385         if(*tgt->starttime > kdc_time){
386             kdc_log(context, config, 0,
387                     "Early request to validate ticket");
388             return KRB5KRB_AP_ERR_TKT_NYV;
389         }
390         /* XXX  tkt = tgt */
391         et->flags.invalid = 0;
392     }else if(tgt->flags.invalid){
393         kdc_log(context, config, 0,
394                 "Ticket-granting ticket has INVALID flag set");
395         return KRB5KRB_AP_ERR_TKT_INVALID;
396     }
397
398     if(f.forwardable){
399         if(!tgt->flags.forwardable){
400             kdc_log(context, config, 0,
401                     "Bad request for forwardable ticket");
402             return KRB5KDC_ERR_BADOPTION;
403         }
404         et->flags.forwardable = 1;
405     }
406     if(f.forwarded){
407         if(!tgt->flags.forwardable){
408             kdc_log(context, config, 0,
409                     "Request to forward non-forwardable ticket");
410             return KRB5KDC_ERR_BADOPTION;
411         }
412         et->flags.forwarded = 1;
413         et->caddr = b->addresses;
414     }
415     if(tgt->flags.forwarded)
416         et->flags.forwarded = 1;
417
418     if(f.proxiable){
419         if(!tgt->flags.proxiable){
420             kdc_log(context, config, 0,
421                     "Bad request for proxiable ticket");
422             return KRB5KDC_ERR_BADOPTION;
423         }
424         et->flags.proxiable = 1;
425     }
426     if(f.proxy){
427         if(!tgt->flags.proxiable){
428             kdc_log(context, config, 0,
429                     "Request to proxy non-proxiable ticket");
430             return KRB5KDC_ERR_BADOPTION;
431         }
432         et->flags.proxy = 1;
433         et->caddr = b->addresses;
434     }
435     if(tgt->flags.proxy)
436         et->flags.proxy = 1;
437
438     if(f.allow_postdate){
439         if(!tgt->flags.may_postdate){
440             kdc_log(context, config, 0,
441                     "Bad request for post-datable ticket");
442             return KRB5KDC_ERR_BADOPTION;
443         }
444         et->flags.may_postdate = 1;
445     }
446     if(f.postdated){
447         if(!tgt->flags.may_postdate){
448             kdc_log(context, config, 0,
449                     "Bad request for postdated ticket");
450             return KRB5KDC_ERR_BADOPTION;
451         }
452         if(b->from)
453             *et->starttime = *b->from;
454         et->flags.postdated = 1;
455         et->flags.invalid = 1;
456     }else if(b->from && *b->from > kdc_time + context->max_skew){
457         kdc_log(context, config, 0, "Ticket cannot be postdated");
458         return KRB5KDC_ERR_CANNOT_POSTDATE;
459     }
460
461     if(f.renewable){
462         if(!tgt->flags.renewable || tgt->renew_till == NULL){
463             kdc_log(context, config, 0,
464                     "Bad request for renewable ticket");
465             return KRB5KDC_ERR_BADOPTION;
466         }
467         et->flags.renewable = 1;
468         ALLOC(et->renew_till);
469         _kdc_fix_time(&b->rtime);
470         *et->renew_till = *b->rtime;
471     }
472     if(f.renew){
473         time_t old_life;
474         if(!tgt->flags.renewable || tgt->renew_till == NULL){
475             kdc_log(context, config, 0,
476                     "Request to renew non-renewable ticket");
477             return KRB5KDC_ERR_BADOPTION;
478         }
479         old_life = tgt->endtime;
480         if(tgt->starttime)
481             old_life -= *tgt->starttime;
482         else
483             old_life -= tgt->authtime;
484         et->endtime = *et->starttime + old_life;
485         if (et->renew_till != NULL)
486             et->endtime = min(*et->renew_till, et->endtime);
487     }
488
489 #if 0
490     /* checks for excess flags */
491     if(f.request_anonymous && !config->allow_anonymous){
492         kdc_log(context, config, 0,
493                 "Request for anonymous ticket");
494         return KRB5KDC_ERR_BADOPTION;
495     }
496 #endif
497     return 0;
498 }
499
500 /*
501  * Determine if constrained delegation is allowed from this client to this server
502  */
503
504 static krb5_error_code
505 check_constrained_delegation(krb5_context context,
506                              krb5_kdc_configuration *config,
507                              HDB *clientdb,
508                              hdb_entry_ex *client,
509                              hdb_entry_ex *server,
510                              krb5_const_principal target)
511 {
512     const HDB_Ext_Constrained_delegation_acl *acl;
513     krb5_error_code ret;
514     size_t i;
515
516     /*
517      * constrained_delegation (S4U2Proxy) only works within
518      * the same realm. We use the already canonicalized version
519      * of the principals here, while "target" is the principal
520      * provided by the client.
521      */
522     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
523         ret = KRB5KDC_ERR_BADOPTION;
524         kdc_log(context, config, 0,
525             "Bad request for constrained delegation");
526         return ret;
527     }
528
529     if (clientdb->hdb_check_constrained_delegation) {
530         ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
531         if (ret == 0)
532             return 0;
533     } else {
534         /* if client delegates to itself, that ok */
535         if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
536             return 0;
537
538         ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
539         if (ret) {
540             krb5_clear_error_message(context);
541             return ret;
542         }
543
544         if (acl) {
545             for (i = 0; i < acl->len; i++) {
546                 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
547                     return 0;
548             }
549         }
550         ret = KRB5KDC_ERR_BADOPTION;
551     }
552     kdc_log(context, config, 0,
553             "Bad request for constrained delegation");
554     return ret;
555 }
556
557 /*
558  * Determine if s4u2self is allowed from this client to this server
559  *
560  * For example, regardless of the principal being impersonated, if the
561  * 'client' and 'server' are the same, then it's safe.
562  */
563
564 static krb5_error_code
565 check_s4u2self(krb5_context context,
566                krb5_kdc_configuration *config,
567                HDB *clientdb,
568                hdb_entry_ex *client,
569                krb5_const_principal server)
570 {
571     krb5_error_code ret;
572
573     /* if client does a s4u2self to itself, that ok */
574     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
575         return 0;
576
577     if (clientdb->hdb_check_s4u2self) {
578         ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
579         if (ret == 0)
580             return 0;
581     } else {
582         ret = KRB5KDC_ERR_BADOPTION;
583     }
584     return ret;
585 }
586
587 /*
588  *
589  */
590
591 static krb5_error_code
592 verify_flags (krb5_context context,
593               krb5_kdc_configuration *config,
594               const EncTicketPart *et,
595               const char *pstr)
596 {
597     if(et->endtime < kdc_time){
598         kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
599         return KRB5KRB_AP_ERR_TKT_EXPIRED;
600     }
601     if(et->flags.invalid){
602         kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
603         return KRB5KRB_AP_ERR_TKT_NYV;
604     }
605     return 0;
606 }
607
608 /*
609  *
610  */
611
612 static krb5_error_code
613 fix_transited_encoding(krb5_context context,
614                        krb5_kdc_configuration *config,
615                        krb5_boolean check_policy,
616                        const TransitedEncoding *tr,
617                        EncTicketPart *et,
618                        const char *client_realm,
619                        const char *server_realm,
620                        const char *tgt_realm)
621 {
622     krb5_error_code ret = 0;
623     char **realms, **tmp;
624     unsigned int num_realms;
625     size_t i;
626
627     switch (tr->tr_type) {
628     case DOMAIN_X500_COMPRESS:
629         break;
630     case 0:
631         /*
632          * Allow empty content of type 0 because that is was Microsoft
633          * generates in their TGT.
634          */
635         if (tr->contents.length == 0)
636             break;
637         kdc_log(context, config, 0,
638                 "Transited type 0 with non empty content");
639         return KRB5KDC_ERR_TRTYPE_NOSUPP;
640     default:
641         kdc_log(context, config, 0,
642                 "Unknown transited type: %u", tr->tr_type);
643         return KRB5KDC_ERR_TRTYPE_NOSUPP;
644     }
645
646     ret = krb5_domain_x500_decode(context,
647                                   tr->contents,
648                                   &realms,
649                                   &num_realms,
650                                   client_realm,
651                                   server_realm);
652     if(ret){
653         krb5_warn(context, ret,
654                   "Decoding transited encoding");
655         return ret;
656     }
657     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
658         /* not us, so add the previous realm to transited set */
659         if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
660             ret = ERANGE;
661             goto free_realms;
662         }
663         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
664         if(tmp == NULL){
665             ret = ENOMEM;
666             goto free_realms;
667         }
668         realms = tmp;
669         realms[num_realms] = strdup(tgt_realm);
670         if(realms[num_realms] == NULL){
671             ret = ENOMEM;
672             goto free_realms;
673         }
674         num_realms++;
675     }
676     if(num_realms == 0) {
677         if(strcmp(client_realm, server_realm))
678             kdc_log(context, config, 0,
679                     "cross-realm %s -> %s", client_realm, server_realm);
680     } else {
681         size_t l = 0;
682         char *rs;
683         for(i = 0; i < num_realms; i++)
684             l += strlen(realms[i]) + 2;
685         rs = malloc(l);
686         if(rs != NULL) {
687             *rs = '\0';
688             for(i = 0; i < num_realms; i++) {
689                 if(i > 0)
690                     strlcat(rs, ", ", l);
691                 strlcat(rs, realms[i], l);
692             }
693             kdc_log(context, config, 0,
694                     "cross-realm %s -> %s via [%s]",
695                     client_realm, server_realm, rs);
696             free(rs);
697         }
698     }
699     if(check_policy) {
700         ret = krb5_check_transited(context, client_realm,
701                                    server_realm,
702                                    realms, num_realms, NULL);
703         if(ret) {
704             krb5_warn(context, ret, "cross-realm %s -> %s",
705                       client_realm, server_realm);
706             goto free_realms;
707         }
708         et->flags.transited_policy_checked = 1;
709     }
710     et->transited.tr_type = DOMAIN_X500_COMPRESS;
711     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
712     if(ret)
713         krb5_warn(context, ret, "Encoding transited encoding");
714   free_realms:
715     for(i = 0; i < num_realms; i++)
716         free(realms[i]);
717     free(realms);
718     return ret;
719 }
720
721
722 static krb5_error_code
723 tgs_make_reply(krb5_context context,
724                krb5_kdc_configuration *config,
725                KDC_REQ_BODY *b,
726                krb5_const_principal tgt_name,
727                const EncTicketPart *tgt,
728                const krb5_keyblock *replykey,
729                int rk_is_subkey,
730                const EncryptionKey *serverkey,
731                const krb5_keyblock *sessionkey,
732                krb5_kvno kvno,
733                AuthorizationData *auth_data,
734                hdb_entry_ex *server,
735                krb5_principal server_principal,
736                const char *server_name,
737                hdb_entry_ex *client,
738                krb5_principal client_principal,
739                hdb_entry_ex *krbtgt,
740                krb5_enctype krbtgt_etype,
741                krb5_principals spp,
742                const krb5_data *rspac,
743                const METHOD_DATA *enc_pa_data,
744                const char **e_text,
745                krb5_data *reply)
746 {
747     KDC_REP rep;
748     EncKDCRepPart ek;
749     EncTicketPart et;
750     KDCOptions f = b->kdc_options;
751     krb5_error_code ret;
752     int is_weak = 0;
753
754     memset(&rep, 0, sizeof(rep));
755     memset(&et, 0, sizeof(et));
756     memset(&ek, 0, sizeof(ek));
757
758     rep.pvno = 5;
759     rep.msg_type = krb_tgs_rep;
760
761     et.authtime = tgt->authtime;
762     _kdc_fix_time(&b->till);
763     et.endtime = min(tgt->endtime, *b->till);
764     ALLOC(et.starttime);
765     *et.starttime = kdc_time;
766
767     ret = check_tgs_flags(context, config, b, tgt, &et);
768     if(ret)
769         goto out;
770
771     /* We should check the transited encoding if:
772        1) the request doesn't ask not to be checked
773        2) globally enforcing a check
774        3) principal requires checking
775        4) we allow non-check per-principal, but principal isn't marked as allowing this
776        5) we don't globally allow this
777     */
778
779 #define GLOBAL_FORCE_TRANSITED_CHECK            \
780     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
781 #define GLOBAL_ALLOW_PER_PRINCIPAL                      \
782     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
783 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                    \
784     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
785
786 /* these will consult the database in future release */
787 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
788 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
789
790     ret = fix_transited_encoding(context, config,
791                                  !f.disable_transited_check ||
792                                  GLOBAL_FORCE_TRANSITED_CHECK ||
793                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
794                                  !((GLOBAL_ALLOW_PER_PRINCIPAL &&
795                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
796                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
797                                  &tgt->transited, &et,
798                                  krb5_principal_get_realm(context, client_principal),
799                                  krb5_principal_get_realm(context, server->entry.principal),
800                                  krb5_principal_get_realm(context, krbtgt->entry.principal));
801     if(ret)
802         goto out;
803
804     copy_Realm(&server_principal->realm, &rep.ticket.realm);
805     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
806     copy_Realm(&tgt_name->realm, &rep.crealm);
807 /*
808     if (f.request_anonymous)
809         _kdc_make_anonymous_principalname (&rep.cname);
810     else */
811
812     copy_PrincipalName(&tgt_name->name, &rep.cname);
813     rep.ticket.tkt_vno = 5;
814
815     ek.caddr = et.caddr;
816     if(et.caddr == NULL)
817         et.caddr = tgt->caddr;
818
819     {
820         time_t life;
821         life = et.endtime - *et.starttime;
822         if(client && client->entry.max_life)
823             life = min(life, *client->entry.max_life);
824         if(server->entry.max_life)
825             life = min(life, *server->entry.max_life);
826         et.endtime = *et.starttime + life;
827     }
828     if(f.renewable_ok && tgt->flags.renewable &&
829        et.renew_till == NULL && et.endtime < *b->till &&
830        tgt->renew_till != NULL)
831     {
832         et.flags.renewable = 1;
833         ALLOC(et.renew_till);
834         *et.renew_till = *b->till;
835     }
836     if(et.renew_till){
837         time_t renew;
838         renew = *et.renew_till - et.authtime;
839         if(client && client->entry.max_renew)
840             renew = min(renew, *client->entry.max_renew);
841         if(server->entry.max_renew)
842             renew = min(renew, *server->entry.max_renew);
843         *et.renew_till = et.authtime + renew;
844     }
845
846     if(et.renew_till){
847         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
848         *et.starttime = min(*et.starttime, *et.renew_till);
849         et.endtime = min(et.endtime, *et.renew_till);
850     }
851
852     *et.starttime = min(*et.starttime, et.endtime);
853
854     if(*et.starttime == et.endtime){
855         ret = KRB5KDC_ERR_NEVER_VALID;
856         goto out;
857     }
858     if(et.renew_till && et.endtime == *et.renew_till){
859         free(et.renew_till);
860         et.renew_till = NULL;
861         et.flags.renewable = 0;
862     }
863
864     et.flags.pre_authent = tgt->flags.pre_authent;
865     et.flags.hw_authent  = tgt->flags.hw_authent;
866     et.flags.anonymous   = tgt->flags.anonymous;
867     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
868
869     if(rspac->length) {
870         /*
871          * No not need to filter out the any PAC from the
872          * auth_data since it's signed by the KDC.
873          */
874         ret = _kdc_tkt_add_if_relevant_ad(context, &et,
875                                           KRB5_AUTHDATA_WIN2K_PAC, rspac);
876         if (ret)
877             goto out;
878     }
879
880     if (auth_data) {
881         unsigned int i = 0;
882
883         /* XXX check authdata */
884
885         if (et.authorization_data == NULL) {
886             et.authorization_data = calloc(1, sizeof(*et.authorization_data));
887             if (et.authorization_data == NULL) {
888                 ret = ENOMEM;
889                 krb5_set_error_message(context, ret, "malloc: out of memory");
890                 goto out;
891             }
892         }
893         for(i = 0; i < auth_data->len ; i++) {
894             ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
895             if (ret) {
896                 krb5_set_error_message(context, ret, "malloc: out of memory");
897                 goto out;
898             }
899         }
900
901         /* Filter out type KRB5SignedPath */
902         ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
903         if (ret == 0) {
904             if (et.authorization_data->len == 1) {
905                 free_AuthorizationData(et.authorization_data);
906                 free(et.authorization_data);
907                 et.authorization_data = NULL;
908             } else {
909                 AuthorizationData *ad = et.authorization_data;
910                 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
911                 ad->len--;
912             }
913         }
914     }
915
916     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
917     if (ret)
918         goto out;
919     et.crealm = tgt_name->realm;
920     et.cname = tgt_name->name;
921
922     ek.key = et.key;
923     /* MIT must have at least one last_req */
924     ek.last_req.len = 1;
925     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
926     if (ek.last_req.val == NULL) {
927         ret = ENOMEM;
928         goto out;
929     }
930     ek.nonce = b->nonce;
931     ek.flags = et.flags;
932     ek.authtime = et.authtime;
933     ek.starttime = et.starttime;
934     ek.endtime = et.endtime;
935     ek.renew_till = et.renew_till;
936     ek.srealm = rep.ticket.realm;
937     ek.sname = rep.ticket.sname;
938
939     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
940                        et.endtime, et.renew_till);
941
942     /* Don't sign cross realm tickets, they can't be checked anyway */
943     {
944         char *r = get_krbtgt_realm(&ek.sname);
945
946         if (r == NULL || strcmp(r, ek.srealm) == 0) {
947             ret = _kdc_add_KRB5SignedPath(context,
948                                           config,
949                                           krbtgt,
950                                           krbtgt_etype,
951                                           client_principal,
952                                           NULL,
953                                           spp,
954                                           &et);
955             if (ret)
956                 goto out;
957         }
958     }
959
960     if (enc_pa_data->len) {
961         rep.padata = calloc(1, sizeof(*rep.padata));
962         if (rep.padata == NULL) {
963             ret = ENOMEM;
964             goto out;
965         }
966         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
967         if (ret)
968             goto out;
969     }
970
971     if (krb5_enctype_valid(context, et.key.keytype) != 0
972         && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
973     {
974         krb5_enctype_enable(context, et.key.keytype);
975         is_weak = 1;
976     }
977
978
979     /* It is somewhat unclear where the etype in the following
980        encryption should come from. What we have is a session
981        key in the passed tgt, and a list of preferred etypes
982        *for the new ticket*. Should we pick the best possible
983        etype, given the keytype in the tgt, or should we look
984        at the etype list here as well?  What if the tgt
985        session key is DES3 and we want a ticket with a (say)
986        CAST session key. Should the DES3 etype be added to the
987        etype list, even if we don't want a session key with
988        DES3? */
989     ret = _kdc_encode_reply(context, config,
990                             &rep, &et, &ek, et.key.keytype,
991                             kvno,
992                             serverkey, 0, replykey, rk_is_subkey,
993                             e_text, reply);
994     if (is_weak)
995         krb5_enctype_disable(context, et.key.keytype);
996
997 out:
998     free_TGS_REP(&rep);
999     free_TransitedEncoding(&et.transited);
1000     if(et.starttime)
1001         free(et.starttime);
1002     if(et.renew_till)
1003         free(et.renew_till);
1004     if(et.authorization_data) {
1005         free_AuthorizationData(et.authorization_data);
1006         free(et.authorization_data);
1007     }
1008     free_LastReq(&ek.last_req);
1009     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1010     free_EncryptionKey(&et.key);
1011     return ret;
1012 }
1013
1014 static krb5_error_code
1015 tgs_check_authenticator(krb5_context context,
1016                         krb5_kdc_configuration *config,
1017                         krb5_auth_context ac,
1018                         KDC_REQ_BODY *b,
1019                         const char **e_text,
1020                         krb5_keyblock *key)
1021 {
1022     krb5_authenticator auth;
1023     size_t len = 0;
1024     unsigned char *buf;
1025     size_t buf_size;
1026     krb5_error_code ret;
1027     krb5_crypto crypto;
1028
1029     krb5_auth_con_getauthenticator(context, ac, &auth);
1030     if(auth->cksum == NULL){
1031         kdc_log(context, config, 0, "No authenticator in request");
1032         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1033         goto out;
1034     }
1035     /*
1036      * according to RFC1510 it doesn't need to be keyed,
1037      * but according to the latest draft it needs to.
1038      */
1039     if (
1040 #if 0
1041 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1042         ||
1043 #endif
1044  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1045         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1046                 auth->cksum->cksumtype);
1047         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1048         goto out;
1049     }
1050
1051     /* XXX should not re-encode this */
1052     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1053     if(ret){
1054         const char *msg = krb5_get_error_message(context, ret);
1055         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1056         krb5_free_error_message(context, msg);
1057         goto out;
1058     }
1059     if(buf_size != len) {
1060         free(buf);
1061         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1062         *e_text = "KDC internal error";
1063         ret = KRB5KRB_ERR_GENERIC;
1064         goto out;
1065     }
1066     ret = krb5_crypto_init(context, key, 0, &crypto);
1067     if (ret) {
1068         const char *msg = krb5_get_error_message(context, ret);
1069         free(buf);
1070         kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1071         krb5_free_error_message(context, msg);
1072         goto out;
1073     }
1074     ret = krb5_verify_checksum(context,
1075                                crypto,
1076                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
1077                                buf,
1078                                len,
1079                                auth->cksum);
1080     free(buf);
1081     krb5_crypto_destroy(context, crypto);
1082     if(ret){
1083         const char *msg = krb5_get_error_message(context, ret);
1084         kdc_log(context, config, 0,
1085                 "Failed to verify authenticator checksum: %s", msg);
1086         krb5_free_error_message(context, msg);
1087     }
1088 out:
1089     free_Authenticator(auth);
1090     free(auth);
1091     return ret;
1092 }
1093
1094 /*
1095  *
1096  */
1097
1098 static const char *
1099 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1100 {
1101     const char *new_realm = krb5_config_get_string(context,
1102                                                    NULL,
1103                                                    "capaths",
1104                                                    crealm,
1105                                                    srealm,
1106                                                    NULL);
1107     return new_realm;
1108 }
1109
1110
1111 static krb5_boolean
1112 need_referral(krb5_context context, krb5_kdc_configuration *config,
1113               const KDCOptions * const options, krb5_principal server,
1114               krb5_realm **realms)
1115 {
1116     const char *name;
1117
1118     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1119         return FALSE;
1120
1121     if (server->name.name_string.len == 1)
1122         name = server->name.name_string.val[0];
1123     else if (server->name.name_string.len == 3 &&
1124              strcasecmp("E3514235-4B06-11D1-AB04-00C04FC2DCD2", server->name.name_string.val[0]) == 0) {
1125         /*
1126           This is used to give referrals for the
1127           E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
1128           SPN form, which is used for inter-domain communication in AD
1129          */
1130         name = server->name.name_string.val[2];
1131         kdc_log(context, config, 0, "Giving 3 part DRSUAPI referral for %s", name);
1132         *realms = malloc(sizeof(char *)*2);
1133         if (*realms == NULL) {
1134             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1135             return FALSE;
1136         }
1137         (*realms)[0] = strdup(name);
1138         (*realms)[1] = NULL;
1139         return TRUE;
1140     } else if (server->name.name_string.len > 1)
1141         name = server->name.name_string.val[1];
1142     else
1143         return FALSE;
1144
1145     kdc_log(context, config, 0, "Searching referral for %s", name);
1146
1147     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1148 }
1149
1150 static krb5_error_code
1151 tgs_parse_request(krb5_context context,
1152                   krb5_kdc_configuration *config,
1153                   KDC_REQ_BODY *b,
1154                   const PA_DATA *tgs_req,
1155                   hdb_entry_ex **krbtgt,
1156                   krb5_enctype *krbtgt_etype,
1157                   krb5_ticket **ticket,
1158                   const char **e_text,
1159                   const char *from,
1160                   const struct sockaddr *from_addr,
1161                   time_t **csec,
1162                   int **cusec,
1163                   AuthorizationData **auth_data,
1164                   krb5_keyblock **replykey,
1165                   int *rk_is_subkey)
1166 {
1167     static char failed[] = "<unparse_name failed>";
1168     krb5_ap_req ap_req;
1169     krb5_error_code ret;
1170     krb5_principal princ;
1171     krb5_auth_context ac = NULL;
1172     krb5_flags ap_req_options;
1173     krb5_flags verify_ap_req_flags;
1174     krb5_crypto crypto;
1175     Key *tkey;
1176     krb5_keyblock *subkey = NULL;
1177     unsigned usage;
1178
1179     *auth_data = NULL;
1180     *csec  = NULL;
1181     *cusec = NULL;
1182     *replykey = NULL;
1183
1184     memset(&ap_req, 0, sizeof(ap_req));
1185     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1186     if(ret){
1187         const char *msg = krb5_get_error_message(context, ret);
1188         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1189         krb5_free_error_message(context, msg);
1190         goto out;
1191     }
1192
1193     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1194         /* XXX check for ticket.sname == req.sname */
1195         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1196         ret = KRB5KDC_ERR_POLICY; /* ? */
1197         goto out;
1198     }
1199
1200     _krb5_principalname2krb5_principal(context,
1201                                        &princ,
1202                                        ap_req.ticket.sname,
1203                                        ap_req.ticket.realm);
1204
1205     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
1206
1207     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1208         char *p;
1209         ret = krb5_unparse_name(context, princ, &p);
1210         if (ret != 0)
1211             p = failed;
1212         krb5_free_principal(context, princ);
1213         kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
1214         if (ret == 0)
1215             free(p);
1216         ret = HDB_ERR_NOT_FOUND_HERE;
1217         goto out;
1218     } else if(ret){
1219         const char *msg = krb5_get_error_message(context, ret);
1220         char *p;
1221         ret = krb5_unparse_name(context, princ, &p);
1222         if (ret != 0)
1223             p = failed;
1224         krb5_free_principal(context, princ);
1225         kdc_log(context, config, 0,
1226                 "Ticket-granting ticket not found in database: %s", msg);
1227         krb5_free_error_message(context, msg);
1228         if (ret == 0)
1229             free(p);
1230         ret = KRB5KRB_AP_ERR_NOT_US;
1231         goto out;
1232     }
1233
1234     if(ap_req.ticket.enc_part.kvno &&
1235        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1236         char *p;
1237
1238         ret = krb5_unparse_name (context, princ, &p);
1239         krb5_free_principal(context, princ);
1240         if (ret != 0)
1241             p = failed;
1242         kdc_log(context, config, 0,
1243                 "Ticket kvno = %d, DB kvno = %d (%s)",
1244                 *ap_req.ticket.enc_part.kvno,
1245                 (*krbtgt)->entry.kvno,
1246                 p);
1247         if (ret == 0)
1248             free (p);
1249         ret = KRB5KRB_AP_ERR_BADKEYVER;
1250         goto out;
1251     }
1252
1253     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1254
1255     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1256                           ap_req.ticket.enc_part.etype, &tkey);
1257     if(ret){
1258         char *str = NULL, *p = NULL;
1259
1260         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1261         krb5_unparse_name(context, princ, &p);
1262         kdc_log(context, config, 0,
1263                 "No server key with enctype %s found for %s",
1264                 str ? str : "<unknown enctype>",
1265                 p ? p : "<unparse_name failed>");
1266         free(str);
1267         free(p);
1268         ret = KRB5KRB_AP_ERR_BADKEYVER;
1269         goto out;
1270     }
1271
1272     if (b->kdc_options.validate)
1273         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1274     else
1275         verify_ap_req_flags = 0;
1276
1277     ret = krb5_verify_ap_req2(context,
1278                               &ac,
1279                               &ap_req,
1280                               princ,
1281                               &tkey->key,
1282                               verify_ap_req_flags,
1283                               &ap_req_options,
1284                               ticket,
1285                               KRB5_KU_TGS_REQ_AUTH);
1286
1287     krb5_free_principal(context, princ);
1288     if(ret) {
1289         const char *msg = krb5_get_error_message(context, ret);
1290         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1291         krb5_free_error_message(context, msg);
1292         goto out;
1293     }
1294
1295     {
1296         krb5_authenticator auth;
1297
1298         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1299         if (ret == 0) {
1300             *csec   = malloc(sizeof(**csec));
1301             if (*csec == NULL) {
1302                 krb5_free_authenticator(context, &auth);
1303                 kdc_log(context, config, 0, "malloc failed");
1304                 goto out;
1305             }
1306             **csec  = auth->ctime;
1307             *cusec  = malloc(sizeof(**cusec));
1308             if (*cusec == NULL) {
1309                 krb5_free_authenticator(context, &auth);
1310                 kdc_log(context, config, 0, "malloc failed");
1311                 goto out;
1312             }
1313             **cusec  = auth->cusec;
1314             krb5_free_authenticator(context, &auth);
1315         }
1316     }
1317
1318     ret = tgs_check_authenticator(context, config,
1319                                   ac, b, e_text, &(*ticket)->ticket.key);
1320     if (ret) {
1321         krb5_auth_con_free(context, ac);
1322         goto out;
1323     }
1324
1325     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1326     *rk_is_subkey = 1;
1327
1328     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1329     if(ret){
1330         const char *msg = krb5_get_error_message(context, ret);
1331         krb5_auth_con_free(context, ac);
1332         kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1333         krb5_free_error_message(context, msg);
1334         goto out;
1335     }
1336     if(subkey == NULL){
1337         usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1338         *rk_is_subkey = 0;
1339
1340         ret = krb5_auth_con_getkey(context, ac, &subkey);
1341         if(ret) {
1342             const char *msg = krb5_get_error_message(context, ret);
1343             krb5_auth_con_free(context, ac);
1344             kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1345             krb5_free_error_message(context, msg);
1346             goto out;
1347         }
1348     }
1349     if(subkey == NULL){
1350         krb5_auth_con_free(context, ac);
1351         kdc_log(context, config, 0,
1352                 "Failed to get key for enc-authorization-data");
1353         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1354         goto out;
1355     }
1356
1357     *replykey = subkey;
1358
1359     if (b->enc_authorization_data) {
1360         krb5_data ad;
1361
1362         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1363         if (ret) {
1364             const char *msg = krb5_get_error_message(context, ret);
1365             krb5_auth_con_free(context, ac);
1366             kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1367             krb5_free_error_message(context, msg);
1368             goto out;
1369         }
1370         ret = krb5_decrypt_EncryptedData (context,
1371                                           crypto,
1372                                           usage,
1373                                           b->enc_authorization_data,
1374                                           &ad);
1375         krb5_crypto_destroy(context, crypto);
1376         if(ret){
1377             krb5_auth_con_free(context, ac);
1378             kdc_log(context, config, 0,
1379                     "Failed to decrypt enc-authorization-data");
1380             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1381             goto out;
1382         }
1383         ALLOC(*auth_data);
1384         if (*auth_data == NULL) {
1385             krb5_auth_con_free(context, ac);
1386             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1387             goto out;
1388         }
1389         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1390         if(ret){
1391             krb5_auth_con_free(context, ac);
1392             free(*auth_data);
1393             *auth_data = NULL;
1394             kdc_log(context, config, 0, "Failed to decode authorization data");
1395             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1396             goto out;
1397         }
1398     }
1399
1400     krb5_auth_con_free(context, ac);
1401
1402 out:
1403     free_AP_REQ(&ap_req);
1404
1405     return ret;
1406 }
1407
1408 static krb5_error_code
1409 build_server_referral(krb5_context context,
1410                       krb5_kdc_configuration *config,
1411                       krb5_crypto session,
1412                       krb5_const_realm referred_realm,
1413                       const PrincipalName *true_principal_name,
1414                       const PrincipalName *requested_principal,
1415                       krb5_data *outdata)
1416 {
1417     PA_ServerReferralData ref;
1418     krb5_error_code ret;
1419     EncryptedData ed;
1420     krb5_data data;
1421     size_t size = 0;
1422
1423     memset(&ref, 0, sizeof(ref));
1424
1425     if (referred_realm) {
1426         ALLOC(ref.referred_realm);
1427         if (ref.referred_realm == NULL)
1428             goto eout;
1429         *ref.referred_realm = strdup(referred_realm);
1430         if (*ref.referred_realm == NULL)
1431             goto eout;
1432     }
1433     if (true_principal_name) {
1434         ALLOC(ref.true_principal_name);
1435         if (ref.true_principal_name == NULL)
1436             goto eout;
1437         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1438         if (ret)
1439             goto eout;
1440     }
1441     if (requested_principal) {
1442         ALLOC(ref.requested_principal_name);
1443         if (ref.requested_principal_name == NULL)
1444             goto eout;
1445         ret = copy_PrincipalName(requested_principal,
1446                                  ref.requested_principal_name);
1447         if (ret)
1448             goto eout;
1449     }
1450
1451     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1452                        data.data, data.length,
1453                        &ref, &size, ret);
1454     free_PA_ServerReferralData(&ref);
1455     if (ret)
1456         return ret;
1457     if (data.length != size)
1458         krb5_abortx(context, "internal asn.1 encoder error");
1459
1460     ret = krb5_encrypt_EncryptedData(context, session,
1461                                      KRB5_KU_PA_SERVER_REFERRAL,
1462                                      data.data, data.length,
1463                                      0 /* kvno */, &ed);
1464     free(data.data);
1465     if (ret)
1466         return ret;
1467
1468     ASN1_MALLOC_ENCODE(EncryptedData,
1469                        outdata->data, outdata->length,
1470                        &ed, &size, ret);
1471     free_EncryptedData(&ed);
1472     if (ret)
1473         return ret;
1474     if (outdata->length != size)
1475         krb5_abortx(context, "internal asn.1 encoder error");
1476
1477     return 0;
1478 eout:
1479     free_PA_ServerReferralData(&ref);
1480     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1481     return ENOMEM;
1482 }
1483
1484 static krb5_error_code
1485 tgs_build_reply(krb5_context context,
1486                 krb5_kdc_configuration *config,
1487                 KDC_REQ *req,
1488                 KDC_REQ_BODY *b,
1489                 hdb_entry_ex *krbtgt,
1490                 krb5_enctype krbtgt_etype,
1491                 const krb5_keyblock *replykey,
1492                 int rk_is_subkey,
1493                 krb5_ticket *ticket,
1494                 krb5_data *reply,
1495                 const char *from,
1496                 const char **e_text,
1497                 AuthorizationData **auth_data,
1498                 const struct sockaddr *from_addr)
1499 {
1500     krb5_error_code ret;
1501     krb5_principal cp = NULL, sp = NULL, tp = NULL, dp = NULL;
1502     krb5_principal krbtgt_principal = NULL;
1503     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1504     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1505     HDB *clientdb, *s4u2self_impersonated_clientdb;
1506     krb5_realm ref_realm = NULL;
1507     EncTicketPart *tgt = &ticket->ticket;
1508     krb5_principals spp = NULL;
1509     const EncryptionKey *ekey;
1510     krb5_keyblock sessionkey;
1511     krb5_kvno kvno;
1512     krb5_data rspac;
1513
1514     hdb_entry_ex *krbtgt_out = NULL;
1515
1516     METHOD_DATA enc_pa_data;
1517
1518     PrincipalName *s;
1519     Realm r;
1520     int nloop = 0;
1521     EncTicketPart adtkt;
1522     char opt_str[128];
1523     int signedpath = 0;
1524
1525     Key *tkey_check;
1526     Key *tkey_sign;
1527     int flags = HDB_F_FOR_TGS_REQ;
1528
1529     memset(&sessionkey, 0, sizeof(sessionkey));
1530     memset(&adtkt, 0, sizeof(adtkt));
1531     krb5_data_zero(&rspac);
1532     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1533
1534     s = b->sname;
1535     r = b->realm;
1536
1537     if (b->kdc_options.canonicalize)
1538         flags |= HDB_F_CANON;
1539
1540     if(b->kdc_options.enc_tkt_in_skey){
1541         Ticket *t;
1542         hdb_entry_ex *uu;
1543         krb5_principal p;
1544         Key *uukey;
1545
1546         if(b->additional_tickets == NULL ||
1547            b->additional_tickets->len == 0){
1548             ret = KRB5KDC_ERR_BADOPTION; /* ? */
1549             kdc_log(context, config, 0,
1550                     "No second ticket present in request");
1551             goto out;
1552         }
1553         t = &b->additional_tickets->val[0];
1554         if(!get_krbtgt_realm(&t->sname)){
1555             kdc_log(context, config, 0,
1556                     "Additional ticket is not a ticket-granting ticket");
1557             ret = KRB5KDC_ERR_POLICY;
1558             goto out;
1559         }
1560         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1561         ret = _kdc_db_fetch(context, config, p,
1562                             HDB_F_GET_KRBTGT, t->enc_part.kvno,
1563                             NULL, &uu);
1564         krb5_free_principal(context, p);
1565         if(ret){
1566             if (ret == HDB_ERR_NOENTRY)
1567                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1568             goto out;
1569         }
1570         ret = hdb_enctype2key(context, &uu->entry,
1571                               t->enc_part.etype, &uukey);
1572         if(ret){
1573             _kdc_free_ent(context, uu);
1574             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1575             goto out;
1576         }
1577         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1578         _kdc_free_ent(context, uu);
1579         if(ret)
1580             goto out;
1581
1582         ret = verify_flags(context, config, &adtkt, spn);
1583         if (ret)
1584             goto out;
1585
1586         s = &adtkt.cname;
1587         r = adtkt.crealm;
1588     }
1589
1590     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1591     ret = krb5_unparse_name(context, sp, &spn);
1592     if (ret)
1593         goto out;
1594     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1595     ret = krb5_unparse_name(context, cp, &cpn);
1596     if (ret)
1597         goto out;
1598     unparse_flags (KDCOptions2int(b->kdc_options),
1599                    asn1_KDCOptions_units(),
1600                    opt_str, sizeof(opt_str));
1601     if(*opt_str)
1602         kdc_log(context, config, 0,
1603                 "TGS-REQ %s from %s for %s [%s]",
1604                 cpn, from, spn, opt_str);
1605     else
1606         kdc_log(context, config, 0,
1607                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1608
1609     /*
1610      * Fetch server
1611      */
1612
1613 server_lookup:
1614     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1615                         NULL, NULL, &server);
1616
1617     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1618         kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1619         goto out;
1620     } else if(ret){
1621         const char *new_rlm, *msg;
1622         Realm req_rlm;
1623         krb5_realm *realms;
1624
1625         if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1626             if(nloop++ < 2) {
1627                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1628                 if(new_rlm) {
1629                     kdc_log(context, config, 5, "krbtgt for realm %s "
1630                             "not found, trying %s",
1631                             req_rlm, new_rlm);
1632                     krb5_free_principal(context, sp);
1633                     free(spn);
1634                     krb5_make_principal(context, &sp, r,
1635                                         KRB5_TGS_NAME, new_rlm, NULL);
1636                     ret = krb5_unparse_name(context, sp, &spn);
1637                     if (ret)
1638                         goto out;
1639
1640                     if (ref_realm)
1641                         free(ref_realm);
1642                     ref_realm = strdup(new_rlm);
1643                     goto server_lookup;
1644                 }
1645             }
1646         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1647             if (strcmp(realms[0], sp->realm) != 0) {
1648                 kdc_log(context, config, 5,
1649                         "Returning a referral to realm %s for "
1650                         "server %s that was not found",
1651                         realms[0], spn);
1652                 krb5_free_principal(context, sp);
1653                 free(spn);
1654                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1655                                     realms[0], NULL);
1656                 ret = krb5_unparse_name(context, sp, &spn);
1657                 if (ret)
1658                     goto out;
1659
1660                 if (ref_realm)
1661                     free(ref_realm);
1662                 ref_realm = strdup(realms[0]);
1663
1664                 krb5_free_host_realm(context, realms);
1665                 goto server_lookup;
1666             }
1667             krb5_free_host_realm(context, realms);
1668         }
1669         msg = krb5_get_error_message(context, ret);
1670         kdc_log(context, config, 0,
1671                 "Server not found in database: %s: %s", spn, msg);
1672         krb5_free_error_message(context, msg);
1673         if (ret == HDB_ERR_NOENTRY)
1674             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1675         goto out;
1676     }
1677
1678     /*
1679      * Select enctype, return key and kvno.
1680      */
1681
1682     {
1683         krb5_enctype etype;
1684
1685         if(b->kdc_options.enc_tkt_in_skey) {
1686             size_t i;
1687             ekey = &adtkt.key;
1688             for(i = 0; i < b->etype.len; i++)
1689                 if (b->etype.val[i] == adtkt.key.keytype)
1690                     break;
1691             if(i == b->etype.len) {
1692                 kdc_log(context, config, 0,
1693                         "Addition ticket have not matching etypes");
1694                 krb5_clear_error_message(context);
1695                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1696                 goto out;
1697             }
1698             etype = b->etype.val[i];
1699             kvno = 0;
1700         } else {
1701             Key *skey;
1702
1703             ret = _kdc_find_etype(context,
1704                                   config->tgs_use_strongest_session_key, FALSE,
1705                                   server, b->etype.val, b->etype.len, NULL,
1706                                   &skey);
1707             if(ret) {
1708                 kdc_log(context, config, 0,
1709                         "Server (%s) has no support for etypes", spn);
1710                 goto out;
1711             }
1712             ekey = &skey->key;
1713             etype = skey->key.keytype;
1714             kvno = server->entry.kvno;
1715         }
1716
1717         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1718         if (ret)
1719             goto out;
1720     }
1721
1722     /*
1723      * Check that service is in the same realm as the krbtgt. If it's
1724      * not the same, it's someone that is using a uni-directional trust
1725      * backward.
1726      */
1727
1728     /*
1729      * Validate authoriation data
1730      */
1731
1732     ret = hdb_enctype2key(context, &krbtgt->entry,
1733                           krbtgt_etype, &tkey_check);
1734     if(ret) {
1735         kdc_log(context, config, 0,
1736                     "Failed to find key for krbtgt PAC check");
1737         goto out;
1738     }
1739
1740     /* Now refetch the primary krbtgt, and get the current kvno (the
1741      * sign check may have been on an old kvno, and the server may
1742      * have been an incoming trust) */
1743     ret = krb5_make_principal(context, &krbtgt_principal,
1744                               krb5_principal_get_comp_string(context,
1745                                                              krbtgt->entry.principal,
1746                                                              1),
1747                               KRB5_TGS_NAME,
1748                               krb5_principal_get_comp_string(context,
1749                                                              krbtgt->entry.principal,
1750                                                              1), NULL);
1751     if(ret) {
1752         kdc_log(context, config, 0,
1753                     "Failed to generate krbtgt principal");
1754         goto out;
1755     }
1756
1757     ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1758     krb5_free_principal(context, krbtgt_principal);
1759     if (ret) {
1760         krb5_error_code ret2;
1761         char *ktpn, *ktpn2;
1762         ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1763         ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1764         kdc_log(context, config, 0,
1765                 "Request with wrong krbtgt: %s, %s not found in our database",
1766                 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1767         if(ret == 0)
1768             free(ktpn);
1769         if(ret2 == 0)
1770             free(ktpn2);
1771         ret = KRB5KRB_AP_ERR_NOT_US;
1772         goto out;
1773     }
1774
1775     /* The first realm is the realm of the service, the second is
1776      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1777      * encrypted to.  The redirection via the krbtgt_out entry allows
1778      * the DB to possibly correct the case of the realm (Samba4 does
1779      * this) before the strcmp() */
1780     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1781                krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1782         char *ktpn;
1783         ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1784         kdc_log(context, config, 0,
1785                 "Request with wrong krbtgt: %s",
1786                 (ret == 0) ? ktpn : "<unknown>");
1787         if(ret == 0)
1788             free(ktpn);
1789         ret = KRB5KRB_AP_ERR_NOT_US;
1790     }
1791
1792     ret = hdb_enctype2key(context, &krbtgt_out->entry,
1793                           krbtgt_etype, &tkey_sign);
1794     if(ret) {
1795         kdc_log(context, config, 0,
1796                     "Failed to find key for krbtgt PAC signature");
1797         goto out;
1798     }
1799
1800     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1801                         NULL, &clientdb, &client);
1802     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1803         /* This is OK, we are just trying to find out if they have
1804          * been disabled or deleted in the meantime, missing secrets
1805          * is OK */
1806     } else if(ret){
1807         const char *krbtgt_realm, *msg;
1808
1809         /*
1810          * If the client belongs to the same realm as our krbtgt, it
1811          * should exist in the local database.
1812          *
1813          */
1814
1815         krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1816
1817         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1818             if (ret == HDB_ERR_NOENTRY)
1819                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1820             kdc_log(context, config, 1, "Client no longer in database: %s",
1821                     cpn);
1822             goto out;
1823         }
1824
1825         msg = krb5_get_error_message(context, ret);
1826         kdc_log(context, config, 1, "Client not found in database: %s", msg);
1827         krb5_free_error_message(context, msg);
1828     }
1829
1830     ret = check_PAC(context, config, cp, NULL,
1831                     client, server, krbtgt,
1832                     &tkey_check->key,
1833                     ekey, &tkey_sign->key,
1834                     tgt, &rspac, &signedpath);
1835     if (ret) {
1836         const char *msg = krb5_get_error_message(context, ret);
1837         kdc_log(context, config, 0,
1838                 "Verify PAC failed for %s (%s) from %s with %s",
1839                 spn, cpn, from, msg);
1840         krb5_free_error_message(context, msg);
1841         goto out;
1842     }
1843
1844     /* also check the krbtgt for signature */
1845     ret = check_KRB5SignedPath(context,
1846                                config,
1847                                krbtgt,
1848                                cp,
1849                                tgt,
1850                                &spp,
1851                                &signedpath);
1852     if (ret) {
1853         const char *msg = krb5_get_error_message(context, ret);
1854         kdc_log(context, config, 0,
1855                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1856                 spn, cpn, from, msg);
1857         krb5_free_error_message(context, msg);
1858         goto out;
1859     }
1860
1861     /*
1862      * Process request
1863      */
1864
1865     /* by default the tgt principal matches the client principal */
1866     tp = cp;
1867     tpn = cpn;
1868
1869     if (client) {
1870         const PA_DATA *sdata;
1871         int i = 0;
1872
1873         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1874         if (sdata) {
1875             krb5_crypto crypto;
1876             krb5_data datack;
1877             PA_S4U2Self self;
1878             const char *str;
1879
1880             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1881                                      sdata->padata_value.length,
1882                                      &self, NULL);
1883             if (ret) {
1884                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1885                 goto out;
1886             }
1887
1888             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1889             if (ret)
1890                 goto out;
1891
1892             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1893             if (ret) {
1894                 const char *msg = krb5_get_error_message(context, ret);
1895                 free_PA_S4U2Self(&self);
1896                 krb5_data_free(&datack);
1897                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1898                 krb5_free_error_message(context, msg);
1899                 goto out;
1900             }
1901
1902             ret = krb5_verify_checksum(context,
1903                                        crypto,
1904                                        KRB5_KU_OTHER_CKSUM,
1905                                        datack.data,
1906                                        datack.length,
1907                                        &self.cksum);
1908             krb5_data_free(&datack);
1909             krb5_crypto_destroy(context, crypto);
1910             if (ret) {
1911                 const char *msg = krb5_get_error_message(context, ret);
1912                 free_PA_S4U2Self(&self);
1913                 kdc_log(context, config, 0,
1914                         "krb5_verify_checksum failed for S4U2Self: %s", msg);
1915                 krb5_free_error_message(context, msg);
1916                 goto out;
1917             }
1918
1919             ret = _krb5_principalname2krb5_principal(context,
1920                                                      &tp,
1921                                                      self.name,
1922                                                      self.realm);
1923             free_PA_S4U2Self(&self);
1924             if (ret)
1925                 goto out;
1926
1927             ret = krb5_unparse_name(context, tp, &tpn);
1928             if (ret)
1929                 goto out;
1930
1931             /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1932             if(rspac.data) {
1933                 krb5_pac p = NULL;
1934                 krb5_data_free(&rspac);
1935                 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1936                                     NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1937                 if (ret) {
1938                     const char *msg;
1939
1940                     /*
1941                      * If the client belongs to the same realm as our krbtgt, it
1942                      * should exist in the local database.
1943                      *
1944                      */
1945
1946                     if (ret == HDB_ERR_NOENTRY)
1947                         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1948                     msg = krb5_get_error_message(context, ret);
1949                     kdc_log(context, config, 1,
1950                             "S2U4Self principal to impersonate %s not found in database: %s",
1951                             tpn, msg);
1952                     krb5_free_error_message(context, msg);
1953                     goto out;
1954                 }
1955                 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1956                 if (ret) {
1957                     kdc_log(context, config, 0, "PAC generation failed for -- %s",
1958                             tpn);
1959                     goto out;
1960                 }
1961                 if (p != NULL) {
1962                     ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1963                                          s4u2self_impersonated_client->entry.principal,
1964                                          ekey, &tkey_sign->key,
1965                                          &rspac);
1966                     krb5_pac_free(context, p);
1967                     if (ret) {
1968                         kdc_log(context, config, 0, "PAC signing failed for -- %s",
1969                                 tpn);
1970                         goto out;
1971                     }
1972                 }
1973             }
1974
1975             /*
1976              * Check that service doing the impersonating is
1977              * requesting a ticket to it-self.
1978              */
1979             ret = check_s4u2self(context, config, clientdb, client, sp);
1980             if (ret) {
1981                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1982                         "to impersonate to service "
1983                         "(tried for user %s to service %s)",
1984                         cpn, tpn, spn);
1985                 goto out;
1986             }
1987
1988             /*
1989              * If the service isn't trusted for authentication to
1990              * delegation, remove the forward flag.
1991              */
1992
1993             if (client->entry.flags.trusted_for_delegation) {
1994                 str = "[forwardable]";
1995             } else {
1996                 b->kdc_options.forwardable = 0;
1997                 str = "";
1998             }
1999             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2000                     "service %s %s", cpn, tpn, spn, str);
2001         }
2002     }
2003
2004     /*
2005      * Constrained delegation
2006      */
2007
2008     if (client != NULL
2009         && b->additional_tickets != NULL
2010         && b->additional_tickets->len != 0
2011         && b->kdc_options.enc_tkt_in_skey == 0)
2012     {
2013         int ad_signedpath = 0;
2014         Key *clientkey;
2015         Ticket *t;
2016
2017         /*
2018          * Require that the KDC have issued the service's krbtgt (not
2019          * self-issued ticket with kimpersonate(1).
2020          */
2021         if (!signedpath) {
2022             ret = KRB5KDC_ERR_BADOPTION;
2023             kdc_log(context, config, 0,
2024                     "Constrained delegation done on service ticket %s/%s",
2025                     cpn, spn);
2026             goto out;
2027         }
2028
2029         t = &b->additional_tickets->val[0];
2030
2031         ret = hdb_enctype2key(context, &client->entry,
2032                               t->enc_part.etype, &clientkey);
2033         if(ret){
2034             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2035             goto out;
2036         }
2037
2038         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2039         if (ret) {
2040             kdc_log(context, config, 0,
2041                     "failed to decrypt ticket for "
2042                     "constrained delegation from %s to %s ", cpn, spn);
2043             goto out;
2044         }
2045
2046         ret = _krb5_principalname2krb5_principal(context,
2047                                                  &tp,
2048                                                  adtkt.cname,
2049                                                  adtkt.crealm);
2050         if (ret)
2051             goto out;
2052
2053         ret = krb5_unparse_name(context, tp, &tpn);
2054         if (ret)
2055             goto out;
2056
2057         ret = _krb5_principalname2krb5_principal(context,
2058                                                  &dp,
2059                                                  t->sname,
2060                                                  t->realm);
2061         if (ret)
2062             goto out;
2063
2064         ret = krb5_unparse_name(context, dp, &dpn);
2065         if (ret)
2066             goto out;
2067
2068         /* check that ticket is valid */
2069         if (adtkt.flags.forwardable == 0) {
2070             kdc_log(context, config, 0,
2071                     "Missing forwardable flag on ticket for "
2072                     "constrained delegation from %s (%s) as %s to %s ",
2073                     cpn, dpn, tpn, spn);
2074             ret = KRB5KDC_ERR_BADOPTION;
2075             goto out;
2076         }
2077
2078         ret = check_constrained_delegation(context, config, clientdb,
2079                                            client, server, sp);
2080         if (ret) {
2081             kdc_log(context, config, 0,
2082                     "constrained delegation from %s (%s) as %s to %s not allowed",
2083                     cpn, dpn, tpn, spn);
2084             goto out;
2085         }
2086
2087         ret = verify_flags(context, config, &adtkt, tpn);
2088         if (ret) {
2089             goto out;
2090         }
2091
2092         krb5_data_free(&rspac);
2093
2094         /*
2095          * generate the PAC for the user.
2096          *
2097          * TODO: pass in t->sname and t->realm and build
2098          * a S4U_DELEGATION_INFO blob to the PAC.
2099          */
2100         ret = check_PAC(context, config, tp, dp,
2101                         client, server, krbtgt,
2102                         &clientkey->key,
2103                         ekey, &tkey_sign->key,
2104                         &adtkt, &rspac, &ad_signedpath);
2105         if (ret) {
2106             const char *msg = krb5_get_error_message(context, ret);
2107             kdc_log(context, config, 0,
2108                     "Verify delegated PAC failed to %s for client"
2109                     "%s (%s) as %s from %s with %s",
2110                     spn, cpn, dpn, tpn, from, msg);
2111             krb5_free_error_message(context, msg);
2112             goto out;
2113         }
2114
2115         /*
2116          * Check that the KDC issued the user's ticket.
2117          */
2118         ret = check_KRB5SignedPath(context,
2119                                    config,
2120                                    krbtgt,
2121                                    cp,
2122                                    &adtkt,
2123                                    NULL,
2124                                    &ad_signedpath);
2125         if (ret) {
2126             const char *msg = krb5_get_error_message(context, ret);
2127             kdc_log(context, config, 0,
2128                     "KRB5SignedPath check from service %s failed "
2129                     "for delegation to %s for client %s (%s)"
2130                     "from %s failed with %s",
2131                     spn, tpn, dpn, cpn, from, msg);
2132             krb5_free_error_message(context, msg);
2133             goto out;
2134         }
2135
2136         if (!ad_signedpath) {
2137             ret = KRB5KDC_ERR_BADOPTION;
2138             kdc_log(context, config, 0,
2139                     "Ticket not signed with PAC nor SignedPath service %s failed "
2140                     "for delegation to %s for client %s (%s)"
2141                     "from %s",
2142                     spn, tpn, dpn, cpn, from);
2143             goto out;
2144         }
2145
2146         kdc_log(context, config, 0, "constrained delegation for %s "
2147                 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2148     }
2149
2150     /*
2151      * Check flags
2152      */
2153
2154     ret = kdc_check_flags(context, config,
2155                           client, cpn,
2156                           server, spn,
2157                           FALSE);
2158     if(ret)
2159         goto out;
2160
2161     if((b->kdc_options.validate || b->kdc_options.renew) &&
2162        !krb5_principal_compare(context,
2163                                krbtgt->entry.principal,
2164                                server->entry.principal)){
2165         kdc_log(context, config, 0, "Inconsistent request.");
2166         ret = KRB5KDC_ERR_SERVER_NOMATCH;
2167         goto out;
2168     }
2169
2170     /* check for valid set of addresses */
2171     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2172         ret = KRB5KRB_AP_ERR_BADADDR;
2173         kdc_log(context, config, 0, "Request from wrong address");
2174         goto out;
2175     }
2176
2177     /*
2178      * If this is an referral, add server referral data to the
2179      * auth_data reply .
2180      */
2181     if (ref_realm) {
2182         PA_DATA pa;
2183         krb5_crypto crypto;
2184
2185         kdc_log(context, config, 0,
2186                 "Adding server referral to %s", ref_realm);
2187
2188         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2189         if (ret)
2190             goto out;
2191
2192         ret = build_server_referral(context, config, crypto, ref_realm,
2193                                     NULL, s, &pa.padata_value);
2194         krb5_crypto_destroy(context, crypto);
2195         if (ret) {
2196             kdc_log(context, config, 0,
2197                     "Failed building server referral");
2198             goto out;
2199         }
2200         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2201
2202         ret = add_METHOD_DATA(&enc_pa_data, &pa);
2203         krb5_data_free(&pa.padata_value);
2204         if (ret) {
2205             kdc_log(context, config, 0,
2206                     "Add server referral METHOD-DATA failed");
2207             goto out;
2208         }
2209     }
2210
2211     /*
2212      *
2213      */
2214
2215     ret = tgs_make_reply(context,
2216                          config,
2217                          b,
2218                          tp,
2219                          tgt,
2220                          replykey,
2221                          rk_is_subkey,
2222                          ekey,
2223                          &sessionkey,
2224                          kvno,
2225                          *auth_data,
2226                          server,
2227                          server->entry.principal,
2228                          spn,
2229                          client,
2230                          cp,
2231                          krbtgt_out,
2232                          krbtgt_etype,
2233                          spp,
2234                          &rspac,
2235                          &enc_pa_data,
2236                          e_text,
2237                          reply);
2238
2239 out:
2240     if (tpn != cpn)
2241             free(tpn);
2242     free(spn);
2243     free(cpn);
2244     if (dpn)
2245         free(dpn);
2246
2247     krb5_data_free(&rspac);
2248     krb5_free_keyblock_contents(context, &sessionkey);
2249     if(krbtgt_out)
2250         _kdc_free_ent(context, krbtgt_out);
2251     if(server)
2252         _kdc_free_ent(context, server);
2253     if(client)
2254         _kdc_free_ent(context, client);
2255     if(s4u2self_impersonated_client)
2256         _kdc_free_ent(context, s4u2self_impersonated_client);
2257
2258     if (tp && tp != cp)
2259         krb5_free_principal(context, tp);
2260     if (cp)
2261         krb5_free_principal(context, cp);
2262     if (dp)
2263         krb5_free_principal(context, dp);
2264     if (sp)
2265         krb5_free_principal(context, sp);
2266     if (ref_realm)
2267         free(ref_realm);
2268     free_METHOD_DATA(&enc_pa_data);
2269
2270     free_EncTicketPart(&adtkt);
2271
2272     return ret;
2273 }
2274
2275 /*
2276  *
2277  */
2278
2279 krb5_error_code
2280 _kdc_tgs_rep(krb5_context context,
2281              krb5_kdc_configuration *config,
2282              KDC_REQ *req,
2283              krb5_data *data,
2284              const char *from,
2285              struct sockaddr *from_addr,
2286              int datagram_reply)
2287 {
2288     AuthorizationData *auth_data = NULL;
2289     krb5_error_code ret;
2290     int i = 0;
2291     const PA_DATA *tgs_req;
2292
2293     hdb_entry_ex *krbtgt = NULL;
2294     krb5_ticket *ticket = NULL;
2295     const char *e_text = NULL;
2296     krb5_enctype krbtgt_etype = ETYPE_NULL;
2297
2298     krb5_keyblock *replykey = NULL;
2299     int rk_is_subkey = 0;
2300     time_t *csec = NULL;
2301     int *cusec = NULL;
2302
2303     if(req->padata == NULL){
2304         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2305         kdc_log(context, config, 0,
2306                 "TGS-REQ from %s without PA-DATA", from);
2307         goto out;
2308     }
2309
2310     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2311
2312     if(tgs_req == NULL){
2313         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2314
2315         kdc_log(context, config, 0,
2316                 "TGS-REQ from %s without PA-TGS-REQ", from);
2317         goto out;
2318     }
2319     ret = tgs_parse_request(context, config,
2320                             &req->req_body, tgs_req,
2321                             &krbtgt,
2322                             &krbtgt_etype,
2323                             &ticket,
2324                             &e_text,
2325                             from, from_addr,
2326                             &csec, &cusec,
2327                             &auth_data,
2328                             &replykey,
2329                             &rk_is_subkey);
2330     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2331         /* kdc_log() is called in tgs_parse_request() */
2332         goto out;
2333     }
2334     if (ret) {
2335         kdc_log(context, config, 0,
2336                 "Failed parsing TGS-REQ from %s", from);
2337         goto out;
2338     }
2339
2340     ret = tgs_build_reply(context,
2341                           config,
2342                           req,
2343                           &req->req_body,
2344                           krbtgt,
2345                           krbtgt_etype,
2346                           replykey,
2347                           rk_is_subkey,
2348                           ticket,
2349                           data,
2350                           from,
2351                           &e_text,
2352                           &auth_data,
2353                           from_addr);
2354     if (ret) {
2355         kdc_log(context, config, 0,
2356                 "Failed building TGS-REP to %s", from);
2357         goto out;
2358     }
2359
2360     /* */
2361     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2362         krb5_data_free(data);
2363         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2364         e_text = "Reply packet too large";
2365     }
2366
2367 out:
2368     if (replykey)
2369         krb5_free_keyblock(context, replykey);
2370     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2371         krb5_mk_error(context,
2372                       ret,
2373                       NULL,
2374                       NULL,
2375                       NULL,
2376                       NULL,
2377                       csec,
2378                       cusec,
2379                       data);
2380         ret = 0;
2381     }
2382     free(csec);
2383     free(cusec);
2384     if (ticket)
2385         krb5_free_ticket(context, ticket);
2386     if(krbtgt)
2387         _kdc_free_ent(context, krbtgt);
2388
2389     if (auth_data) {
2390         free_AuthorizationData(auth_data);
2391         free(auth_data);
2392     }
2393
2394     return ret;
2395 }