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