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