s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e89...
[amitay/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_const_principal server,
110                         krb5_principals principals,
111                         EncTicketPart *tkt)
112 {
113     krb5_error_code ret;
114     KRB5SignedPath sp;
115     krb5_data data;
116     krb5_crypto crypto = NULL;
117     size_t size;
118
119     if (server && principals) {
120         ret = add_Principals(principals, server);
121         if (ret)
122             return ret;
123     }
124
125     {
126         KRB5SignedPathData spd;
127         
128         spd.encticket = *tkt;
129         spd.delegated = principals;
130         
131         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
132                            &spd, &size, ret);
133         if (ret)
134             return ret;
135         if (data.length != size)
136             krb5_abortx(context, "internal asn.1 encoder error");
137     }
138
139     {
140         Key *key;
141         ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
142         if (ret == 0)
143             ret = krb5_crypto_init(context, &key->key, 0, &crypto);
144         if (ret) {
145             free(data.data);
146             return ret;
147         }
148     }
149
150     /*
151      * Fill in KRB5SignedPath
152      */
153
154     sp.etype = enctype;
155     sp.delegated = principals;
156
157     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
158                                data.data, data.length, &sp.cksum);
159     krb5_crypto_destroy(context, crypto);
160     free(data.data);
161     if (ret)
162         return ret;
163
164     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
165     free_Checksum(&sp.cksum);
166     if (ret)
167         return ret;
168     if (data.length != size)
169         krb5_abortx(context, "internal asn.1 encoder error");
170
171
172     /*
173      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
174      * authorization data field.
175      */
176
177     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
178                                       KRB5_AUTHDATA_SIGNTICKET, &data);
179     krb5_data_free(&data);
180
181     return ret;
182 }
183
184 static krb5_error_code
185 check_KRB5SignedPath(krb5_context context,
186                      krb5_kdc_configuration *config,
187                      hdb_entry_ex *krbtgt,
188                      EncTicketPart *tkt,
189                      krb5_principals *delegated,
190                      int *signedpath)
191 {
192     krb5_error_code ret;
193     krb5_data data;
194     krb5_crypto crypto = NULL;
195
196     if (delegated)
197         *delegated = NULL;
198
199     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
200     if (ret == 0) {
201         KRB5SignedPathData spd;
202         KRB5SignedPath sp;
203         AuthorizationData *ad;
204         size_t size;
205
206         ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
207         krb5_data_free(&data);
208         if (ret)
209             return ret;
210
211         spd.encticket = *tkt;
212         /* the KRB5SignedPath is the last entry */
213         ad = spd.encticket.authorization_data;
214         if (--ad->len == 0)
215             spd.encticket.authorization_data = NULL;
216         spd.delegated = sp.delegated;
217
218         ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219                            &spd, &size, ret);
220         ad->len++;
221         spd.encticket.authorization_data = ad;
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             return ret;
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_entry_ex *client,
496                              krb5_const_principal server)
497 {
498     const HDB_Ext_Constrained_delegation_acl *acl;
499     krb5_error_code ret;
500     int i;
501
502     ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
503     if (ret) {
504         krb5_clear_error_message(context);
505         return ret;
506     }
507
508     if (acl) {
509         for (i = 0; i < acl->len; i++) {
510             if (krb5_principal_compare(context, server, &acl->val[i]) == TRUE)
511                 return 0;
512         }
513     }
514     kdc_log(context, config, 0,
515             "Bad request for constrained delegation");
516     return KRB5KDC_ERR_BADOPTION;
517 }
518
519 /*
520  *
521  */
522
523 static krb5_error_code
524 verify_flags (krb5_context context,
525               krb5_kdc_configuration *config,
526               const EncTicketPart *et,
527               const char *pstr)
528 {
529     if(et->endtime < kdc_time){
530         kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
531         return KRB5KRB_AP_ERR_TKT_EXPIRED;
532     }
533     if(et->flags.invalid){
534         kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
535         return KRB5KRB_AP_ERR_TKT_NYV;
536     }
537     return 0;
538 }
539
540 /*
541  *
542  */
543
544 static krb5_error_code
545 fix_transited_encoding(krb5_context context,
546                        krb5_kdc_configuration *config,
547                        krb5_boolean check_policy,
548                        const TransitedEncoding *tr,
549                        EncTicketPart *et,
550                        const char *client_realm,
551                        const char *server_realm,
552                        const char *tgt_realm)
553 {
554     krb5_error_code ret = 0;
555     char **realms, **tmp;
556     unsigned int num_realms;
557     int i;
558
559     switch (tr->tr_type) {
560     case DOMAIN_X500_COMPRESS:
561         break;
562     case 0:
563         /*
564          * Allow empty content of type 0 because that is was Microsoft
565          * generates in their TGT.
566          */
567         if (tr->contents.length == 0)
568             break;
569         kdc_log(context, config, 0,
570                 "Transited type 0 with non empty content");
571         return KRB5KDC_ERR_TRTYPE_NOSUPP;
572     default:
573         kdc_log(context, config, 0,
574                 "Unknown transited type: %u", tr->tr_type);
575         return KRB5KDC_ERR_TRTYPE_NOSUPP;
576     }
577
578     ret = krb5_domain_x500_decode(context,
579                                   tr->contents,
580                                   &realms,
581                                   &num_realms,
582                                   client_realm,
583                                   server_realm);
584     if(ret){
585         krb5_warn(context, ret,
586                   "Decoding transited encoding");
587         return ret;
588     }
589     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
590         /* not us, so add the previous realm to transited set */
591         if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
592             ret = ERANGE;
593             goto free_realms;
594         }
595         tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
596         if(tmp == NULL){
597             ret = ENOMEM;
598             goto free_realms;
599         }
600         realms = tmp;
601         realms[num_realms] = strdup(tgt_realm);
602         if(realms[num_realms] == NULL){
603             ret = ENOMEM;
604             goto free_realms;
605         }
606         num_realms++;
607     }
608     if(num_realms == 0) {
609         if(strcmp(client_realm, server_realm))
610             kdc_log(context, config, 0,
611                     "cross-realm %s -> %s", client_realm, server_realm);
612     } else {
613         size_t l = 0;
614         char *rs;
615         for(i = 0; i < num_realms; i++)
616             l += strlen(realms[i]) + 2;
617         rs = malloc(l);
618         if(rs != NULL) {
619             *rs = '\0';
620             for(i = 0; i < num_realms; i++) {
621                 if(i > 0)
622                     strlcat(rs, ", ", l);
623                 strlcat(rs, realms[i], l);
624             }
625             kdc_log(context, config, 0,
626                     "cross-realm %s -> %s via [%s]",
627                     client_realm, server_realm, rs);
628             free(rs);
629         }
630     }
631     if(check_policy) {
632         ret = krb5_check_transited(context, client_realm,
633                                    server_realm,
634                                    realms, num_realms, NULL);
635         if(ret) {
636             krb5_warn(context, ret, "cross-realm %s -> %s",
637                       client_realm, server_realm);
638             goto free_realms;
639         }
640         et->flags.transited_policy_checked = 1;
641     }
642     et->transited.tr_type = DOMAIN_X500_COMPRESS;
643     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
644     if(ret)
645         krb5_warn(context, ret, "Encoding transited encoding");
646   free_realms:
647     for(i = 0; i < num_realms; i++)
648         free(realms[i]);
649     free(realms);
650     return ret;
651 }
652
653
654 static krb5_error_code
655 tgs_make_reply(krb5_context context,
656                krb5_kdc_configuration *config,
657                KDC_REQ_BODY *b,
658                krb5_const_principal tgt_name,
659                const EncTicketPart *tgt,
660                const EncryptionKey *serverkey,
661                const krb5_keyblock *sessionkey,
662                krb5_kvno kvno,
663                AuthorizationData *auth_data,
664                hdb_entry_ex *server,
665                krb5_principal server_principal,
666                const char *server_name,
667                hdb_entry_ex *client,
668                krb5_principal client_principal,
669                hdb_entry_ex *krbtgt,
670                krb5_enctype krbtgt_etype,
671                krb5_principals spp,
672                const krb5_data *rspac,
673                const METHOD_DATA *enc_pa_data,
674                const char **e_text,
675                krb5_data *reply)
676 {
677     KDC_REP rep;
678     EncKDCRepPart ek;
679     EncTicketPart et;
680     KDCOptions f = b->kdc_options;
681     krb5_error_code ret;
682     int is_weak = 0;
683
684     memset(&rep, 0, sizeof(rep));
685     memset(&et, 0, sizeof(et));
686     memset(&ek, 0, sizeof(ek));
687
688     rep.pvno = 5;
689     rep.msg_type = krb_tgs_rep;
690
691     et.authtime = tgt->authtime;
692     _kdc_fix_time(&b->till);
693     et.endtime = min(tgt->endtime, *b->till);
694     ALLOC(et.starttime);
695     *et.starttime = kdc_time;
696
697     ret = check_tgs_flags(context, config, b, tgt, &et);
698     if(ret)
699         goto out;
700
701     /* We should check the transited encoding if:
702        1) the request doesn't ask not to be checked
703        2) globally enforcing a check
704        3) principal requires checking
705        4) we allow non-check per-principal, but principal isn't marked as allowing this
706        5) we don't globally allow this
707     */
708
709 #define GLOBAL_FORCE_TRANSITED_CHECK            \
710     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
711 #define GLOBAL_ALLOW_PER_PRINCIPAL                      \
712     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
713 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                    \
714     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
715
716 /* these will consult the database in future release */
717 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)              0
718 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)      0
719
720     ret = fix_transited_encoding(context, config,
721                                  !f.disable_transited_check ||
722                                  GLOBAL_FORCE_TRANSITED_CHECK ||
723                                  PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
724                                  !((GLOBAL_ALLOW_PER_PRINCIPAL &&
725                                     PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
726                                    GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
727                                  &tgt->transited, &et,
728                                  krb5_principal_get_realm(context, client_principal),
729                                  krb5_principal_get_realm(context, server->entry.principal),
730                                  krb5_principal_get_realm(context, krbtgt->entry.principal));
731     if(ret)
732         goto out;
733
734     copy_Realm(&server_principal->realm, &rep.ticket.realm);
735     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
736     copy_Realm(&tgt_name->realm, &rep.crealm);
737 /*
738     if (f.request_anonymous)
739         _kdc_make_anonymous_principalname (&rep.cname);
740     else */
741
742     copy_PrincipalName(&tgt_name->name, &rep.cname);
743     rep.ticket.tkt_vno = 5;
744
745     ek.caddr = et.caddr;
746     if(et.caddr == NULL)
747         et.caddr = tgt->caddr;
748
749     {
750         time_t life;
751         life = et.endtime - *et.starttime;
752         if(client && client->entry.max_life)
753             life = min(life, *client->entry.max_life);
754         if(server->entry.max_life)
755             life = min(life, *server->entry.max_life);
756         et.endtime = *et.starttime + life;
757     }
758     if(f.renewable_ok && tgt->flags.renewable &&
759        et.renew_till == NULL && et.endtime < *b->till){
760         et.flags.renewable = 1;
761         ALLOC(et.renew_till);
762         *et.renew_till = *b->till;
763     }
764     if(et.renew_till){
765         time_t renew;
766         renew = *et.renew_till - et.authtime;
767         if(client && client->entry.max_renew)
768             renew = min(renew, *client->entry.max_renew);
769         if(server->entry.max_renew)
770             renew = min(renew, *server->entry.max_renew);
771         *et.renew_till = et.authtime + renew;
772     }
773         
774     if(et.renew_till){
775         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
776         *et.starttime = min(*et.starttime, *et.renew_till);
777         et.endtime = min(et.endtime, *et.renew_till);
778     }
779
780     *et.starttime = min(*et.starttime, et.endtime);
781
782     if(*et.starttime == et.endtime){
783         ret = KRB5KDC_ERR_NEVER_VALID;
784         goto out;
785     }
786     if(et.renew_till && et.endtime == *et.renew_till){
787         free(et.renew_till);
788         et.renew_till = NULL;
789         et.flags.renewable = 0;
790     }
791
792     et.flags.pre_authent = tgt->flags.pre_authent;
793     et.flags.hw_authent  = tgt->flags.hw_authent;
794     et.flags.anonymous   = tgt->flags.anonymous;
795     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
796         
797     if (auth_data) {
798         /* XXX Check enc-authorization-data */
799         et.authorization_data = calloc(1, sizeof(*et.authorization_data));
800         if (et.authorization_data == NULL) {
801             ret = ENOMEM;
802             goto out;
803         }
804         ret = copy_AuthorizationData(auth_data, et.authorization_data);
805         if (ret)
806             goto out;
807
808         /* Filter out type KRB5SignedPath */
809         ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
810         if (ret == 0) {
811             if (et.authorization_data->len == 1) {
812                 free_AuthorizationData(et.authorization_data);
813                 free(et.authorization_data);
814                 et.authorization_data = NULL;
815             } else {
816                 AuthorizationData *ad = et.authorization_data;
817                 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
818                 ad->len--;
819             }
820         }
821     }
822
823     if(rspac->length) {
824         /*
825          * No not need to filter out the any PAC from the
826          * auth_data since it's signed by the KDC.
827          */
828         ret = _kdc_tkt_add_if_relevant_ad(context, &et,
829                                           KRB5_AUTHDATA_WIN2K_PAC,
830                                           rspac);
831         if (ret)
832             goto out;
833     }
834
835     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
836     if (ret)
837         goto out;
838     et.crealm = tgt->crealm;
839     et.cname = tgt_name->name;
840         
841     ek.key = et.key;
842     /* MIT must have at least one last_req */
843     ek.last_req.len = 1;
844     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
845     if (ek.last_req.val == NULL) {
846         ret = ENOMEM;
847         goto out;
848     }
849     ek.nonce = b->nonce;
850     ek.flags = et.flags;
851     ek.authtime = et.authtime;
852     ek.starttime = et.starttime;
853     ek.endtime = et.endtime;
854     ek.renew_till = et.renew_till;
855     ek.srealm = rep.ticket.realm;
856     ek.sname = rep.ticket.sname;
857
858     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
859                        et.endtime, et.renew_till);
860
861     /* Don't sign cross realm tickets, they can't be checked anyway */
862     {
863         char *r = get_krbtgt_realm(&ek.sname);
864
865         if (r == NULL || strcmp(r, ek.srealm) == 0) {
866             ret = _kdc_add_KRB5SignedPath(context,
867                                           config,
868                                           krbtgt,
869                                           krbtgt_etype,
870                                           NULL,
871                                           spp,
872                                           &et);
873             if (ret)
874                 goto out;
875         }
876     }
877
878     if (enc_pa_data->len) {
879         rep.padata = calloc(1, sizeof(*rep.padata));
880         if (rep.padata == NULL) {
881             ret = ENOMEM;
882             goto out;
883         }
884         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
885         if (ret)
886             goto out;
887     }
888
889     if (krb5_enctype_valid(context, et.key.keytype) != 0
890         && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
891     {
892         krb5_enctype_enable(context, et.key.keytype);
893         is_weak = 1;
894     }
895
896
897     /* It is somewhat unclear where the etype in the following
898        encryption should come from. What we have is a session
899        key in the passed tgt, and a list of preferred etypes
900        *for the new ticket*. Should we pick the best possible
901        etype, given the keytype in the tgt, or should we look
902        at the etype list here as well?  What if the tgt
903        session key is DES3 and we want a ticket with a (say)
904        CAST session key. Should the DES3 etype be added to the
905        etype list, even if we don't want a session key with
906        DES3? */
907     ret = _kdc_encode_reply(context, config,
908                             &rep, &et, &ek, et.key.keytype,
909                             kvno,
910                             serverkey, 0, &tgt->key, e_text, reply);
911     if (is_weak)
912         krb5_enctype_disable(context, et.key.keytype);
913
914 out:
915     free_TGS_REP(&rep);
916     free_TransitedEncoding(&et.transited);
917     if(et.starttime)
918         free(et.starttime);
919     if(et.renew_till)
920         free(et.renew_till);
921     if(et.authorization_data) {
922         free_AuthorizationData(et.authorization_data);
923         free(et.authorization_data);
924     }
925     free_LastReq(&ek.last_req);
926     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
927     free_EncryptionKey(&et.key);
928     return ret;
929 }
930
931 static krb5_error_code
932 tgs_check_authenticator(krb5_context context,
933                         krb5_kdc_configuration *config,
934                         krb5_auth_context ac,
935                         KDC_REQ_BODY *b,
936                         const char **e_text,
937                         krb5_keyblock *key)
938 {
939     krb5_authenticator auth;
940     size_t len;
941     unsigned char *buf;
942     size_t buf_size;
943     krb5_error_code ret;
944     krb5_crypto crypto;
945
946     krb5_auth_con_getauthenticator(context, ac, &auth);
947     if(auth->cksum == NULL){
948         kdc_log(context, config, 0, "No authenticator in request");
949         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
950         goto out;
951     }
952     /*
953      * according to RFC1510 it doesn't need to be keyed,
954      * but according to the latest draft it needs to.
955      */
956     if (
957 #if 0
958 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
959         ||
960 #endif
961  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
962         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
963                 auth->cksum->cksumtype);
964         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
965         goto out;
966     }
967                 
968     /* XXX should not re-encode this */
969     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
970     if(ret){
971         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
972                 krb5_get_err_text(context, ret));
973         goto out;
974     }
975     if(buf_size != len) {
976         free(buf);
977         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
978         *e_text = "KDC internal error";
979         ret = KRB5KRB_ERR_GENERIC;
980         goto out;
981     }
982     ret = krb5_crypto_init(context, key, 0, &crypto);
983     if (ret) {
984         free(buf);
985         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
986                 krb5_get_err_text(context, ret));
987         goto out;
988     }
989     ret = krb5_verify_checksum(context,
990                                crypto,
991                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
992                                buf,
993                                len,
994                                auth->cksum);
995     free(buf);
996     krb5_crypto_destroy(context, crypto);
997     if(ret){
998         kdc_log(context, config, 0,
999                 "Failed to verify authenticator checksum: %s",
1000                 krb5_get_err_text(context, ret));
1001     }
1002 out:
1003     free_Authenticator(auth);
1004     free(auth);
1005     return ret;
1006 }
1007
1008 /*
1009  *
1010  */
1011
1012 static const char *
1013 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1014 {
1015     const char *new_realm = krb5_config_get_string(context,
1016                                                    NULL,
1017                                                    "capaths",
1018                                                    crealm,
1019                                                    srealm,
1020                                                    NULL);
1021     return new_realm;
1022 }
1023         
1024
1025 static krb5_boolean
1026 need_referral(krb5_context context, krb5_kdc_configuration *config,
1027               const KDCOptions * const options, krb5_principal server,
1028               krb5_realm **realms)
1029 {
1030     const char *name;
1031
1032     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1033         return FALSE;
1034
1035     if (server->name.name_string.len == 1)
1036         name = server->name.name_string.val[0];
1037     else if (server->name.name_string.len > 1)
1038         name = server->name.name_string.val[1];
1039     else
1040         return FALSE;
1041
1042     kdc_log(context, config, 0, "Searching referral for %s", name);
1043
1044     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1045 }
1046
1047 static krb5_error_code
1048 tgs_parse_request(krb5_context context,
1049                   krb5_kdc_configuration *config,
1050                   KDC_REQ_BODY *b,
1051                   const PA_DATA *tgs_req,
1052                   hdb_entry_ex **krbtgt,
1053                   krb5_enctype *krbtgt_etype,
1054                   krb5_ticket **ticket,
1055                   const char **e_text,
1056                   const char *from,
1057                   const struct sockaddr *from_addr,
1058                   time_t **csec,
1059                   int **cusec,
1060                   AuthorizationData **auth_data)
1061 {
1062     krb5_ap_req ap_req;
1063     krb5_error_code ret;
1064     krb5_principal princ;
1065     krb5_auth_context ac = NULL;
1066     krb5_flags ap_req_options;
1067     krb5_flags verify_ap_req_flags;
1068     krb5_crypto crypto;
1069     Key *tkey;
1070
1071     *auth_data = NULL;
1072     *csec  = NULL;
1073     *cusec = NULL;
1074
1075     memset(&ap_req, 0, sizeof(ap_req));
1076     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1077     if(ret){
1078         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1079                 krb5_get_err_text(context, ret));
1080         goto out;
1081     }
1082
1083     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1084         /* XXX check for ticket.sname == req.sname */
1085         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1086         ret = KRB5KDC_ERR_POLICY; /* ? */
1087         goto out;
1088     }
1089
1090     _krb5_principalname2krb5_principal(context,
1091                                        &princ,
1092                                        ap_req.ticket.sname,
1093                                        ap_req.ticket.realm);
1094
1095     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1096
1097     if(ret) {
1098         char *p;
1099         ret = krb5_unparse_name(context, princ, &p);
1100         if (ret != 0)
1101             p = "<unparse_name failed>";
1102         krb5_free_principal(context, princ);
1103         kdc_log(context, config, 0,
1104                 "Ticket-granting ticket not found in database: %s: %s",
1105                 p, krb5_get_err_text(context, ret));
1106         if (ret == 0)
1107             free(p);
1108         ret = KRB5KRB_AP_ERR_NOT_US;
1109         goto out;
1110     }
1111
1112     if(ap_req.ticket.enc_part.kvno &&
1113        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1114         char *p;
1115
1116         ret = krb5_unparse_name (context, princ, &p);
1117         krb5_free_principal(context, princ);
1118         if (ret != 0)
1119             p = "<unparse_name failed>";
1120         kdc_log(context, config, 0,
1121                 "Ticket kvno = %d, DB kvno = %d (%s)",
1122                 *ap_req.ticket.enc_part.kvno,
1123                 (*krbtgt)->entry.kvno,
1124                 p);
1125         if (ret == 0)
1126             free (p);
1127         ret = KRB5KRB_AP_ERR_BADKEYVER;
1128         goto out;
1129     }
1130
1131     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1132
1133     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1134                           ap_req.ticket.enc_part.etype, &tkey);
1135     if(ret){
1136         char *str = NULL, *p = NULL;
1137
1138         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1139         krb5_unparse_name(context, princ, &p);
1140         kdc_log(context, config, 0,
1141                 "No server key with enctype %s found for %s",
1142                 str ? str : "<unknown enctype>",
1143                 p ? p : "<unparse_name failed>");
1144         free(str);
1145         free(p);
1146         ret = KRB5KRB_AP_ERR_BADKEYVER;
1147         goto out;
1148     }
1149
1150     if (b->kdc_options.validate)
1151         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1152     else
1153         verify_ap_req_flags = 0;
1154
1155     ret = krb5_verify_ap_req2(context,
1156                               &ac,
1157                               &ap_req,
1158                               princ,
1159                               &tkey->key,
1160                               verify_ap_req_flags,
1161                               &ap_req_options,
1162                               ticket,
1163                               KRB5_KU_TGS_REQ_AUTH);
1164                         
1165     krb5_free_principal(context, princ);
1166     if(ret) {
1167         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1168                 krb5_get_err_text(context, ret));
1169         goto out;
1170     }
1171
1172     {
1173         krb5_authenticator auth;
1174
1175         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1176         if (ret == 0) {
1177             *csec   = malloc(sizeof(**csec));
1178             if (*csec == NULL) {
1179                 krb5_free_authenticator(context, &auth);
1180                 kdc_log(context, config, 0, "malloc failed");
1181                 goto out;
1182             }
1183             **csec  = auth->ctime;
1184             *cusec  = malloc(sizeof(**cusec));
1185             if (*cusec == NULL) {
1186                 krb5_free_authenticator(context, &auth);
1187                 kdc_log(context, config, 0, "malloc failed");
1188                 goto out;
1189             }
1190             **cusec  = auth->cusec;
1191             krb5_free_authenticator(context, &auth);
1192         }
1193     }
1194
1195     ret = tgs_check_authenticator(context, config,
1196                                   ac, b, e_text, &(*ticket)->ticket.key);
1197     if (ret) {
1198         krb5_auth_con_free(context, ac);
1199         goto out;
1200     }
1201
1202     if (b->enc_authorization_data) {
1203         unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1204         krb5_keyblock *subkey;
1205         krb5_data ad;
1206
1207         ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1208         if(ret){
1209             krb5_auth_con_free(context, ac);
1210             kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1211                     krb5_get_err_text(context, ret));
1212             goto out;
1213         }
1214         if(subkey == NULL){
1215             usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1216             ret = krb5_auth_con_getkey(context, ac, &subkey);
1217             if(ret) {
1218                 krb5_auth_con_free(context, ac);
1219                 kdc_log(context, config, 0, "Failed to get session key: %s",
1220                         krb5_get_err_text(context, ret));
1221                 goto out;
1222             }
1223         }
1224         if(subkey == NULL){
1225             krb5_auth_con_free(context, ac);
1226             kdc_log(context, config, 0,
1227                     "Failed to get key for enc-authorization-data");
1228             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1229             goto out;
1230         }
1231         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1232         krb5_free_keyblock(context, subkey);
1233         if (ret) {
1234             krb5_auth_con_free(context, ac);
1235             kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1236                     krb5_get_err_text(context, ret));
1237             goto out;
1238         }
1239         ret = krb5_decrypt_EncryptedData (context,
1240                                           crypto,
1241                                           usage,
1242                                           b->enc_authorization_data,
1243                                           &ad);
1244         krb5_crypto_destroy(context, crypto);
1245         if(ret){
1246             krb5_auth_con_free(context, ac);
1247             kdc_log(context, config, 0,
1248                     "Failed to decrypt enc-authorization-data");
1249             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1250             goto out;
1251         }
1252         ALLOC(*auth_data);
1253         if (*auth_data == NULL) {
1254             krb5_auth_con_free(context, ac);
1255             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1256             goto out;
1257         }
1258         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1259         if(ret){
1260             krb5_auth_con_free(context, ac);
1261             free(*auth_data);
1262             *auth_data = NULL;
1263             kdc_log(context, config, 0, "Failed to decode authorization data");
1264             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1265             goto out;
1266         }
1267     }
1268
1269     krb5_auth_con_free(context, ac);
1270
1271 out:
1272     free_AP_REQ(&ap_req);
1273
1274     return ret;
1275 }
1276
1277 static krb5_error_code
1278 build_server_referral(krb5_context context,
1279                       krb5_kdc_configuration *config,
1280                       krb5_crypto session,
1281                       krb5_const_realm referred_realm,
1282                       const PrincipalName *true_principal_name,
1283                       const PrincipalName *requested_principal,
1284                       krb5_data *outdata)
1285 {               
1286     PA_ServerReferralData ref;
1287     krb5_error_code ret;
1288     EncryptedData ed;
1289     krb5_data data;
1290     size_t size;
1291
1292     memset(&ref, 0, sizeof(ref));
1293
1294     if (referred_realm) {
1295         ALLOC(ref.referred_realm);
1296         if (ref.referred_realm == NULL)
1297             goto eout;
1298         *ref.referred_realm = strdup(referred_realm);
1299         if (*ref.referred_realm == NULL)
1300             goto eout;
1301     }
1302     if (true_principal_name) {
1303         ALLOC(ref.true_principal_name);
1304         if (ref.true_principal_name == NULL)
1305             goto eout;
1306         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1307         if (ret)
1308             goto eout;
1309     }
1310     if (requested_principal) {
1311         ALLOC(ref.requested_principal_name);
1312         if (ref.requested_principal_name == NULL)
1313             goto eout;
1314         ret = copy_PrincipalName(requested_principal,
1315                                  ref.requested_principal_name);
1316         if (ret)
1317             goto eout;
1318     }
1319
1320     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1321                        data.data, data.length,
1322                        &ref, &size, ret);
1323     free_PA_ServerReferralData(&ref);
1324     if (ret)
1325         return ret;
1326     if (data.length != size)
1327         krb5_abortx(context, "internal asn.1 encoder error");
1328
1329     ret = krb5_encrypt_EncryptedData(context, session,
1330                                      KRB5_KU_PA_SERVER_REFERRAL,
1331                                      data.data, data.length,
1332                                      0 /* kvno */, &ed);
1333     free(data.data);
1334     if (ret)
1335         return ret;
1336
1337     ASN1_MALLOC_ENCODE(EncryptedData,
1338                        outdata->data, outdata->length,
1339                        &ed, &size, ret);
1340     free_EncryptedData(&ed);
1341     if (ret)
1342         return ret;
1343     if (outdata->length != size)
1344         krb5_abortx(context, "internal asn.1 encoder error");
1345
1346     return 0;
1347 eout:
1348     free_PA_ServerReferralData(&ref);
1349     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1350     return ENOMEM;
1351 }
1352
1353 static krb5_error_code
1354 tgs_build_reply(krb5_context context,
1355                 krb5_kdc_configuration *config,
1356                 KDC_REQ *req,
1357                 KDC_REQ_BODY *b,
1358                 hdb_entry_ex *krbtgt,
1359                 krb5_enctype krbtgt_etype,
1360                 krb5_ticket *ticket,
1361                 krb5_data *reply,
1362                 const char *from,
1363                 const char **e_text,
1364                 AuthorizationData **auth_data,
1365                 const struct sockaddr *from_addr)
1366 {
1367     krb5_error_code ret;
1368     krb5_principal cp = NULL, sp = NULL;
1369     krb5_principal client_principal = NULL;
1370     char *spn = NULL, *cpn = NULL;
1371     hdb_entry_ex *server = NULL, *client = NULL;
1372     krb5_realm ref_realm = NULL;
1373     EncTicketPart *tgt = &ticket->ticket;
1374     krb5_principals spp = NULL;
1375     const EncryptionKey *ekey;
1376     krb5_keyblock sessionkey;
1377     krb5_kvno kvno;
1378     krb5_data rspac;
1379
1380     METHOD_DATA enc_pa_data;
1381
1382     PrincipalName *s;
1383     Realm r;
1384     int nloop = 0;
1385     EncTicketPart adtkt;
1386     char opt_str[128];
1387     int signedpath = 0;
1388
1389     Key *tkey;
1390
1391     memset(&sessionkey, 0, sizeof(sessionkey));
1392     memset(&adtkt, 0, sizeof(adtkt));
1393     krb5_data_zero(&rspac);
1394     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1395
1396     s = b->sname;
1397     r = b->realm;
1398
1399     if(b->kdc_options.enc_tkt_in_skey){
1400         Ticket *t;
1401         hdb_entry_ex *uu;
1402         krb5_principal p;
1403         Key *uukey;
1404         
1405         if(b->additional_tickets == NULL ||
1406            b->additional_tickets->len == 0){
1407             ret = KRB5KDC_ERR_BADOPTION; /* ? */
1408             kdc_log(context, config, 0,
1409                     "No second ticket present in request");
1410             goto out;
1411         }
1412         t = &b->additional_tickets->val[0];
1413         if(!get_krbtgt_realm(&t->sname)){
1414             kdc_log(context, config, 0,
1415                     "Additional ticket is not a ticket-granting ticket");
1416             ret = KRB5KDC_ERR_POLICY;
1417             goto out;
1418         }
1419         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1420         ret = _kdc_db_fetch(context, config, p,
1421                             HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1422                             NULL, &uu);
1423         krb5_free_principal(context, p);
1424         if(ret){
1425             if (ret == HDB_ERR_NOENTRY)
1426                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1427             goto out;
1428         }
1429         ret = hdb_enctype2key(context, &uu->entry,
1430                               t->enc_part.etype, &uukey);
1431         if(ret){
1432             _kdc_free_ent(context, uu);
1433             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1434             goto out;
1435         }
1436         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1437         _kdc_free_ent(context, uu);
1438         if(ret)
1439             goto out;
1440
1441         ret = verify_flags(context, config, &adtkt, spn);
1442         if (ret)
1443             goto out;
1444
1445         s = &adtkt.cname;
1446         r = adtkt.crealm;
1447     }
1448
1449     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1450     ret = krb5_unparse_name(context, sp, &spn); 
1451     if (ret)
1452         goto out;
1453     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1454     ret = krb5_unparse_name(context, cp, &cpn);
1455     if (ret)
1456         goto out;
1457     unparse_flags (KDCOptions2int(b->kdc_options),
1458                    asn1_KDCOptions_units(),
1459                    opt_str, sizeof(opt_str));
1460     if(*opt_str)
1461         kdc_log(context, config, 0,
1462                 "TGS-REQ %s from %s for %s [%s]",
1463                 cpn, from, spn, opt_str);
1464     else
1465         kdc_log(context, config, 0,
1466                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1467
1468     /*
1469      * Fetch server
1470      */
1471
1472 server_lookup:
1473     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1474                         NULL, &server);
1475
1476     if(ret){
1477         const char *new_rlm;
1478         Realm req_rlm;
1479         krb5_realm *realms;
1480
1481         if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1482             if(nloop++ < 2) {
1483                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1484                 if(new_rlm) {
1485                     kdc_log(context, config, 5, "krbtgt for realm %s "
1486                             "not found, trying %s",
1487                             req_rlm, new_rlm);
1488                     krb5_free_principal(context, sp);
1489                     free(spn);
1490                     krb5_make_principal(context, &sp, r,
1491                                         KRB5_TGS_NAME, new_rlm, NULL);
1492                     ret = krb5_unparse_name(context, sp, &spn); 
1493                     if (ret)
1494                         goto out;
1495
1496                     if (ref_realm)
1497                         free(ref_realm);
1498                     ref_realm = strdup(new_rlm);
1499                     goto server_lookup;
1500                 }
1501             }
1502         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1503             if (strcmp(realms[0], sp->realm) != 0) {
1504                 kdc_log(context, config, 5,
1505                         "Returning a referral to realm %s for "
1506                         "server %s that was not found",
1507                         realms[0], spn);
1508                 krb5_free_principal(context, sp);
1509                 free(spn);
1510                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1511                                     realms[0], NULL);
1512                 ret = krb5_unparse_name(context, sp, &spn);
1513                 if (ret)
1514                     goto out;
1515
1516                 if (ref_realm)
1517                     free(ref_realm);
1518                 ref_realm = strdup(realms[0]);
1519
1520                 krb5_free_host_realm(context, realms);
1521                 goto server_lookup;
1522             }
1523             krb5_free_host_realm(context, realms);
1524         }
1525         kdc_log(context, config, 0,
1526                 "Server not found in database: %s: %s", spn,
1527                 krb5_get_err_text(context, ret));
1528         if (ret == HDB_ERR_NOENTRY)
1529             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1530         goto out;
1531     }
1532
1533     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1534                         NULL, &client);
1535     if(ret) {
1536         const char *krbtgt_realm;
1537
1538         /*
1539          * If the client belongs to the same realm as our krbtgt, it
1540          * should exist in the local database.
1541          *
1542          */
1543
1544         krbtgt_realm =
1545             krb5_principal_get_comp_string(context,
1546                                            krbtgt->entry.principal, 1);
1547
1548         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1549             if (ret == HDB_ERR_NOENTRY)
1550                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1551             kdc_log(context, config, 1, "Client no longer in database: %s",
1552                     cpn);
1553             goto out;
1554         }
1555         
1556         kdc_log(context, config, 1, "Client not found in database: %s: %s",
1557                 cpn, krb5_get_err_text(context, ret));
1558     }
1559
1560     /*
1561      * Select enctype, return key and kvno.
1562      */
1563
1564     {
1565         krb5_enctype etype;
1566
1567         if(b->kdc_options.enc_tkt_in_skey) {
1568             int i;
1569             ekey = &adtkt.key;
1570             for(i = 0; i < b->etype.len; i++)
1571                 if (b->etype.val[i] == adtkt.key.keytype)
1572                     break;
1573             if(i == b->etype.len) {
1574                 kdc_log(context, config, 0,
1575                         "Addition ticket have not matching etypes");
1576                 krb5_clear_error_message(context);
1577                 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1578                 goto out;
1579             }
1580             etype = b->etype.val[i];
1581             kvno = 0;
1582         } else {
1583             Key *skey;
1584         
1585             ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1586                                   &skey, &etype);
1587             if(ret) {
1588                 kdc_log(context, config, 0,
1589                         "Server (%s) has no support for etypes", spn);
1590                 goto out;
1591             }
1592             ekey = &skey->key;
1593             kvno = server->entry.kvno;
1594         }
1595         
1596         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1597         if (ret)
1598             goto out;
1599     }
1600
1601     /*
1602      * Check that service is in the same realm as the krbtgt. If it's
1603      * not the same, it's someone that is using a uni-directional trust
1604      * backward.
1605      */
1606
1607     if (strcmp(krb5_principal_get_realm(context, sp),
1608                krb5_principal_get_comp_string(context,
1609                                               krbtgt->entry.principal,
1610                                               1)) != 0) {
1611         char *tpn;
1612         ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1613         kdc_log(context, config, 0,
1614                 "Request with wrong krbtgt: %s",
1615                 (ret == 0) ? tpn : "<unknown>");
1616         if(ret == 0)
1617             free(tpn);
1618         ret = KRB5KRB_AP_ERR_NOT_US;
1619         goto out;
1620     }
1621
1622     /*
1623      * Validate authoriation data
1624      */
1625
1626     ret = hdb_enctype2key(context, &krbtgt->entry,
1627                           krbtgt_etype, &tkey);
1628     if(ret) {
1629         kdc_log(context, config, 0,
1630                     "Failed to find key for krbtgt PAC check");
1631         goto out;
1632     }
1633
1634     ret = check_PAC(context, config, cp,
1635                     client, server, ekey, &tkey->key,
1636                     tgt, &rspac, &signedpath);
1637     if (ret) {
1638         kdc_log(context, config, 0,
1639                 "Verify PAC failed for %s (%s) from %s with %s",
1640                 spn, cpn, from, krb5_get_err_text(context, ret));
1641         goto out;
1642     }
1643
1644     /* also check the krbtgt for signature */
1645     ret = check_KRB5SignedPath(context,
1646                                config,
1647                                krbtgt,
1648                                tgt,
1649                                &spp,
1650                                &signedpath);
1651     if (ret) {
1652         kdc_log(context, config, 0,
1653                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1654                 spn, cpn, from, krb5_get_err_text(context, ret));
1655         goto out;
1656     }
1657
1658     /*
1659      * Process request
1660      */
1661
1662     client_principal = cp;
1663
1664     if (client) {
1665         const PA_DATA *sdata;
1666         int i = 0;
1667
1668         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1669         if (sdata) {
1670             krb5_crypto crypto;
1671             krb5_data datack;
1672             PA_S4U2Self self;
1673             char *selfcpn = NULL;
1674             const char *str;
1675
1676             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1677                                      sdata->padata_value.length,
1678                                      &self, NULL);
1679             if (ret) {
1680                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1681                 goto out;
1682             }
1683
1684             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1685             if (ret)
1686                 goto out;
1687
1688             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1689             if (ret) {
1690                 free_PA_S4U2Self(&self);
1691                 krb5_data_free(&datack);
1692                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1693                         krb5_get_err_text(context, ret));
1694                 goto out;
1695             }
1696
1697             ret = krb5_verify_checksum(context,
1698                                        crypto,
1699                                        KRB5_KU_OTHER_CKSUM,
1700                                        datack.data,
1701                                        datack.length,
1702                                        &self.cksum);
1703             krb5_data_free(&datack);
1704             krb5_crypto_destroy(context, crypto);
1705             if (ret) {
1706                 free_PA_S4U2Self(&self);
1707                 kdc_log(context, config, 0,
1708                         "krb5_verify_checksum failed for S4U2Self: %s",
1709                         krb5_get_err_text(context, ret));
1710                 goto out;
1711             }
1712
1713             ret = _krb5_principalname2krb5_principal(context,
1714                                                      &client_principal,
1715                                                      self.name,
1716                                                      self.realm);
1717             free_PA_S4U2Self(&self);
1718             if (ret)
1719                 goto out;
1720
1721             ret = krb5_unparse_name(context, client_principal, &selfcpn);       
1722             if (ret)
1723                 goto out;
1724
1725             /*
1726              * Check that service doing the impersonating is
1727              * requesting a ticket to it-self.
1728              */
1729             if (krb5_principal_compare(context, cp, sp) != TRUE) {
1730                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1731                         "to impersonate some other user "
1732                         "(tried for user %s to service %s)",
1733                         cpn, selfcpn, spn);
1734                 free(selfcpn);
1735                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1736                 goto out;
1737             }
1738
1739             /*
1740              * If the service isn't trusted for authentication to
1741              * delegation, remove the forward flag.
1742              */
1743
1744             if (client->entry.flags.trusted_for_delegation) {
1745                 str = "[forwardable]";
1746             } else {
1747                 b->kdc_options.forwardable = 0;
1748                 str = "";
1749             }
1750             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1751                     "service %s %s", cpn, selfcpn, spn, str);
1752             free(selfcpn);
1753         }
1754     }
1755
1756     /*
1757      * Constrained delegation
1758      */
1759
1760     if (client != NULL
1761         && b->additional_tickets != NULL
1762         && b->additional_tickets->len != 0
1763         && b->kdc_options.enc_tkt_in_skey == 0)
1764     {
1765         int ad_signedpath = 0;
1766         Key *clientkey;
1767         Ticket *t;
1768         char *str;
1769
1770         /*
1771          * Require that the KDC have issued the service's krbtgt (not
1772          * self-issued ticket with kimpersonate(1).
1773          */
1774         if (!signedpath) {
1775             ret = KRB5KDC_ERR_BADOPTION;
1776             kdc_log(context, config, 0,
1777                     "Constrained delegation done on service ticket %s/%s",
1778                     cpn, spn);
1779             goto out;
1780         }
1781
1782         t = &b->additional_tickets->val[0];
1783
1784         ret = hdb_enctype2key(context, &client->entry,
1785                               t->enc_part.etype, &clientkey);
1786         if(ret){
1787             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1788             goto out;
1789         }
1790
1791         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1792         if (ret) {
1793             kdc_log(context, config, 0,
1794                     "failed to decrypt ticket for "
1795                     "constrained delegation from %s to %s ", spn, cpn);
1796             goto out;
1797         }
1798
1799         /* check that ticket is valid */
1800         if (adtkt.flags.forwardable == 0) {
1801             kdc_log(context, config, 0,
1802                     "Missing forwardable flag on ticket for "
1803                     "constrained delegation from %s to %s ", spn, cpn);
1804             ret = KRB5KDC_ERR_BADOPTION;
1805             goto out;
1806         }
1807
1808         ret = check_constrained_delegation(context, config, client, sp);
1809         if (ret) {
1810             kdc_log(context, config, 0,
1811                     "constrained delegation from %s to %s not allowed",
1812                     spn, cpn);
1813             goto out;
1814         }
1815
1816         ret = _krb5_principalname2krb5_principal(context,
1817                                                  &client_principal,
1818                                                  adtkt.cname,
1819                                                  adtkt.crealm);
1820         if (ret)
1821             goto out;
1822
1823         ret = krb5_unparse_name(context, client_principal, &str);
1824         if (ret)
1825             goto out;
1826
1827         ret = verify_flags(context, config, &adtkt, str);
1828         if (ret) {
1829             free(str);
1830             goto out;
1831         }
1832
1833         /*
1834          * Check that the KDC issued the user's ticket.
1835          */
1836         ret = check_KRB5SignedPath(context,
1837                                    config,
1838                                    krbtgt,
1839                                    &adtkt,
1840                                    NULL,
1841                                    &ad_signedpath);
1842         if (ret == 0 && !ad_signedpath)
1843             ret = KRB5KDC_ERR_BADOPTION;
1844         if (ret) {
1845             kdc_log(context, config, 0,
1846                     "KRB5SignedPath check from service %s failed "
1847                     "for delegation to %s for client %s "
1848                     "from %s failed with %s",
1849                     spn, str, cpn, from, krb5_get_err_text(context, ret));
1850             free(str);
1851             goto out;
1852         }
1853
1854         kdc_log(context, config, 0, "constrained delegation for %s "
1855                 "from %s to %s", str, cpn, spn);
1856         free(str);
1857     }
1858
1859     /*
1860      * Check flags
1861      */
1862
1863     ret = _kdc_check_flags(context, config,
1864                            client, cpn,
1865                            server, spn,
1866                            FALSE);
1867     if(ret)
1868         goto out;
1869
1870     if((b->kdc_options.validate || b->kdc_options.renew) &&
1871        !krb5_principal_compare(context,
1872                                krbtgt->entry.principal,
1873                                server->entry.principal)){
1874         kdc_log(context, config, 0, "Inconsistent request.");
1875         ret = KRB5KDC_ERR_SERVER_NOMATCH;
1876         goto out;
1877     }
1878
1879     /* check for valid set of addresses */
1880     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1881         ret = KRB5KRB_AP_ERR_BADADDR;
1882         kdc_log(context, config, 0, "Request from wrong address");
1883         goto out;
1884     }
1885         
1886     /*
1887      * If this is an referral, add server referral data to the
1888      * auth_data reply .
1889      */
1890     if (ref_realm) {
1891         PA_DATA pa;
1892         krb5_crypto crypto;
1893
1894         kdc_log(context, config, 0,
1895                 "Adding server referral to %s", ref_realm);
1896
1897         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1898         if (ret)
1899             goto out;
1900
1901         ret = build_server_referral(context, config, crypto, ref_realm,
1902                                     NULL, s, &pa.padata_value);
1903         krb5_crypto_destroy(context, crypto);
1904         if (ret) {
1905             kdc_log(context, config, 0,
1906                     "Failed building server referral");
1907             goto out;
1908         }
1909         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1910
1911         ret = add_METHOD_DATA(&enc_pa_data, &pa);
1912         krb5_data_free(&pa.padata_value);
1913         if (ret) {
1914             kdc_log(context, config, 0,
1915                     "Add server referral METHOD-DATA failed");
1916             goto out;
1917         }
1918     }
1919
1920     /*
1921      *
1922      */
1923
1924     ret = tgs_make_reply(context,
1925                          config,
1926                          b,
1927                          client_principal,
1928                          tgt,
1929                          ekey,
1930                          &sessionkey,
1931                          kvno,
1932                          *auth_data,
1933                          server,
1934                          sp,
1935                          spn,
1936                          client,
1937                          cp,
1938                          krbtgt,
1939                          krbtgt_etype,
1940                          spp,
1941                          &rspac,
1942                          &enc_pa_data,
1943                          e_text,
1944                          reply);
1945         
1946 out:
1947     free(spn);
1948     free(cpn);
1949         
1950     krb5_data_free(&rspac);
1951     krb5_free_keyblock_contents(context, &sessionkey);
1952     if(server)
1953         _kdc_free_ent(context, server);
1954     if(client)
1955         _kdc_free_ent(context, client);
1956
1957     if (client_principal && client_principal != cp)
1958         krb5_free_principal(context, client_principal);
1959     if (cp)
1960         krb5_free_principal(context, cp);
1961     if (sp)
1962         krb5_free_principal(context, sp);
1963     if (ref_realm)
1964         free(ref_realm);
1965     free_METHOD_DATA(&enc_pa_data);
1966
1967     free_EncTicketPart(&adtkt);
1968
1969     return ret;
1970 }
1971
1972 /*
1973  *
1974  */
1975
1976 krb5_error_code
1977 _kdc_tgs_rep(krb5_context context,
1978              krb5_kdc_configuration *config,
1979              KDC_REQ *req,
1980              krb5_data *data,
1981              const char *from,
1982              struct sockaddr *from_addr,
1983              int datagram_reply)
1984 {
1985     AuthorizationData *auth_data = NULL;
1986     krb5_error_code ret;
1987     int i = 0;
1988     const PA_DATA *tgs_req;
1989
1990     hdb_entry_ex *krbtgt = NULL;
1991     krb5_ticket *ticket = NULL;
1992     const char *e_text = NULL;
1993     krb5_enctype krbtgt_etype = ETYPE_NULL;
1994
1995     time_t *csec = NULL;
1996     int *cusec = NULL;
1997
1998     if(req->padata == NULL){
1999         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2000         kdc_log(context, config, 0,
2001                 "TGS-REQ from %s without PA-DATA", from);
2002         goto out;
2003     }
2004
2005     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2006
2007     if(tgs_req == NULL){
2008         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2009         
2010         kdc_log(context, config, 0,
2011                 "TGS-REQ from %s without PA-TGS-REQ", from);
2012         goto out;
2013     }
2014     ret = tgs_parse_request(context, config,
2015                             &req->req_body, tgs_req,
2016                             &krbtgt,
2017                             &krbtgt_etype,
2018                             &ticket,
2019                             &e_text,
2020                             from, from_addr,
2021                             &csec, &cusec,
2022                             &auth_data);
2023     if (ret) {
2024         kdc_log(context, config, 0,
2025                 "Failed parsing TGS-REQ from %s", from);
2026         goto out;
2027     }
2028
2029     ret = tgs_build_reply(context,
2030                           config,
2031                           req,
2032                           &req->req_body,
2033                           krbtgt,
2034                           krbtgt_etype,
2035                           ticket,
2036                           data,
2037                           from,
2038                           &e_text,
2039                           &auth_data,
2040                           from_addr);
2041     if (ret) {
2042         kdc_log(context, config, 0,
2043                 "Failed building TGS-REP to %s", from);
2044         goto out;
2045     }
2046
2047     /* */
2048     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2049         krb5_data_free(data);
2050         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2051         e_text = "Reply packet too large";
2052     }
2053
2054 out:
2055     if(ret && data->data == NULL){
2056         krb5_mk_error(context,
2057                       ret,
2058                       NULL,
2059                       NULL,
2060                       NULL,
2061                       NULL,
2062                       csec,
2063                       cusec,
2064                       data);
2065     }
2066     free(csec);
2067     free(cusec);
2068     if (ticket)
2069         krb5_free_ticket(context, ticket);
2070     if(krbtgt)
2071         _kdc_free_ent(context, krbtgt);
2072
2073     if (auth_data) {
2074         free_AuthorizationData(auth_data);
2075         free(auth_data);
2076     }
2077
2078     return 0;
2079 }