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