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