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