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