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