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