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