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