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