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