9131e5baf0d0ee88ec38c4dab77582d58c093299
[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     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1641                         NULL, &clientdb, &client);
1642     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1643         kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy", cp);
1644         goto out;
1645     } else if(ret){
1646         const char *krbtgt_realm, *msg;
1647
1648         /*
1649          * If the client belongs to the same realm as our krbtgt, it
1650          * should exist in the local database.
1651          *
1652          */
1653
1654         krbtgt_realm =
1655             krb5_principal_get_comp_string(context,
1656                                            krbtgt->entry.principal, 1);
1657
1658         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1659             if (ret == HDB_ERR_NOENTRY)
1660                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1661             kdc_log(context, config, 1, "Client no longer in database: %s",
1662                     cpn);
1663             goto out;
1664         }
1665         
1666         msg = krb5_get_error_message(context, ret);
1667         kdc_log(context, config, 1, "Client not found in database: %s", msg);
1668         krb5_free_error_message(context, msg);
1669     }
1670
1671     /*
1672      * Select enctype, return key and kvno.
1673      */
1674
1675     {
1676         krb5_enctype etype;
1677
1678         if(b->kdc_options.enc_tkt_in_skey) {
1679             int i;
1680             ekey = &adtkt.key;
1681             for(i = 0; i < b->etype.len; i++)
1682                 if (b->etype.val[i] == adtkt.key.keytype)
1683                     break;
1684             if(i == b->etype.len) {
1685                 kdc_log(context, config, 0,
1686                         "Addition ticket have not matching etypes");
1687                 krb5_clear_error_message(context);
1688                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1689                 goto out;
1690             }
1691             etype = b->etype.val[i];
1692             kvno = 0;
1693         } else {
1694             Key *skey;
1695         
1696             ret = _kdc_find_etype(context, server,
1697                                   b->etype.val, b->etype.len, &skey);
1698             if(ret) {
1699                 kdc_log(context, config, 0,
1700                         "Server (%s) has no support for etypes", spn);
1701                 goto out;
1702             }
1703             ekey = &skey->key;
1704             etype = skey->key.keytype;
1705             kvno = server->entry.kvno;
1706         }
1707         
1708         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1709         if (ret)
1710             goto out;
1711     }
1712
1713     /*
1714      * Check that service is in the same realm as the krbtgt. If it's
1715      * not the same, it's someone that is using a uni-directional trust
1716      * backward.
1717      */
1718
1719     /*
1720      * Validate authoriation data
1721      */
1722
1723     ret = hdb_enctype2key(context, &krbtgt->entry,
1724                           krbtgt_etype, &tkey_check);
1725     if(ret) {
1726         kdc_log(context, config, 0,
1727                     "Failed to find key for krbtgt PAC check");
1728         goto out;
1729     }
1730
1731     /* Now refetch the primary krbtgt, and get the current kvno (the
1732      * sign check may have been on an old kvno, and the server may
1733      * have been an incoming trust) */
1734     ret = krb5_make_principal(context, &krbtgt_principal, 
1735                               krb5_principal_get_comp_string(context,
1736                                                              krbtgt->entry.principal,
1737                                                              1),
1738                               KRB5_TGS_NAME, 
1739                               krb5_principal_get_comp_string(context,
1740                                                              krbtgt->entry.principal,
1741                                                              1), NULL);
1742     if(ret) {
1743         kdc_log(context, config, 0,
1744                     "Failed to generate krbtgt principal");
1745         goto out;
1746     }
1747
1748     ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1749     krb5_free_principal(context, krbtgt_principal);
1750     if (ret) {
1751         krb5_error_code ret2;
1752         char *tpn, *tpn2;
1753         ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1754         ret2 = krb5_unparse_name(context, krbtgt->entry.principal, &tpn2);
1755         kdc_log(context, config, 0,
1756                 "Request with wrong krbtgt: %s, %s not found in our database",
1757                 (ret == 0) ? tpn : "<unknown>", (ret2 == 0) ? tpn2 : "<unknown>");
1758         if(ret == 0)
1759             free(tpn);
1760         if(ret2 == 0)
1761             free(tpn2);
1762         ret = KRB5KRB_AP_ERR_NOT_US;
1763         goto out;
1764     }
1765
1766     /* The first realm is the realm of the service, the second is
1767      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1768      * encrypted to.  The redirection via the krbtgt_out entry allows
1769      * the DB to possibly correct the case of the realm (Samba4 does
1770      * this) before the strcmp() */
1771     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1772                krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1773         char *tpn;
1774         ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &tpn);
1775         kdc_log(context, config, 0,
1776                 "Request with wrong krbtgt: %s",
1777                 (ret == 0) ? tpn : "<unknown>");
1778         if(ret == 0)
1779             free(tpn);
1780         ret = KRB5KRB_AP_ERR_NOT_US;
1781     }
1782
1783     ret = hdb_enctype2key(context, &krbtgt_out->entry,
1784                           krbtgt_etype, &tkey_sign);
1785     if(ret) {
1786         kdc_log(context, config, 0,
1787                     "Failed to find key for krbtgt PAC signature");
1788         goto out;
1789     }
1790
1791     ret = check_PAC(context, config, cp,
1792                     client, server, krbtgt, ekey, &tkey_check->key, &tkey_sign->key,
1793                     tgt, &rspac, &signedpath);
1794     if (ret) {
1795         const char *msg = krb5_get_error_message(context, ret);
1796         kdc_log(context, config, 0,
1797                 "Verify PAC failed for %s (%s) from %s with %s",
1798                 spn, cpn, from, msg);
1799         krb5_free_error_message(context, msg);
1800         goto out;
1801     }
1802
1803     /* also check the krbtgt for signature */
1804     ret = check_KRB5SignedPath(context,
1805                                config,
1806                                krbtgt,
1807                                cp,
1808                                tgt,
1809                                &spp,
1810                                &signedpath);
1811     if (ret) {
1812         const char *msg = krb5_get_error_message(context, ret);
1813         kdc_log(context, config, 0,
1814                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1815                 spn, cpn, from, msg);
1816         krb5_free_error_message(context, msg);
1817         goto out;
1818     }
1819
1820     /*
1821      * Process request
1822      */
1823
1824     client_principal = cp;
1825
1826     if (client) {
1827         const PA_DATA *sdata;
1828         int i = 0;
1829
1830         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1831         if (sdata) {
1832             krb5_crypto crypto;
1833             krb5_data datack;
1834             PA_S4U2Self self;
1835             char *selfcpn = NULL;
1836             const char *str;
1837
1838             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1839                                      sdata->padata_value.length,
1840                                      &self, NULL);
1841             if (ret) {
1842                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1843                 goto out;
1844             }
1845
1846             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1847             if (ret)
1848                 goto out;
1849
1850             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1851             if (ret) {
1852                 const char *msg = krb5_get_error_message(context, ret);
1853                 free_PA_S4U2Self(&self);
1854                 krb5_data_free(&datack);
1855                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1856                 krb5_free_error_message(context, msg);
1857                 goto out;
1858             }
1859
1860             ret = krb5_verify_checksum(context,
1861                                        crypto,
1862                                        KRB5_KU_OTHER_CKSUM,
1863                                        datack.data,
1864                                        datack.length,
1865                                        &self.cksum);
1866             krb5_data_free(&datack);
1867             krb5_crypto_destroy(context, crypto);
1868             if (ret) {
1869                 const char *msg = krb5_get_error_message(context, ret);
1870                 free_PA_S4U2Self(&self);
1871                 kdc_log(context, config, 0,
1872                         "krb5_verify_checksum failed for S4U2Self: %s", msg);
1873                 krb5_free_error_message(context, msg);
1874                 goto out;
1875             }
1876
1877             ret = _krb5_principalname2krb5_principal(context,
1878                                                      &client_principal,
1879                                                      self.name,
1880                                                      self.realm);
1881             free_PA_S4U2Self(&self);
1882             if (ret)
1883                 goto out;
1884
1885             ret = krb5_unparse_name(context, client_principal, &selfcpn);       
1886             if (ret)
1887                 goto out;
1888
1889             /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1890             if(rspac.data) {
1891                 krb5_pac p = NULL;
1892                 krb5_data_free(&rspac);
1893                 ret = _kdc_db_fetch(context, config, client_principal, HDB_F_GET_CLIENT | HDB_F_CANON,
1894                                     NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1895                 if (ret) {
1896                     const char *msg;
1897
1898                     /*
1899                      * If the client belongs to the same realm as our krbtgt, it
1900                      * should exist in the local database.
1901                      *
1902                      */
1903
1904                     if (ret == HDB_ERR_NOENTRY)
1905                         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1906                     msg = krb5_get_error_message(context, ret);
1907                     kdc_log(context, config, 1, "S2U4Self principal to impersonate %s not found in database: %s", cpn, msg);
1908                     krb5_free_error_message(context, msg);
1909                     goto out;
1910                 }
1911                 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1912                 if (ret) {
1913                     kdc_log(context, config, 0, "PAC generation failed for -- %s",
1914                             selfcpn);
1915                     goto out;
1916                 }
1917                 if (p != NULL) {
1918                     ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1919                                          s4u2self_impersonated_client->entry.principal,
1920                                          ekey, &tkey_sign->key,
1921                                          &rspac);
1922                     krb5_pac_free(context, p);
1923                     if (ret) {
1924                         kdc_log(context, config, 0, "PAC signing failed for -- %s",
1925                                 selfcpn);
1926                         goto out;
1927                     }
1928                 }
1929             }
1930
1931             /*
1932              * Check that service doing the impersonating is
1933              * requesting a ticket to it-self.
1934              */
1935             ret = check_s4u2self(context, config, clientdb, client, sp);
1936             if (ret) {
1937                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1938                         "to impersonate to service "
1939                         "(tried for user %s to service %s)",
1940                         cpn, selfcpn, spn);
1941                 free(selfcpn);
1942                 goto out;
1943             }
1944
1945             /*
1946              * If the service isn't trusted for authentication to
1947              * delegation, remove the forward flag.
1948              */
1949
1950             if (client->entry.flags.trusted_for_delegation) {
1951                 str = "[forwardable]";
1952             } else {
1953                 b->kdc_options.forwardable = 0;
1954                 str = "";
1955             }
1956             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1957                     "service %s %s", cpn, selfcpn, spn, str);
1958             free(selfcpn);
1959         }
1960     }
1961
1962     /*
1963      * Constrained delegation
1964      */
1965
1966     if (client != NULL
1967         && b->additional_tickets != NULL
1968         && b->additional_tickets->len != 0
1969         && b->kdc_options.enc_tkt_in_skey == 0)
1970     {
1971         int ad_signedpath = 0;
1972         Key *clientkey;
1973         Ticket *t;
1974         char *str;
1975
1976         /*
1977          * Require that the KDC have issued the service's krbtgt (not
1978          * self-issued ticket with kimpersonate(1).
1979          */
1980         if (!signedpath) {
1981             ret = KRB5KDC_ERR_BADOPTION;
1982             kdc_log(context, config, 0,
1983                     "Constrained delegation done on service ticket %s/%s",
1984                     cpn, spn);
1985             goto out;
1986         }
1987
1988         t = &b->additional_tickets->val[0];
1989
1990         ret = hdb_enctype2key(context, &client->entry,
1991                               t->enc_part.etype, &clientkey);
1992         if(ret){
1993             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1994             goto out;
1995         }
1996
1997         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1998         if (ret) {
1999             kdc_log(context, config, 0,
2000                     "failed to decrypt ticket for "
2001                     "constrained delegation from %s to %s ", cpn, spn);
2002             goto out;
2003         }
2004
2005         /* check that ticket is valid */
2006         if (adtkt.flags.forwardable == 0) {
2007             kdc_log(context, config, 0,
2008                     "Missing forwardable flag on ticket for "
2009                     "constrained delegation from %s to %s ", cpn, spn);
2010             ret = KRB5KDC_ERR_BADOPTION;
2011             goto out;
2012         }
2013
2014         ret = check_constrained_delegation(context, config, clientdb, 
2015                                            client, sp);
2016         if (ret) {
2017             kdc_log(context, config, 0,
2018                     "constrained delegation from %s to %s not allowed",
2019                     cpn, spn);
2020             goto out;
2021         }
2022
2023         ret = _krb5_principalname2krb5_principal(context,
2024                                                  &client_principal,
2025                                                  adtkt.cname,
2026                                                  adtkt.crealm);
2027         if (ret)
2028             goto out;
2029
2030         ret = krb5_unparse_name(context, client_principal, &str);
2031         if (ret)
2032             goto out;
2033
2034         ret = verify_flags(context, config, &adtkt, str);
2035         if (ret) {
2036             free(str);
2037             goto out;
2038         }
2039
2040         /*
2041          * Check that the KDC issued the user's ticket.
2042          */
2043         ret = check_KRB5SignedPath(context,
2044                                    config,
2045                                    krbtgt,
2046                                    cp,
2047                                    &adtkt,
2048                                    NULL,
2049                                    &ad_signedpath);
2050         if (ret == 0 && !ad_signedpath)
2051             ret = KRB5KDC_ERR_BADOPTION;
2052         if (ret) {
2053             const char *msg = krb5_get_error_message(context, ret);
2054             kdc_log(context, config, 0,
2055                     "KRB5SignedPath check from service %s failed "
2056                     "for delegation to %s for client %s "
2057                     "from %s failed with %s",
2058                     spn, str, cpn, from, msg);
2059             krb5_free_error_message(context, msg);
2060             free(str);
2061             goto out;
2062         }
2063
2064         kdc_log(context, config, 0, "constrained delegation for %s "
2065                 "from %s to %s", str, cpn, spn);
2066         free(str);
2067     }
2068
2069     /*
2070      * Check flags
2071      */
2072
2073     ret = kdc_check_flags(context, config,
2074                           client, cpn,
2075                           server, spn,
2076                           FALSE);
2077     if(ret)
2078         goto out;
2079
2080     if((b->kdc_options.validate || b->kdc_options.renew) &&
2081        !krb5_principal_compare(context,
2082                                krbtgt->entry.principal,
2083                                server->entry.principal)){
2084         kdc_log(context, config, 0, "Inconsistent request.");
2085         ret = KRB5KDC_ERR_SERVER_NOMATCH;
2086         goto out;
2087     }
2088
2089     /* check for valid set of addresses */
2090     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2091         ret = KRB5KRB_AP_ERR_BADADDR;
2092         kdc_log(context, config, 0, "Request from wrong address");
2093         goto out;
2094     }
2095         
2096     /*
2097      * If this is an referral, add server referral data to the
2098      * auth_data reply .
2099      */
2100     if (ref_realm) {
2101         PA_DATA pa;
2102         krb5_crypto crypto;
2103
2104         kdc_log(context, config, 0,
2105                 "Adding server referral to %s", ref_realm);
2106
2107         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2108         if (ret)
2109             goto out;
2110
2111         ret = build_server_referral(context, config, crypto, ref_realm,
2112                                     NULL, s, &pa.padata_value);
2113         krb5_crypto_destroy(context, crypto);
2114         if (ret) {
2115             kdc_log(context, config, 0,
2116                     "Failed building server referral");
2117             goto out;
2118         }
2119         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2120
2121         ret = add_METHOD_DATA(&enc_pa_data, &pa);
2122         krb5_data_free(&pa.padata_value);
2123         if (ret) {
2124             kdc_log(context, config, 0,
2125                     "Add server referral METHOD-DATA failed");
2126             goto out;
2127         }
2128     }
2129
2130     /*
2131      *
2132      */
2133
2134     ret = tgs_make_reply(context,
2135                          config,
2136                          b,
2137                          client_principal,
2138                          tgt,
2139                          replykey,
2140                          rk_is_subkey,
2141                          ekey,
2142                          &sessionkey,
2143                          kvno,
2144                          *auth_data,
2145                          server,
2146                          sp,
2147                          spn,
2148                          client,
2149                          cp,
2150                          krbtgt_out,
2151                          krbtgt_etype,
2152                          spp,
2153                          &rspac,
2154                          &enc_pa_data,
2155                          e_text,
2156                          reply);
2157         
2158 out:
2159     free(spn);
2160     free(cpn);
2161         
2162     krb5_data_free(&rspac);
2163     krb5_free_keyblock_contents(context, &sessionkey);
2164     if(krbtgt_out)
2165         _kdc_free_ent(context, krbtgt_out);
2166     if(server)
2167         _kdc_free_ent(context, server);
2168     if(client)
2169         _kdc_free_ent(context, client);
2170     if(s4u2self_impersonated_client)
2171         _kdc_free_ent(context, s4u2self_impersonated_client);
2172
2173     if (client_principal && client_principal != cp)
2174         krb5_free_principal(context, client_principal);
2175     if (cp)
2176         krb5_free_principal(context, cp);
2177     if (sp)
2178         krb5_free_principal(context, sp);
2179     if (ref_realm)
2180         free(ref_realm);
2181     free_METHOD_DATA(&enc_pa_data);
2182
2183     free_EncTicketPart(&adtkt);
2184
2185     return ret;
2186 }
2187
2188 /*
2189  *
2190  */
2191
2192 krb5_error_code
2193 _kdc_tgs_rep(krb5_context context,
2194              krb5_kdc_configuration *config,
2195              KDC_REQ *req,
2196              krb5_data *data,
2197              const char *from,
2198              struct sockaddr *from_addr,
2199              int datagram_reply)
2200 {
2201     AuthorizationData *auth_data = NULL;
2202     krb5_error_code ret;
2203     int i = 0;
2204     const PA_DATA *tgs_req;
2205
2206     hdb_entry_ex *krbtgt = NULL;
2207     krb5_ticket *ticket = NULL;
2208     const char *e_text = NULL;
2209     krb5_enctype krbtgt_etype = ETYPE_NULL;
2210
2211     krb5_keyblock *replykey = NULL;
2212     int rk_is_subkey = 0;
2213     time_t *csec = NULL;
2214     int *cusec = NULL;
2215
2216     if(req->padata == NULL){
2217         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2218         kdc_log(context, config, 0,
2219                 "TGS-REQ from %s without PA-DATA", from);
2220         goto out;
2221     }
2222
2223     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2224
2225     if(tgs_req == NULL){
2226         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2227         
2228         kdc_log(context, config, 0,
2229                 "TGS-REQ from %s without PA-TGS-REQ", from);
2230         goto out;
2231     }
2232     ret = tgs_parse_request(context, config,
2233                             &req->req_body, tgs_req,
2234                             &krbtgt,
2235                             &krbtgt_etype,
2236                             &ticket,
2237                             &e_text,
2238                             from, from_addr,
2239                             &csec, &cusec,
2240                             &auth_data,
2241                             &replykey,
2242                             &rk_is_subkey);
2243     if (ret) {
2244         kdc_log(context, config, 0,
2245                 "Failed parsing TGS-REQ from %s", from);
2246         goto out;
2247     }
2248
2249     ret = tgs_build_reply(context,
2250                           config,
2251                           req,
2252                           &req->req_body,
2253                           krbtgt,
2254                           krbtgt_etype,
2255                           replykey,
2256                           rk_is_subkey,
2257                           ticket,
2258                           data,
2259                           from,
2260                           &e_text,
2261                           &auth_data,
2262                           from_addr);
2263     if (ret) {
2264         kdc_log(context, config, 0,
2265                 "Failed building TGS-REP to %s", from);
2266         goto out;
2267     }
2268
2269     /* */
2270     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2271         krb5_data_free(data);
2272         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2273         e_text = "Reply packet too large";
2274     }
2275
2276 out:
2277     if (replykey)
2278         krb5_free_keyblock(context, replykey);
2279     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2280         krb5_mk_error(context,
2281                       ret,
2282                       NULL,
2283                       NULL,
2284                       NULL,
2285                       NULL,
2286                       csec,
2287                       cusec,
2288                       data);
2289         ret = 0;
2290     }
2291     free(csec);
2292     free(cusec);
2293     if (ticket)
2294         krb5_free_ticket(context, ticket);
2295     if(krbtgt)
2296         _kdc_free_ent(context, krbtgt);
2297
2298     if (auth_data) {
2299         free_AuthorizationData(auth_data);
2300         free(auth_data);
2301     }
2302
2303     return ret;
2304 }