f59f99f369f5641c36060a0249df95b1cd266819
[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     krb5_principal user2user_princ = NULL;
1306     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1307     char *user2user_name = NULL;
1308     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1309     HDB *clientdb, *s4u2self_impersonated_clientdb;
1310     HDB *serverdb = NULL;
1311     krb5_realm ref_realm = NULL;
1312     EncTicketPart *tgt = &ticket->ticket;
1313     const char *tgt_realm = /* Realm of TGT issuer */
1314         krb5_principal_get_realm(context, krbtgt->entry.principal);
1315     const EncryptionKey *ekey;
1316     krb5_keyblock sessionkey;
1317     krb5_kvno kvno;
1318     krb5_pac mspac = NULL;
1319     uint16_t rodc_id;
1320     krb5_boolean add_ticket_sig = FALSE;
1321     hdb_entry_ex *krbtgt_out = NULL;
1322
1323     METHOD_DATA enc_pa_data;
1324
1325     PrincipalName *s;
1326     Realm r;
1327     int nloop = 0;
1328     EncTicketPart adtkt;
1329     char opt_str[128];
1330     krb5_boolean kdc_issued = FALSE;
1331
1332     Key *tkey_sign;
1333     int flags = HDB_F_FOR_TGS_REQ;
1334
1335     memset(&sessionkey, 0, sizeof(sessionkey));
1336     memset(&adtkt, 0, sizeof(adtkt));
1337     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1338
1339     s = b->sname;
1340     r = b->realm;
1341
1342     if (b->kdc_options.canonicalize)
1343         flags |= HDB_F_CANON;
1344
1345     if (s == NULL) {
1346         ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1347         krb5_set_error_message(context, ret, "No server in request");
1348         goto out;
1349     }
1350
1351     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1352     ret = krb5_unparse_name(context, sp, &spn);
1353     if (ret)
1354         goto out;
1355     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1356     ret = krb5_unparse_name(context, cp, &cpn);
1357     if (ret)
1358         goto out;
1359     unparse_flags (KDCOptions2int(b->kdc_options),
1360                    asn1_KDCOptions_units(),
1361                    opt_str, sizeof(opt_str));
1362     if(*opt_str)
1363         kdc_log(context, config, 0,
1364                 "TGS-REQ %s from %s for %s [%s]",
1365                 cpn, from, spn, opt_str);
1366     else
1367         kdc_log(context, config, 0,
1368                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1369
1370     /*
1371      * Fetch server
1372      */
1373
1374 server_lookup:
1375     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1376                         NULL, &serverdb, &server);
1377
1378     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1379         kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1380         goto out;
1381     } else if (ret == HDB_ERR_WRONG_REALM) {
1382         if (ref_realm)
1383             free(ref_realm);
1384         ref_realm = strdup(server->entry.principal->realm);
1385         if (ref_realm == NULL) {
1386             ret = ENOMEM;
1387             goto out;
1388         }
1389
1390         kdc_log(context, config, 5,
1391                 "Returning a referral to realm %s for "
1392                 "server %s.",
1393                 ref_realm, spn);
1394         krb5_free_principal(context, sp);
1395         sp = NULL;
1396         free(spn);
1397         spn = NULL;
1398         ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1399                                   ref_realm, NULL);
1400         if (ret)
1401             goto out;
1402         ret = krb5_unparse_name(context, sp, &spn);
1403         if (ret)
1404             goto out;
1405
1406         goto server_lookup;
1407     } else if(ret){
1408         const char *new_rlm, *msg;
1409         Realm req_rlm;
1410         krb5_realm *realms;
1411
1412         if (!config->autodetect_referrals) {
1413                 /* noop */
1414         } else if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1415             if(nloop++ < 2) {
1416                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1417                 if(new_rlm) {
1418                     kdc_log(context, config, 5, "krbtgt for realm %s "
1419                             "not found, trying %s",
1420                             req_rlm, new_rlm);
1421                     krb5_free_principal(context, sp);
1422                     free(spn);
1423                     krb5_make_principal(context, &sp, r,
1424                                         KRB5_TGS_NAME, new_rlm, NULL);
1425                     ret = krb5_unparse_name(context, sp, &spn);
1426                     if (ret)
1427                         goto out;
1428
1429                     if (ref_realm)
1430                         free(ref_realm);
1431                     ref_realm = strdup(new_rlm);
1432                     goto server_lookup;
1433                 }
1434             }
1435         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1436             if (strcmp(realms[0], sp->realm) != 0) {
1437                 kdc_log(context, config, 5,
1438                         "Returning a referral to realm %s for "
1439                         "server %s that was not found",
1440                         realms[0], spn);
1441                 krb5_free_principal(context, sp);
1442                 free(spn);
1443                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1444                                     realms[0], NULL);
1445                 ret = krb5_unparse_name(context, sp, &spn);
1446                 if (ret)
1447                     goto out;
1448
1449                 if (ref_realm)
1450                     free(ref_realm);
1451                 ref_realm = strdup(realms[0]);
1452
1453                 krb5_free_host_realm(context, realms);
1454                 goto server_lookup;
1455             }
1456             krb5_free_host_realm(context, realms);
1457         }
1458         msg = krb5_get_error_message(context, ret);
1459         kdc_log(context, config, 0,
1460                 "Server not found in database: %s: %s", spn, msg);
1461         krb5_free_error_message(context, msg);
1462         if (ret == HDB_ERR_NOENTRY)
1463             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1464         goto out;
1465     }
1466
1467     /* Now refetch the primary krbtgt, and get the current kvno (the
1468      * sign check may have been on an old kvno, and the server may
1469      * have been an incoming trust) */
1470     ret = krb5_make_principal(context, &krbtgt_principal,
1471                               krb5_principal_get_comp_string(context,
1472                                                              krbtgt->entry.principal,
1473                                                              1),
1474                               KRB5_TGS_NAME,
1475                               krb5_principal_get_comp_string(context,
1476                                                              krbtgt->entry.principal,
1477                                                              1), NULL);
1478     if(ret) {
1479         kdc_log(context, config, 0,
1480                     "Failed to generate krbtgt principal");
1481         goto out;
1482     }
1483
1484     ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1485     krb5_free_principal(context, krbtgt_principal);
1486     if (ret) {
1487         krb5_error_code ret2;
1488         char *ktpn, *ktpn2;
1489         ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1490         ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1491         kdc_log(context, config, 0,
1492                 "Request with wrong krbtgt: %s, %s not found in our database",
1493                 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1494         if(ret == 0)
1495             free(ktpn);
1496         if(ret2 == 0)
1497             free(ktpn2);
1498         ret = KRB5KRB_AP_ERR_NOT_US;
1499         goto out;
1500     }
1501
1502     /*
1503      * Select enctype, return key and kvno.
1504      */
1505
1506     {
1507         krb5_enctype etype;
1508
1509         if(b->kdc_options.enc_tkt_in_skey) {
1510             Ticket *t;
1511             hdb_entry_ex *uu;
1512             krb5_principal p;
1513             Key *uukey;
1514             krb5uint32 second_kvno = 0;
1515             krb5uint32 *kvno_ptr = NULL;
1516             size_t i;
1517             hdb_entry_ex *user2user_client = NULL;
1518
1519             if(b->additional_tickets == NULL ||
1520                b->additional_tickets->len == 0){
1521                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1522                 kdc_log(context, config, 0,
1523                         "No second ticket present in request");
1524                 goto out;
1525             }
1526             t = &b->additional_tickets->val[0];
1527             if(!get_krbtgt_realm(&t->sname)){
1528                 kdc_log(context, config, 0,
1529                         "Additional ticket is not a ticket-granting ticket");
1530                 ret = KRB5KDC_ERR_POLICY;
1531                 goto out;
1532             }
1533             ret = _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1534             if (ret) {
1535                 goto out;
1536             }
1537             if(t->enc_part.kvno){
1538                 second_kvno = *t->enc_part.kvno;
1539                 kvno_ptr = &second_kvno;
1540             }
1541             ret = _kdc_db_fetch(context, config, p,
1542                                 HDB_F_GET_KRBTGT, kvno_ptr,
1543                                 NULL, &uu);
1544             krb5_free_principal(context, p);
1545             if(ret){
1546                 if (ret == HDB_ERR_NOENTRY)
1547                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1548                 goto out;
1549             }
1550             ret = hdb_enctype2key(context, &uu->entry,
1551                                   t->enc_part.etype, &uukey);
1552             if(ret){
1553                 _kdc_free_ent(context, uu);
1554                 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1555                 goto out;
1556             }
1557             ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1558             _kdc_free_ent(context, uu);
1559             if(ret)
1560                 goto out;
1561
1562             ret = verify_flags(context, config, &adtkt, spn);
1563             if (ret)
1564                 goto out;
1565
1566             /* Fetch the name from the TGT. */
1567             ret = _krb5_principalname2krb5_principal(context, &user2user_princ,
1568                                                      adtkt.cname, adtkt.crealm);
1569             if (ret) {
1570                 goto out;
1571             }
1572
1573             ret = krb5_unparse_name(context, user2user_princ, &user2user_name);
1574             if (ret) {
1575                 goto out;
1576             }
1577
1578             /* Look up the name given in the TGT in the database. */
1579             ret = db_fetch_client(context, config, flags, user2user_princ, user2user_name,
1580                                   krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1581                                   NULL, &user2user_client);
1582             if (ret) {
1583                 goto out;
1584             }
1585
1586             if (user2user_client != NULL) {
1587                 /*
1588                  * If the account is present in the database, check the account
1589                  * flags.
1590                  */
1591                 ret = kdc_check_flags(context, config,
1592                                       user2user_client, user2user_name,
1593                                       NULL, NULL,
1594                                       FALSE);
1595                 if (ret) {
1596                     _kdc_free_ent(context, user2user_client);
1597                     goto out;
1598                 }
1599
1600                 /*
1601                  * Also check that the account is the same one specified in the
1602                  * request.
1603                  */
1604                 ret = check_s4u2self(context, config, serverdb, server, user2user_client, user2user_princ);
1605                 if (ret) {
1606                     _kdc_free_ent(context, user2user_client);
1607                     goto out;
1608                 }
1609             }
1610
1611             _kdc_free_ent(context, user2user_client);
1612
1613             ekey = &adtkt.key;
1614             for(i = 0; i < b->etype.len; i++)
1615                 if (b->etype.val[i] == adtkt.key.keytype)
1616                     break;
1617             if(i == b->etype.len) {
1618                 kdc_log(context, config, 0,
1619                         "Addition ticket have not matching etypes");
1620                 krb5_clear_error_message(context);
1621                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1622                 goto out;
1623             }
1624             etype = b->etype.val[i];
1625             kvno = 0;
1626         } else {
1627             Key *skey;
1628
1629             ret = _kdc_find_etype(context,
1630                                   config->tgs_use_strongest_session_key, FALSE,
1631                                   server, b->etype.val, b->etype.len, NULL,
1632                                   &skey);
1633             if(ret) {
1634                 kdc_log(context, config, 0,
1635                         "Server (%s) has no support for etypes", spn);
1636                 goto out;
1637             }
1638             ekey = &skey->key;
1639             etype = skey->key.keytype;
1640             kvno = server->entry.kvno;
1641         }
1642
1643         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1644         if (ret)
1645             goto out;
1646     }
1647
1648     /*
1649      * Check that service is in the same realm as the krbtgt. If it's
1650      * not the same, it's someone that is using a uni-directional trust
1651      * backward.
1652      */
1653
1654     /* The first realm is the realm of the service, the second is
1655      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1656      * encrypted to.  The redirection via the krbtgt_out entry allows
1657      * the DB to possibly correct the case of the realm (Samba4 does
1658      * this) before the strcmp() */
1659     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1660                krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1661         char *ktpn;
1662         ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1663         kdc_log(context, config, 0,
1664                 "Request with wrong krbtgt: %s",
1665                 (ret == 0) ? ktpn : "<unknown>");
1666         if(ret == 0)
1667             free(ktpn);
1668         ret = KRB5KRB_AP_ERR_NOT_US;
1669     }
1670
1671     ret = hdb_enctype2key(context, &krbtgt_out->entry,
1672                           krbtgt_etype, &tkey_sign);
1673     if(ret) {
1674         kdc_log(context, config, 0,
1675                     "Failed to find key for krbtgt PAC signature");
1676         goto out;
1677     }
1678
1679     ret = db_fetch_client(context, config, flags, cp, cpn,
1680                           krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1681                           &clientdb, &client);
1682     if (ret)
1683         goto out;
1684
1685     ret = check_PAC(context, config, cp, NULL, client, server, krbtgt, krbtgt,
1686                     &tkey_check->key, &tkey_check->key, tgt, &kdc_issued, &mspac);
1687     if (ret) {
1688         const char *msg = krb5_get_error_message(context, ret);
1689         kdc_log(context, config, 0,
1690                 "Verify PAC failed for %s (%s) from %s with %s",
1691                 spn, cpn, from, msg);
1692         krb5_free_error_message(context, msg);
1693         goto out;
1694     }
1695
1696     /*
1697      * Process request
1698      */
1699
1700     /* by default the tgt principal matches the client principal */
1701     tp = cp;
1702     tpn = cpn;
1703
1704     if (client) {
1705         const PA_DATA *sdata;
1706         int i = 0;
1707
1708         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1709         if (sdata) {
1710             krb5_crypto crypto;
1711             krb5_data datack;
1712             PA_S4U2Self self;
1713             const char *str;
1714
1715             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1716                                      sdata->padata_value.length,
1717                                      &self, NULL);
1718             if (ret) {
1719                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1720                 goto out;
1721             }
1722
1723             if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
1724                 free_PA_S4U2Self(&self);
1725                 kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
1726                 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1727                 goto out;
1728             }
1729
1730             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1731             if (ret)
1732                 goto out;
1733
1734             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1735             if (ret) {
1736                 const char *msg = krb5_get_error_message(context, ret);
1737                 free_PA_S4U2Self(&self);
1738                 krb5_data_free(&datack);
1739                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1740                 krb5_free_error_message(context, msg);
1741                 goto out;
1742             }
1743
1744             /* Allow HMAC_MD5 checksum with any key type */
1745             if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
1746                 unsigned char csdata[16];
1747                 Checksum cs;
1748
1749                 cs.checksum.length = sizeof(csdata);
1750                 cs.checksum.data = &csdata;
1751
1752                 ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
1753                                               datack.data, datack.length,
1754                                               KRB5_KU_OTHER_CKSUM, &cs);
1755                 if (ret == 0 &&
1756                     krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
1757                     ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
1758             }
1759             else {
1760                 ret = krb5_verify_checksum(context,
1761                                            crypto,
1762                                            KRB5_KU_OTHER_CKSUM,
1763                                            datack.data,
1764                                            datack.length,
1765                                            &self.cksum);
1766             }
1767             krb5_data_free(&datack);
1768             krb5_crypto_destroy(context, crypto);
1769             if (ret) {
1770                 const char *msg = krb5_get_error_message(context, ret);
1771                 free_PA_S4U2Self(&self);
1772                 kdc_log(context, config, 0,
1773                         "krb5_verify_checksum failed for S4U2Self: %s", msg);
1774                 krb5_free_error_message(context, msg);
1775                 goto out;
1776             }
1777
1778             ret = _krb5_principalname2krb5_principal(context,
1779                                                      &tp,
1780                                                      self.name,
1781                                                      self.realm);
1782             free_PA_S4U2Self(&self);
1783             if (ret)
1784                 goto out;
1785
1786             ret = krb5_unparse_name(context, tp, &tpn);
1787             if (ret)
1788                 goto out;
1789
1790             ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1791                                 NULL, &s4u2self_impersonated_clientdb,
1792                                 &s4u2self_impersonated_client);
1793             if (ret) {
1794                 const char *msg;
1795
1796                 /*
1797                  * If the client belongs to the same realm as our krbtgt, it
1798                  * should exist in the local database.
1799                  *
1800                  */
1801
1802                 if (ret == HDB_ERR_NOENTRY)
1803                     ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1804                 msg = krb5_get_error_message(context, ret);
1805                 kdc_log(context, config, 1,
1806                         "S2U4Self principal to impersonate %s not found in database: %s",
1807                         tpn, msg);
1808                 krb5_free_error_message(context, msg);
1809                 goto out;
1810             }
1811
1812             /* Ignore pw_end attributes (as Windows does),
1813              * since S4U2Self is not password authentication. */
1814             free(s4u2self_impersonated_client->entry.pw_end);
1815             s4u2self_impersonated_client->entry.pw_end = NULL;
1816
1817             ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
1818                                   NULL, NULL, FALSE);
1819             if (ret)
1820                 goto out;
1821
1822             /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1823             if (mspac) {
1824                 krb5_pac_free(context, mspac);
1825                 mspac = NULL;
1826                 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, NULL, NULL, &mspac);
1827                 if (ret) {
1828                     kdc_log(context, config, 0, "PAC generation failed for -- %s",
1829                             tpn);
1830                     goto out;
1831                 }
1832             }
1833
1834             /*
1835              * Check that service doing the impersonating is
1836              * requesting a ticket to it-self.
1837              */
1838             ret = check_s4u2self(context, config, clientdb, client, server, sp);
1839             if (ret) {
1840                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1841                         "to impersonate to service "
1842                         "(tried for user %s to service %s)",
1843                         cpn, tpn, spn);
1844                 goto out;
1845             }
1846
1847             /*
1848              * If the service isn't trusted for authentication to
1849              * delegation or if the impersonate client is disallowed
1850              * forwardable, remove the forwardable flag.
1851              */
1852
1853             if (client->entry.flags.trusted_for_delegation &&
1854                 s4u2self_impersonated_client->entry.flags.forwardable) {
1855                 str = "[forwardable]";
1856             } else {
1857                 b->kdc_options.forwardable = 0;
1858                 str = "";
1859             }
1860             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1861                     "service %s %s", cpn, tpn, spn, str);
1862         }
1863     }
1864
1865     /*
1866      * Constrained delegation
1867      */
1868
1869     if (client != NULL
1870         && b->additional_tickets != NULL
1871         && b->additional_tickets->len != 0
1872         && b->kdc_options.enc_tkt_in_skey == 0)
1873     {
1874         hdb_entry_ex *adclient = NULL;
1875         krb5_boolean ad_kdc_issued = FALSE;
1876         Key *clientkey;
1877         Ticket *t;
1878
1879         /*
1880          * We require that the service's krbtgt has a PAC.
1881          */
1882         if (mspac == NULL) {
1883             ret = KRB5KDC_ERR_BADOPTION;
1884             kdc_log(context, config, 0,
1885                     "Constrained delegation without PAC %s/%s",
1886                     cpn, spn);
1887             goto out;
1888         }
1889
1890         krb5_pac_free(context, mspac);
1891         mspac = NULL;
1892
1893         t = &b->additional_tickets->val[0];
1894
1895         ret = hdb_enctype2key(context, &client->entry,
1896                               t->enc_part.etype, &clientkey);
1897         if(ret){
1898             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1899             goto out;
1900         }
1901
1902         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1903         if (ret) {
1904             kdc_log(context, config, 0,
1905                     "failed to decrypt ticket for "
1906                     "constrained delegation from %s to %s ", cpn, spn);
1907             goto out;
1908         }
1909
1910         ret = _krb5_principalname2krb5_principal(context,
1911                                                  &tp,
1912                                                  adtkt.cname,
1913                                                  adtkt.crealm);
1914         if (ret)
1915             goto out;
1916
1917         ret = krb5_unparse_name(context, tp, &tpn);
1918         if (ret)
1919             goto out;
1920
1921         ret = _krb5_principalname2krb5_principal(context,
1922                                                  &dp,
1923                                                  t->sname,
1924                                                  t->realm);
1925         if (ret)
1926             goto out;
1927
1928         ret = krb5_unparse_name(context, dp, &dpn);
1929         if (ret)
1930             goto out;
1931
1932         /* check that ticket is valid */
1933         if (adtkt.flags.forwardable == 0) {
1934             kdc_log(context, config, 0,
1935                     "Missing forwardable flag on ticket for "
1936                     "constrained delegation from %s (%s) as %s to %s ",
1937                     cpn, dpn, tpn, spn);
1938             ret = KRB5KDC_ERR_BADOPTION;
1939             goto out;
1940         }
1941
1942         ret = check_constrained_delegation(context, config, clientdb,
1943                                            client, server, sp);
1944         if (ret) {
1945             kdc_log(context, config, 0,
1946                     "constrained delegation from %s (%s) as %s to %s not allowed",
1947                     cpn, dpn, tpn, spn);
1948             goto out;
1949         }
1950
1951         ret = verify_flags(context, config, &adtkt, tpn);
1952         if (ret) {
1953             goto out;
1954         }
1955
1956         /* Try lookup the delegated client in DB */
1957         ret = db_fetch_client(context, config, flags, tp, tpn,
1958                               krb5_principal_get_realm(context, krbtgt_out->entry.principal),
1959                               NULL, &adclient);
1960         if (ret)
1961             goto out;
1962
1963         if (adclient != NULL) {
1964             ret = kdc_check_flags(context, config,
1965                                   adclient, tpn,
1966                                   server, spn,
1967                                   FALSE);
1968             if (ret) {
1969                 _kdc_free_ent(context, adclient);
1970                 goto out;
1971             }
1972         }
1973
1974         /*
1975          * TODO: pass in t->sname and t->realm and build
1976          * a S4U_DELEGATION_INFO blob to the PAC.
1977          */
1978         ret = check_PAC(context, config, tp, dp, adclient, server, krbtgt, client,
1979                         &clientkey->key, &tkey_check->key, &adtkt, &ad_kdc_issued, &mspac);
1980         if (adclient)
1981             _kdc_free_ent(context, adclient);
1982         if (ret) {
1983             const char *msg = krb5_get_error_message(context, ret);
1984             kdc_log(context, config, 0,
1985                     "Verify delegated PAC failed to %s for client"
1986                     "%s (%s) as %s from %s with %s",
1987                     spn, cpn, dpn, tpn, from, msg);
1988             krb5_free_error_message(context, msg);
1989             goto out;
1990         }
1991
1992         if (mspac == NULL || !ad_kdc_issued) {
1993             ret = KRB5KDC_ERR_BADOPTION;
1994             kdc_log(context, config, 0,
1995                     "Ticket not signed with PAC; service %s failed for "
1996                     "for delegation to %s for client %s (%s) from %s; (%s).",
1997                     spn, tpn, dpn, cpn, from, mspac ? "Ticket unsigned" : "No PAC");
1998             goto out;
1999         }
2000
2001         kdc_log(context, config, 0, "constrained delegation for %s "
2002                 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2003     }
2004
2005     /*
2006      * Check flags
2007      */
2008
2009     ret = kdc_check_flags(context, config,
2010                           client, cpn,
2011                           server, spn,
2012                           FALSE);
2013     if(ret)
2014         goto out;
2015
2016     if((b->kdc_options.validate || b->kdc_options.renew) &&
2017        !krb5_principal_compare(context,
2018                                krbtgt->entry.principal,
2019                                server->entry.principal)){
2020         kdc_log(context, config, 0, "Inconsistent request.");
2021         ret = KRB5KDC_ERR_SERVER_NOMATCH;
2022         goto out;
2023     }
2024
2025     /* check for valid set of addresses */
2026     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2027         ret = KRB5KRB_AP_ERR_BADADDR;
2028         kdc_log(context, config, 0, "Request from wrong address");
2029         goto out;
2030     }
2031
2032     /*
2033      * If this is an referral, add server referral data to the
2034      * auth_data reply .
2035      */
2036     if (ref_realm) {
2037         PA_DATA pa;
2038         krb5_crypto crypto;
2039
2040         kdc_log(context, config, 0,
2041                 "Adding server referral to %s", ref_realm);
2042
2043         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2044         if (ret)
2045             goto out;
2046
2047         ret = build_server_referral(context, config, crypto, ref_realm,
2048                                     NULL, s, &pa.padata_value);
2049         krb5_crypto_destroy(context, crypto);
2050         if (ret) {
2051             kdc_log(context, config, 0,
2052                     "Failed building server referral");
2053             goto out;
2054         }
2055         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2056
2057         ret = add_METHOD_DATA(&enc_pa_data, &pa);
2058         krb5_data_free(&pa.padata_value);
2059         if (ret) {
2060             kdc_log(context, config, 0,
2061                     "Add server referral METHOD-DATA failed");
2062             goto out;
2063         }
2064     }
2065
2066     /*
2067      * Only add ticket signature if the requested server is not krbtgt, and
2068      * either the header server is krbtgt or, in the case of renewal/validation
2069      * if it was signed with PAC ticket signature and we verified it.
2070      * Currently Heimdal only allows renewal of krbtgt anyway but that might
2071      * change one day (see issue #763) so make sure to check for it.
2072      */
2073
2074     if (kdc_issued &&
2075         !krb5_principal_is_krbtgt(context, server->entry.principal))
2076         add_ticket_sig = TRUE;
2077
2078     /*
2079      * Active-Directory implementations use the high part of the kvno as the
2080      * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2081      */
2082
2083     rodc_id = krbtgt_out->entry.kvno >> 16;
2084
2085     /*
2086      *
2087      */
2088
2089     ret = tgs_make_reply(context,
2090                          config,
2091                          b,
2092                          tp,
2093                          tgt,
2094                          replykey,
2095                          rk_is_subkey,
2096                          ekey,
2097                          &tkey_sign->key,
2098                          &sessionkey,
2099                          kvno,
2100                          *auth_data,
2101                          server,
2102                          server->entry.principal,
2103                          spn,
2104                          client,
2105                          cp,
2106                          tgt_realm,
2107                          krbtgt_out,
2108                          mspac,
2109                          rodc_id,
2110                          add_ticket_sig,
2111                          &enc_pa_data,
2112                          e_text,
2113                          reply);
2114
2115 out:
2116     free(user2user_name);
2117     if (tpn != cpn)
2118             free(tpn);
2119     free(spn);
2120     free(cpn);
2121     if (dpn)
2122         free(dpn);
2123
2124     krb5_free_keyblock_contents(context, &sessionkey);
2125     if(krbtgt_out)
2126         _kdc_free_ent(context, krbtgt_out);
2127     if(server)
2128         _kdc_free_ent(context, server);
2129     if(client)
2130         _kdc_free_ent(context, client);
2131     if(s4u2self_impersonated_client)
2132         _kdc_free_ent(context, s4u2self_impersonated_client);
2133
2134     if (user2user_princ)
2135         krb5_free_principal(context, user2user_princ);
2136     if (tp && tp != cp)
2137         krb5_free_principal(context, tp);
2138     if (cp)
2139         krb5_free_principal(context, cp);
2140     if (dp)
2141         krb5_free_principal(context, dp);
2142     if (sp)
2143         krb5_free_principal(context, sp);
2144     if (ref_realm)
2145         free(ref_realm);
2146     free_METHOD_DATA(&enc_pa_data);
2147
2148     free_EncTicketPart(&adtkt);
2149
2150     krb5_pac_free(context, mspac);
2151
2152     return ret;
2153 }
2154
2155 /*
2156  *
2157  */
2158
2159 krb5_error_code
2160 _kdc_tgs_rep(krb5_context context,
2161              krb5_kdc_configuration *config,
2162              KDC_REQ *req,
2163              krb5_data *data,
2164              const char *from,
2165              struct sockaddr *from_addr,
2166              int datagram_reply)
2167 {
2168     AuthorizationData *auth_data = NULL;
2169     krb5_error_code ret;
2170     int i = 0;
2171     const PA_DATA *tgs_req;
2172     Key *header_key = NULL;
2173
2174     hdb_entry_ex *krbtgt = NULL;
2175     krb5_ticket *ticket = NULL;
2176     const char *e_text = NULL;
2177     krb5_enctype krbtgt_etype = ETYPE_NULL;
2178
2179     krb5_keyblock *replykey = NULL;
2180     int rk_is_subkey = 0;
2181     time_t *csec = NULL;
2182     int *cusec = NULL;
2183
2184     if(req->padata == NULL){
2185         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2186         kdc_log(context, config, 0,
2187                 "TGS-REQ from %s without PA-DATA", from);
2188         goto out;
2189     }
2190
2191     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2192
2193     if(tgs_req == NULL){
2194         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2195
2196         kdc_log(context, config, 0,
2197                 "TGS-REQ from %s without PA-TGS-REQ", from);
2198         goto out;
2199     }
2200     ret = tgs_parse_request(context, config,
2201                             &req->req_body, tgs_req,
2202                             &krbtgt,
2203                             &krbtgt_etype,
2204                             &ticket,
2205                             &e_text,
2206                             from, from_addr,
2207                             &csec, &cusec,
2208                             &auth_data,
2209                             &replykey,
2210                             &header_key,
2211                             &rk_is_subkey);
2212     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2213         /* kdc_log() is called in tgs_parse_request() */
2214         goto out;
2215     }
2216     if (ret) {
2217         kdc_log(context, config, 0,
2218                 "Failed parsing TGS-REQ from %s", from);
2219         goto out;
2220     }
2221
2222     ret = tgs_build_reply(context,
2223                           config,
2224                           req,
2225                           &req->req_body,
2226                           krbtgt,
2227                           krbtgt_etype,
2228                           header_key,
2229                           replykey,
2230                           rk_is_subkey,
2231                           ticket,
2232                           data,
2233                           from,
2234                           &e_text,
2235                           &auth_data,
2236                           from_addr);
2237     if (ret) {
2238         kdc_log(context, config, 0,
2239                 "Failed building TGS-REP to %s", from);
2240         goto out;
2241     }
2242
2243     /* */
2244     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2245         krb5_data_free(data);
2246         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2247         e_text = "Reply packet too large";
2248     }
2249
2250 out:
2251     if (replykey)
2252         krb5_free_keyblock(context, replykey);
2253     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2254         krb5_mk_error(context,
2255                       ret,
2256                       NULL,
2257                       NULL,
2258                       NULL,
2259                       NULL,
2260                       csec,
2261                       cusec,
2262                       data);
2263         ret = 0;
2264     }
2265     free(csec);
2266     free(cusec);
2267     if (ticket)
2268         krb5_free_ticket(context, ticket);
2269     if(krbtgt)
2270         _kdc_free_ent(context, krbtgt);
2271
2272     if (auth_data) {
2273         free_AuthorizationData(auth_data);
2274         free(auth_data);
2275     }
2276
2277     return ret;
2278 }