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