Fix build with arc4.
[kai/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                         KRB5SignedPathPrincipals *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_KRB5SignedPathPrincipals(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                      KRB5SignedPathPrincipals **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_KRB5SignedPathPrincipals(*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_string(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                KRB5SignedPathPrincipals *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_princ_realm(context, client_principal),
729                                  *krb5_princ_realm(context, server->entry.principal),
730                                  *krb5_princ_realm(context, krbtgt->entry.principal));
731     if(ret)
732         goto out;
733
734     copy_Realm(krb5_princ_realm(context, server_principal),
735                &rep.ticket.realm);
736     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
737     copy_Realm(&tgt_name->realm, &rep.crealm);
738 /*
739     if (f.request_anonymous)
740         _kdc_make_anonymous_principalname (&rep.cname);
741     else */
742
743     copy_PrincipalName(&tgt_name->name, &rep.cname);
744     rep.ticket.tkt_vno = 5;
745
746     ek.caddr = et.caddr;
747     if(et.caddr == NULL)
748         et.caddr = tgt->caddr;
749
750     {
751         time_t life;
752         life = et.endtime - *et.starttime;
753         if(client && client->entry.max_life)
754             life = min(life, *client->entry.max_life);
755         if(server->entry.max_life)
756             life = min(life, *server->entry.max_life);
757         et.endtime = *et.starttime + life;
758     }
759     if(f.renewable_ok && tgt->flags.renewable &&
760        et.renew_till == NULL && et.endtime < *b->till){
761         et.flags.renewable = 1;
762         ALLOC(et.renew_till);
763         *et.renew_till = *b->till;
764     }
765     if(et.renew_till){
766         time_t renew;
767         renew = *et.renew_till - et.authtime;
768         if(client && client->entry.max_renew)
769             renew = min(renew, *client->entry.max_renew);
770         if(server->entry.max_renew)
771             renew = min(renew, *server->entry.max_renew);
772         *et.renew_till = et.authtime + renew;
773     }
774         
775     if(et.renew_till){
776         *et.renew_till = min(*et.renew_till, *tgt->renew_till);
777         *et.starttime = min(*et.starttime, *et.renew_till);
778         et.endtime = min(et.endtime, *et.renew_till);
779     }
780
781     *et.starttime = min(*et.starttime, et.endtime);
782
783     if(*et.starttime == et.endtime){
784         ret = KRB5KDC_ERR_NEVER_VALID;
785         goto out;
786     }
787     if(et.renew_till && et.endtime == *et.renew_till){
788         free(et.renew_till);
789         et.renew_till = NULL;
790         et.flags.renewable = 0;
791     }
792
793     et.flags.pre_authent = tgt->flags.pre_authent;
794     et.flags.hw_authent  = tgt->flags.hw_authent;
795     et.flags.anonymous   = tgt->flags.anonymous;
796     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
797         
798     if (auth_data) {
799         /* XXX Check enc-authorization-data */
800         et.authorization_data = calloc(1, sizeof(*et.authorization_data));
801         if (et.authorization_data == NULL) {
802             ret = ENOMEM;
803             goto out;
804         }
805         ret = copy_AuthorizationData(auth_data, et.authorization_data);
806         if (ret)
807             goto out;
808
809         /* Filter out type KRB5SignedPath */
810         ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
811         if (ret == 0) {
812             if (et.authorization_data->len == 1) {
813                 free_AuthorizationData(et.authorization_data);
814                 free(et.authorization_data);
815                 et.authorization_data = NULL;
816             } else {
817                 AuthorizationData *ad = et.authorization_data;
818                 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
819                 ad->len--;
820             }
821         }
822     }
823
824     if(rspac->length) {
825         /*
826          * No not need to filter out the any PAC from the
827          * auth_data since it's signed by the KDC.
828          */
829         ret = _kdc_tkt_add_if_relevant_ad(context, &et,
830                                           KRB5_AUTHDATA_WIN2K_PAC,
831                                           rspac);
832         if (ret)
833             goto out;
834     }
835
836     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
837     if (ret)
838         goto out;
839     et.crealm = tgt->crealm;
840     et.cname = tgt_name->name;
841         
842     ek.key = et.key;
843     /* MIT must have at least one last_req */
844     ek.last_req.len = 1;
845     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
846     if (ek.last_req.val == NULL) {
847         ret = ENOMEM;
848         goto out;
849     }
850     ek.nonce = b->nonce;
851     ek.flags = et.flags;
852     ek.authtime = et.authtime;
853     ek.starttime = et.starttime;
854     ek.endtime = et.endtime;
855     ek.renew_till = et.renew_till;
856     ek.srealm = rep.ticket.realm;
857     ek.sname = rep.ticket.sname;
858
859     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
860                        et.endtime, et.renew_till);
861
862     /* Don't sign cross realm tickets, they can't be checked anyway */
863     {
864         char *r = get_krbtgt_realm(&ek.sname);
865
866         if (r == NULL || strcmp(r, ek.srealm) == 0) {
867             ret = _kdc_add_KRB5SignedPath(context,
868                                           config,
869                                           krbtgt,
870                                           krbtgt_etype,
871                                           NULL,
872                                           spp,
873                                           &et);
874             if (ret)
875                 goto out;
876         }
877     }
878
879     if (enc_pa_data->len) {
880         rep.padata = calloc(1, sizeof(*rep.padata));
881         if (rep.padata == NULL) {
882             ret = ENOMEM;
883             goto out;
884         }
885         ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
886         if (ret)
887             goto out;
888     }
889
890     if (krb5_enctype_valid(context, et.key.keytype) != 0
891         && _kdc_is_weak_expection(server->entry.principal, et.key.keytype)) 
892     {
893         krb5_enctype_enable(context, et.key.keytype);
894         is_weak = 1;
895     }
896
897
898     /* It is somewhat unclear where the etype in the following
899        encryption should come from. What we have is a session
900        key in the passed tgt, and a list of preferred etypes
901        *for the new ticket*. Should we pick the best possible
902        etype, given the keytype in the tgt, or should we look
903        at the etype list here as well?  What if the tgt
904        session key is DES3 and we want a ticket with a (say)
905        CAST session key. Should the DES3 etype be added to the
906        etype list, even if we don't want a session key with
907        DES3? */
908     ret = _kdc_encode_reply(context, config,
909                             &rep, &et, &ek, et.key.keytype,
910                             kvno,
911                             serverkey, 0, &tgt->key, e_text, reply);
912     if (is_weak)
913         krb5_enctype_disable(context, et.key.keytype);
914
915 out:
916     free_TGS_REP(&rep);
917     free_TransitedEncoding(&et.transited);
918     if(et.starttime)
919         free(et.starttime);
920     if(et.renew_till)
921         free(et.renew_till);
922     if(et.authorization_data) {
923         free_AuthorizationData(et.authorization_data);
924         free(et.authorization_data);
925     }
926     free_LastReq(&ek.last_req);
927     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
928     free_EncryptionKey(&et.key);
929     return ret;
930 }
931
932 static krb5_error_code
933 tgs_check_authenticator(krb5_context context,
934                         krb5_kdc_configuration *config,
935                         krb5_auth_context ac,
936                         KDC_REQ_BODY *b,
937                         const char **e_text,
938                         krb5_keyblock *key)
939 {
940     krb5_authenticator auth;
941     size_t len;
942     unsigned char *buf;
943     size_t buf_size;
944     krb5_error_code ret;
945     krb5_crypto crypto;
946
947     krb5_auth_con_getauthenticator(context, ac, &auth);
948     if(auth->cksum == NULL){
949         kdc_log(context, config, 0, "No authenticator in request");
950         ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
951         goto out;
952     }
953     /*
954      * according to RFC1510 it doesn't need to be keyed,
955      * but according to the latest draft it needs to.
956      */
957     if (
958 #if 0
959 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
960         ||
961 #endif
962  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
963         kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
964                 auth->cksum->cksumtype);
965         ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
966         goto out;
967     }
968                 
969     /* XXX should not re-encode this */
970     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
971     if(ret){
972         kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s",
973                 krb5_get_err_text(context, ret));
974         goto out;
975     }
976     if(buf_size != len) {
977         free(buf);
978         kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
979         *e_text = "KDC internal error";
980         ret = KRB5KRB_ERR_GENERIC;
981         goto out;
982     }
983     ret = krb5_crypto_init(context, key, 0, &crypto);
984     if (ret) {
985         free(buf);
986         kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
987                 krb5_get_err_text(context, ret));
988         goto out;
989     }
990     ret = krb5_verify_checksum(context,
991                                crypto,
992                                KRB5_KU_TGS_REQ_AUTH_CKSUM,
993                                buf,
994                                len,
995                                auth->cksum);
996     free(buf);
997     krb5_crypto_destroy(context, crypto);
998     if(ret){
999         kdc_log(context, config, 0,
1000                 "Failed to verify authenticator checksum: %s",
1001                 krb5_get_err_text(context, ret));
1002     }
1003 out:
1004     free_Authenticator(auth);
1005     free(auth);
1006     return ret;
1007 }
1008
1009 /*
1010  *
1011  */
1012
1013 static const char *
1014 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1015 {
1016     const char *new_realm = krb5_config_get_string(context,
1017                                                    NULL,
1018                                                    "capaths",
1019                                                    crealm,
1020                                                    srealm,
1021                                                    NULL);
1022     return new_realm;
1023 }
1024         
1025
1026 static krb5_boolean
1027 need_referral(krb5_context context, krb5_kdc_configuration *config,
1028               const KDCOptions * const options, krb5_principal server,
1029               krb5_realm **realms)
1030 {
1031     const char *name;
1032
1033     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1034         return FALSE;
1035
1036     if (server->name.name_string.len == 1)
1037         name = server->name.name_string.val[0];
1038     if (server->name.name_string.len > 1)
1039         name = server->name.name_string.val[1];
1040     else
1041         return FALSE;
1042
1043     kdc_log(context, config, 0, "Searching referral for %s", name);
1044
1045     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1046 }
1047
1048 static krb5_error_code
1049 tgs_parse_request(krb5_context context,
1050                   krb5_kdc_configuration *config,
1051                   KDC_REQ_BODY *b,
1052                   const PA_DATA *tgs_req,
1053                   hdb_entry_ex **krbtgt,
1054                   krb5_enctype *krbtgt_etype,
1055                   krb5_ticket **ticket,
1056                   const char **e_text,
1057                   const char *from,
1058                   const struct sockaddr *from_addr,
1059                   time_t **csec,
1060                   int **cusec,
1061                   AuthorizationData **auth_data)
1062 {
1063     krb5_ap_req ap_req;
1064     krb5_error_code ret;
1065     krb5_principal princ;
1066     krb5_auth_context ac = NULL;
1067     krb5_flags ap_req_options;
1068     krb5_flags verify_ap_req_flags;
1069     krb5_crypto crypto;
1070     Key *tkey;
1071
1072     *auth_data = NULL;
1073     *csec  = NULL;
1074     *cusec = NULL;
1075
1076     memset(&ap_req, 0, sizeof(ap_req));
1077     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1078     if(ret){
1079         kdc_log(context, config, 0, "Failed to decode AP-REQ: %s",
1080                 krb5_get_err_text(context, ret));
1081         goto out;
1082     }
1083
1084     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1085         /* XXX check for ticket.sname == req.sname */
1086         kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1087         ret = KRB5KDC_ERR_POLICY; /* ? */
1088         goto out;
1089     }
1090
1091     _krb5_principalname2krb5_principal(context,
1092                                        &princ,
1093                                        ap_req.ticket.sname,
1094                                        ap_req.ticket.realm);
1095
1096     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);
1097
1098     if(ret) {
1099         char *p;
1100         ret = krb5_unparse_name(context, princ, &p);
1101         if (ret != 0)
1102             p = "<unparse_name failed>";
1103         krb5_free_principal(context, princ);
1104         kdc_log(context, config, 0,
1105                 "Ticket-granting ticket not found in database: %s: %s",
1106                 p, krb5_get_err_text(context, ret));
1107         if (ret == 0)
1108             free(p);
1109         ret = KRB5KRB_AP_ERR_NOT_US;
1110         goto out;
1111     }
1112
1113     if(ap_req.ticket.enc_part.kvno &&
1114        *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1115         char *p;
1116
1117         ret = krb5_unparse_name (context, princ, &p);
1118         krb5_free_principal(context, princ);
1119         if (ret != 0)
1120             p = "<unparse_name failed>";
1121         kdc_log(context, config, 0,
1122                 "Ticket kvno = %d, DB kvno = %d (%s)",
1123                 *ap_req.ticket.enc_part.kvno,
1124                 (*krbtgt)->entry.kvno,
1125                 p);
1126         if (ret == 0)
1127             free (p);
1128         ret = KRB5KRB_AP_ERR_BADKEYVER;
1129         goto out;
1130     }
1131
1132     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1133
1134     ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1135                           ap_req.ticket.enc_part.etype, &tkey);
1136     if(ret){
1137         char *str = NULL, *p = NULL;
1138
1139         krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1140         krb5_unparse_name(context, princ, &p);
1141         kdc_log(context, config, 0,
1142                 "No server key with enctype %s found for %s",
1143                 str ? str : "<unknown enctype>",
1144                 p ? p : "<unparse_name failed>");
1145         free(str);
1146         free(p);
1147         ret = KRB5KRB_AP_ERR_BADKEYVER;
1148         goto out;
1149     }
1150
1151     if (b->kdc_options.validate)
1152         verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1153     else
1154         verify_ap_req_flags = 0;
1155
1156     ret = krb5_verify_ap_req2(context,
1157                               &ac,
1158                               &ap_req,
1159                               princ,
1160                               &tkey->key,
1161                               verify_ap_req_flags,
1162                               &ap_req_options,
1163                               ticket,
1164                               KRB5_KU_TGS_REQ_AUTH);
1165                         
1166     krb5_free_principal(context, princ);
1167     if(ret) {
1168         kdc_log(context, config, 0, "Failed to verify AP-REQ: %s",
1169                 krb5_get_err_text(context, ret));
1170         goto out;
1171     }
1172
1173     {
1174         krb5_authenticator auth;
1175
1176         ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1177         if (ret == 0) {
1178             *csec   = malloc(sizeof(**csec));
1179             if (*csec == NULL) {
1180                 krb5_free_authenticator(context, &auth);
1181                 kdc_log(context, config, 0, "malloc failed");
1182                 goto out;
1183             }
1184             **csec  = auth->ctime;
1185             *cusec  = malloc(sizeof(**cusec));
1186             if (*cusec == NULL) {
1187                 krb5_free_authenticator(context, &auth);
1188                 kdc_log(context, config, 0, "malloc failed");
1189                 goto out;
1190             }
1191             **cusec  = auth->cusec;
1192             krb5_free_authenticator(context, &auth);
1193         }
1194     }
1195
1196     ret = tgs_check_authenticator(context, config,
1197                                   ac, b, e_text, &(*ticket)->ticket.key);
1198     if (ret) {
1199         krb5_auth_con_free(context, ac);
1200         goto out;
1201     }
1202
1203     if (b->enc_authorization_data) {
1204         unsigned usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1205         krb5_keyblock *subkey;
1206         krb5_data ad;
1207
1208         ret = krb5_auth_con_getremotesubkey(context,
1209                                             ac,
1210                                             &subkey);
1211         if(ret){
1212             krb5_auth_con_free(context, ac);
1213             kdc_log(context, config, 0, "Failed to get remote subkey: %s",
1214                     krb5_get_err_text(context, ret));
1215             goto out;
1216         }
1217         if(subkey == NULL){
1218             usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1219             ret = krb5_auth_con_getkey(context, ac, &subkey);
1220             if(ret) {
1221                 krb5_auth_con_free(context, ac);
1222                 kdc_log(context, config, 0, "Failed to get session key: %s",
1223                         krb5_get_err_text(context, ret));
1224                 goto out;
1225             }
1226         }
1227         if(subkey == NULL){
1228             krb5_auth_con_free(context, ac);
1229             kdc_log(context, config, 0,
1230                     "Failed to get key for enc-authorization-data");
1231             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1232             goto out;
1233         }
1234         ret = krb5_crypto_init(context, subkey, 0, &crypto);
1235         if (ret) {
1236             krb5_auth_con_free(context, ac);
1237             kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1238                     krb5_get_err_text(context, ret));
1239             goto out;
1240         }
1241         ret = krb5_decrypt_EncryptedData (context,
1242                                           crypto,
1243                                           usage,
1244                                           b->enc_authorization_data,
1245                                           &ad);
1246         krb5_crypto_destroy(context, crypto);
1247         if(ret){
1248             krb5_auth_con_free(context, ac);
1249             kdc_log(context, config, 0,
1250                     "Failed to decrypt enc-authorization-data");
1251             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1252             goto out;
1253         }
1254         krb5_free_keyblock(context, subkey);
1255         ALLOC(*auth_data);
1256         if (*auth_data == NULL) {
1257             krb5_auth_con_free(context, ac);
1258             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1259             goto out;
1260         }
1261         ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1262         if(ret){
1263             krb5_auth_con_free(context, ac);
1264             free(*auth_data);
1265             *auth_data = NULL;
1266             kdc_log(context, config, 0, "Failed to decode authorization data");
1267             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1268             goto out;
1269         }
1270     }
1271
1272     krb5_auth_con_free(context, ac);
1273
1274 out:
1275     free_AP_REQ(&ap_req);
1276
1277     return ret;
1278 }
1279
1280 static krb5_error_code
1281 build_server_referral(krb5_context context,
1282                       krb5_kdc_configuration *config,
1283                       krb5_crypto session,
1284                       krb5_const_realm referred_realm,
1285                       const PrincipalName *true_principal_name,
1286                       const PrincipalName *requested_principal,
1287                       krb5_data *outdata)
1288 {               
1289     PA_ServerReferralData ref;
1290     krb5_error_code ret;
1291     EncryptedData ed;
1292     krb5_data data;
1293     size_t size;
1294
1295     memset(&ref, 0, sizeof(ref));
1296
1297     if (referred_realm) {
1298         ref.referred_realm = malloc(sizeof(ref.referred_realm));
1299         if (ref.referred_realm == NULL)
1300             goto eout;
1301         *ref.referred_realm = strdup(referred_realm);
1302         if (*ref.referred_realm == NULL)
1303             goto eout;
1304     }
1305     if (true_principal_name) {
1306         ref.true_principal_name =
1307             malloc(sizeof(ref.true_principal_name));
1308         if (ref.true_principal_name == NULL)
1309             goto eout;
1310         ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1311         if (ret)
1312             goto eout;
1313     }
1314     if (requested_principal) {
1315         ref.requested_principal_name =
1316             malloc(sizeof(ref.requested_principal_name));
1317         if (ref.requested_principal_name == NULL)
1318             goto eout;
1319         ret = copy_PrincipalName(requested_principal,
1320                                  ref.requested_principal_name);
1321         if (ret)
1322             goto eout;
1323     }
1324
1325     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1326                        data.data, data.length,
1327                        &ref, &size, ret);
1328     free_PA_ServerReferralData(&ref);
1329     if (ret)
1330         return ret;
1331     if (data.length != size)
1332         krb5_abortx(context, "internal asn.1 encoder error");
1333
1334     ret = krb5_encrypt_EncryptedData(context, session,
1335                                      KRB5_KU_PA_SERVER_REFERRAL,
1336                                      data.data, data.length,
1337                                      0 /* kvno */, &ed);
1338     free(data.data);
1339     if (ret)
1340         return ret;
1341
1342     ASN1_MALLOC_ENCODE(EncryptedData,
1343                        outdata->data, outdata->length,
1344                        &ed, &size, ret);
1345     free_EncryptedData(&ed);
1346     if (ret)
1347         return ret;
1348     if (outdata->length != size)
1349         krb5_abortx(context, "internal asn.1 encoder error");
1350
1351     return 0;
1352 eout:
1353     free_PA_ServerReferralData(&ref);
1354     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1355     return ENOMEM;
1356 }
1357
1358 static krb5_error_code
1359 tgs_build_reply(krb5_context context,
1360                 krb5_kdc_configuration *config,
1361                 KDC_REQ *req,
1362                 KDC_REQ_BODY *b,
1363                 hdb_entry_ex *krbtgt,
1364                 krb5_enctype krbtgt_etype,
1365                 krb5_ticket *ticket,
1366                 krb5_data *reply,
1367                 const char *from,
1368                 const char **e_text,
1369                 AuthorizationData **auth_data,
1370                 const struct sockaddr *from_addr,
1371                 int datagram_reply)
1372 {
1373     krb5_error_code ret;
1374     krb5_principal cp = NULL, sp = NULL;
1375     krb5_principal client_principal = NULL;
1376     char *spn = NULL, *cpn = NULL;
1377     hdb_entry_ex *server = NULL, *client = NULL;
1378     krb5_realm ref_realm = NULL;
1379     EncTicketPart *tgt = &ticket->ticket;
1380     KRB5SignedPathPrincipals *spp = NULL;
1381     const EncryptionKey *ekey;
1382     krb5_keyblock sessionkey;
1383     krb5_kvno kvno;
1384     krb5_data rspac;
1385     int cross_realm = 0;
1386
1387     METHOD_DATA enc_pa_data;
1388
1389     PrincipalName *s;
1390     Realm r;
1391     int nloop = 0;
1392     EncTicketPart adtkt;
1393     char opt_str[128];
1394     int signedpath = 0;
1395
1396     memset(&sessionkey, 0, sizeof(sessionkey));
1397     memset(&adtkt, 0, sizeof(adtkt));
1398     krb5_data_zero(&rspac);
1399     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1400
1401     s = b->sname;
1402     r = b->realm;
1403
1404     if(b->kdc_options.enc_tkt_in_skey){
1405         Ticket *t;
1406         hdb_entry_ex *uu;
1407         krb5_principal p;
1408         Key *uukey;
1409         
1410         if(b->additional_tickets == NULL ||
1411            b->additional_tickets->len == 0){
1412             ret = KRB5KDC_ERR_BADOPTION; /* ? */
1413             kdc_log(context, config, 0,
1414                     "No second ticket present in request");
1415             goto out;
1416         }
1417         t = &b->additional_tickets->val[0];
1418         if(!get_krbtgt_realm(&t->sname)){
1419             kdc_log(context, config, 0,
1420                     "Additional ticket is not a ticket-granting ticket");
1421             ret = KRB5KDC_ERR_POLICY;
1422             goto out;
1423         }
1424         _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1425         ret = _kdc_db_fetch(context, config, p,
1426                             HDB_F_GET_CLIENT|HDB_F_GET_SERVER,
1427                             NULL, &uu);
1428         krb5_free_principal(context, p);
1429         if(ret){
1430             if (ret == HDB_ERR_NOENTRY)
1431                 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1432             goto out;
1433         }
1434         ret = hdb_enctype2key(context, &uu->entry,
1435                               t->enc_part.etype, &uukey);
1436         if(ret){
1437             _kdc_free_ent(context, uu);
1438             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1439             goto out;
1440         }
1441         ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1442         _kdc_free_ent(context, uu);
1443         if(ret)
1444             goto out;
1445
1446         ret = verify_flags(context, config, &adtkt, spn);
1447         if (ret)
1448             goto out;
1449
1450         s = &adtkt.cname;
1451         r = adtkt.crealm;
1452     }
1453
1454     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1455     ret = krb5_unparse_name(context, sp, &spn); 
1456     if (ret)
1457         goto out;
1458     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1459     ret = krb5_unparse_name(context, cp, &cpn);
1460     if (ret)
1461         goto out;
1462     unparse_flags (KDCOptions2int(b->kdc_options),
1463                    asn1_KDCOptions_units(),
1464                    opt_str, sizeof(opt_str));
1465     if(*opt_str)
1466         kdc_log(context, config, 0,
1467                 "TGS-REQ %s from %s for %s [%s]",
1468                 cpn, from, spn, opt_str);
1469     else
1470         kdc_log(context, config, 0,
1471                 "TGS-REQ %s from %s for %s", cpn, from, spn);
1472
1473     /*
1474      * Fetch server
1475      */
1476
1477 server_lookup:
1478     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | HDB_F_CANON,
1479                         NULL, &server);
1480
1481     if(ret){
1482         const char *new_rlm;
1483         Realm req_rlm;
1484         krb5_realm *realms;
1485
1486         if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1487             if(nloop++ < 2) {
1488                 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1489                 if(new_rlm) {
1490                     kdc_log(context, config, 5, "krbtgt for realm %s "
1491                             "not found, trying %s",
1492                             req_rlm, new_rlm);
1493                     krb5_free_principal(context, sp);
1494                     free(spn);
1495                     krb5_make_principal(context, &sp, r,
1496                                         KRB5_TGS_NAME, new_rlm, NULL);
1497                     ret = krb5_unparse_name(context, sp, &spn); 
1498                     if (ret)
1499                         goto out;
1500
1501                     if (ref_realm)
1502                         free(ref_realm);
1503                     ref_realm = strdup(new_rlm);
1504                     goto server_lookup;
1505                 }
1506             }
1507         } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1508             if (strcmp(realms[0], sp->realm) != 0) {
1509                 kdc_log(context, config, 5,
1510                         "Returning a referral to realm %s for "
1511                         "server %s that was not found",
1512                         realms[0], spn);
1513                 krb5_free_principal(context, sp);
1514                 free(spn);
1515                 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1516                                     realms[0], NULL);
1517                 ret = krb5_unparse_name(context, sp, &spn);
1518                 if (ret)
1519                     goto out;
1520
1521                 if (ref_realm)
1522                     free(ref_realm);
1523                 ref_realm = strdup(realms[0]);
1524
1525                 krb5_free_host_realm(context, realms);
1526                 goto server_lookup;
1527             }
1528             krb5_free_host_realm(context, realms);
1529         }
1530         kdc_log(context, config, 0,
1531                 "Server not found in database: %s: %s", spn,
1532                 krb5_get_err_text(context, ret));
1533         if (ret == HDB_ERR_NOENTRY)
1534             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1535         goto out;
1536     }
1537
1538     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | HDB_F_CANON,
1539                         NULL, &client);
1540     if(ret) {
1541         const char *krbtgt_realm;
1542
1543         /*
1544          * If the client belongs to the same realm as our krbtgt, it
1545          * should exist in the local database.
1546          *
1547          */
1548
1549         krbtgt_realm =
1550             krb5_principal_get_comp_string(context,
1551                                            krbtgt->entry.principal, 1);
1552
1553         if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1554             if (ret == HDB_ERR_NOENTRY)
1555                 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1556             kdc_log(context, config, 1, "Client no longer in database: %s",
1557                     cpn);
1558             goto out;
1559         }
1560         
1561         kdc_log(context, config, 1, "Client not found in database: %s: %s",
1562                 cpn, krb5_get_err_text(context, ret));
1563
1564         cross_realm = 1;
1565     }
1566
1567     /*
1568      * Select enctype, return key and kvno.
1569      */
1570
1571     {
1572         krb5_enctype etype;
1573
1574         if(b->kdc_options.enc_tkt_in_skey) {
1575             int i;
1576             ekey = &adtkt.key;
1577             for(i = 0; i < b->etype.len; i++)
1578                 if (b->etype.val[i] == adtkt.key.keytype)
1579                     break;
1580             if(i == b->etype.len) {
1581                 kdc_log(context, config, 0,
1582                         "Addition ticket have not matching etypes", spp);
1583                 krb5_clear_error_string(context);
1584                 return KRB5KDC_ERR_ETYPE_NOSUPP;
1585             }
1586             etype = b->etype.val[i];
1587             kvno = 0;
1588         } else {
1589             Key *skey;
1590         
1591             ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len,
1592                                   &skey, &etype);
1593             if(ret) {
1594                 kdc_log(context, config, 0,
1595                         "Server (%s) has no support for etypes", spn);
1596                 return ret;
1597             }
1598             ekey = &skey->key;
1599             kvno = server->entry.kvno;
1600         }
1601         
1602         ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1603         if (ret)
1604             goto out;
1605     }
1606
1607     /*
1608      * Validate authoriation data
1609      */
1610
1611     /*
1612      * Check that service is in the same realm as the krbtgt. If it's
1613      * not the same, it's someone that is using a uni-directional trust
1614      * backward.
1615      */
1616
1617     if (strcmp(krb5_principal_get_realm(context, sp),
1618                krb5_principal_get_comp_string(context,
1619                                               krbtgt->entry.principal,
1620                                               1)) != 0) {
1621         char *tpn;
1622         ret = krb5_unparse_name(context, krbtgt->entry.principal, &tpn);
1623         kdc_log(context, config, 0,
1624                 "Request with wrong krbtgt: %s",
1625                 (ret == 0) ? tpn : "<unknown>");
1626         if(ret == 0)
1627             free(tpn);
1628         ret = KRB5KRB_AP_ERR_NOT_US;
1629         goto out;
1630     }
1631
1632     /* check PAC if not cross realm and if there is one */
1633     if (!cross_realm) {
1634         Key *tkey;
1635
1636         ret = hdb_enctype2key(context, &krbtgt->entry,
1637                               krbtgt_etype, &tkey);
1638         if(ret) {
1639             kdc_log(context, config, 0,
1640                     "Failed to find key for krbtgt PAC check");
1641             goto out;
1642         }
1643
1644         ret = check_PAC(context, config, cp,
1645                         client, server, ekey, &tkey->key,
1646                         tgt, &rspac, &signedpath);
1647         if (ret) {
1648             kdc_log(context, config, 0,
1649                     "Verify PAC failed for %s (%s) from %s with %s",
1650                     spn, cpn, from, krb5_get_err_text(context, ret));
1651             goto out;
1652         }
1653     }
1654
1655     /* also check the krbtgt for signature */
1656     ret = check_KRB5SignedPath(context,
1657                                config,
1658                                krbtgt,
1659                                tgt,
1660                                &spp,
1661                                &signedpath);
1662     if (ret) {
1663         kdc_log(context, config, 0,
1664                 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1665                 spn, cpn, from, krb5_get_err_text(context, ret));
1666         goto out;
1667     }
1668
1669     /*
1670      * Process request
1671      */
1672
1673     client_principal = cp;
1674
1675     if (client) {
1676         const PA_DATA *sdata;
1677         int i = 0;
1678
1679         sdata = _kdc_find_padata(req, &i, KRB5_PADATA_S4U2SELF);
1680         if (sdata) {
1681             krb5_crypto crypto;
1682             krb5_data datack;
1683             PA_S4U2Self self;
1684             char *selfcpn = NULL;
1685             const char *str;
1686
1687             ret = decode_PA_S4U2Self(sdata->padata_value.data,
1688                                      sdata->padata_value.length,
1689                                      &self, NULL);
1690             if (ret) {
1691                 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1692                 goto out;
1693             }
1694
1695             ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1696             if (ret)
1697                 goto out;
1698
1699             ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1700             if (ret) {
1701                 free_PA_S4U2Self(&self);
1702                 krb5_data_free(&datack);
1703                 kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
1704                         krb5_get_err_text(context, ret));
1705                 goto out;
1706             }
1707
1708             ret = krb5_verify_checksum(context,
1709                                        crypto,
1710                                        KRB5_KU_OTHER_CKSUM,
1711                                        datack.data,
1712                                        datack.length,
1713                                        &self.cksum);
1714             krb5_data_free(&datack);
1715             krb5_crypto_destroy(context, crypto);
1716             if (ret) {
1717                 free_PA_S4U2Self(&self);
1718                 kdc_log(context, config, 0,
1719                         "krb5_verify_checksum failed for S4U2Self: %s",
1720                         krb5_get_err_text(context, ret));
1721                 goto out;
1722             }
1723
1724             ret = _krb5_principalname2krb5_principal(context,
1725                                                      &client_principal,
1726                                                      self.name,
1727                                                      self.realm);
1728             free_PA_S4U2Self(&self);
1729             if (ret)
1730                 goto out;
1731
1732             ret = krb5_unparse_name(context, client_principal, &selfcpn);       
1733             if (ret)
1734                 goto out;
1735
1736             /*
1737              * Check that service doing the impersonating is
1738              * requesting a ticket to it-self.
1739              */
1740             if (krb5_principal_compare(context, cp, sp) != TRUE) {
1741                 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1742                         "to impersonate some other user "
1743                         "(tried for user %s to service %s)",
1744                         cpn, selfcpn, spn);
1745                 free(selfcpn);
1746                 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1747                 goto out;
1748             }
1749
1750             /*
1751              * If the service isn't trusted for authentication to
1752              * delegation, remove the forward flag.
1753              */
1754
1755             if (client->entry.flags.trusted_for_delegation) {
1756                 str = "[forwardable]";
1757             } else {
1758                 b->kdc_options.forwardable = 0;
1759                 str = "";
1760             }
1761             kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
1762                     "service %s %s", cpn, selfcpn, spn, str);
1763             free(selfcpn);
1764         }
1765     }
1766
1767     /*
1768      * Constrained delegation
1769      */
1770
1771     if (client != NULL
1772         && b->additional_tickets != NULL
1773         && b->additional_tickets->len != 0
1774         && b->kdc_options.enc_tkt_in_skey == 0)
1775     {
1776         int ad_signedpath = 0;
1777         Key *clientkey;
1778         Ticket *t;
1779         char *str;
1780
1781         /*
1782          * Require that the KDC have issued the service's krbtgt (not
1783          * self-issued ticket with kimpersonate(1).
1784          */
1785         if (!signedpath) {
1786             ret = KRB5KDC_ERR_BADOPTION;
1787             kdc_log(context, config, 0,
1788                     "Constrained delegation done on service ticket %s/%s",
1789                     cpn, spn);
1790             goto out;
1791         }
1792
1793         t = &b->additional_tickets->val[0];
1794
1795         ret = hdb_enctype2key(context, &client->entry,
1796                               t->enc_part.etype, &clientkey);
1797         if(ret){
1798             ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1799             goto out;
1800         }
1801
1802         ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
1803         if (ret) {
1804             kdc_log(context, config, 0,
1805                     "failed to decrypt ticket for "
1806                     "constrained delegation from %s to %s ", spn, cpn);
1807             goto out;
1808         }
1809
1810         /* check that ticket is valid */
1811         if (adtkt.flags.forwardable == 0) {
1812             kdc_log(context, config, 0,
1813                     "Missing forwardable flag on ticket for "
1814                     "constrained delegation from %s to %s ", spn, cpn);
1815             ret = KRB5KDC_ERR_BADOPTION;
1816             goto out;
1817         }
1818
1819         ret = check_constrained_delegation(context, config, client, sp);
1820         if (ret) {
1821             kdc_log(context, config, 0,
1822                     "constrained delegation from %s to %s not allowed",
1823                     spn, cpn);
1824             goto out;
1825         }
1826
1827         ret = _krb5_principalname2krb5_principal(context,
1828                                                  &client_principal,
1829                                                  adtkt.cname,
1830                                                  adtkt.crealm);
1831         if (ret)
1832             goto out;
1833
1834         ret = krb5_unparse_name(context, client_principal, &str);
1835         if (ret)
1836             goto out;
1837
1838         ret = verify_flags(context, config, &adtkt, str);
1839         if (ret) {
1840             free(str);
1841             goto out;
1842         }
1843
1844         /*
1845          * Check that the KDC issued the user's ticket.
1846          */
1847         ret = check_KRB5SignedPath(context,
1848                                    config,
1849                                    krbtgt,
1850                                    &adtkt,
1851                                    NULL,
1852                                    &ad_signedpath);
1853         if (ret == 0 && !ad_signedpath)
1854             ret = KRB5KDC_ERR_BADOPTION;
1855         if (ret) {
1856             kdc_log(context, config, 0,
1857                     "KRB5SignedPath check from service %s failed "
1858                     "for delegation to %s for client %s "
1859                     "from %s failed with %s",
1860                     spn, str, cpn, from, krb5_get_err_text(context, ret));
1861             free(str);
1862             goto out;
1863         }
1864
1865         kdc_log(context, config, 0, "constrained delegation for %s "
1866                 "from %s to %s", str, cpn, spn);
1867         free(str);
1868     }
1869
1870     /*
1871      * Check flags
1872      */
1873
1874     ret = _kdc_check_flags(context, config,
1875                            client, cpn,
1876                            server, spn,
1877                            FALSE);
1878     if(ret)
1879         goto out;
1880
1881     if((b->kdc_options.validate || b->kdc_options.renew) &&
1882        !krb5_principal_compare(context,
1883                                krbtgt->entry.principal,
1884                                server->entry.principal)){
1885         kdc_log(context, config, 0, "Inconsistent request.");
1886         ret = KRB5KDC_ERR_SERVER_NOMATCH;
1887         goto out;
1888     }
1889
1890     /* check for valid set of addresses */
1891     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
1892         ret = KRB5KRB_AP_ERR_BADADDR;
1893         kdc_log(context, config, 0, "Request from wrong address");
1894         goto out;
1895     }
1896         
1897     /*
1898      * If this is an referral, add server referral data to the
1899      * auth_data reply .
1900      */
1901     if (ref_realm) {
1902         PA_DATA pa;
1903         krb5_crypto crypto;
1904
1905         kdc_log(context, config, 0,
1906                 "Adding server referral to %s", ref_realm);
1907
1908         ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
1909         if (ret)
1910             goto out;
1911
1912         ret = build_server_referral(context, config, crypto, ref_realm,
1913                                     NULL, s, &pa.padata_value);
1914         krb5_crypto_destroy(context, crypto);
1915         if (ret) {
1916             kdc_log(context, config, 0,
1917                     "Failed building server referral");
1918             goto out;
1919         }
1920         pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
1921
1922         ret = add_METHOD_DATA(&enc_pa_data, &pa);
1923         krb5_data_free(&pa.padata_value);
1924         if (ret) {
1925             kdc_log(context, config, 0,
1926                     "Add server referral METHOD-DATA failed");
1927             goto out;
1928         }
1929     }
1930
1931     /*
1932      *
1933      */
1934
1935     ret = tgs_make_reply(context,
1936                          config,
1937                          b,
1938                          client_principal,
1939                          tgt,
1940                          ekey,
1941                          &sessionkey,
1942                          kvno,
1943                          *auth_data,
1944                          server,
1945                          sp,
1946                          spn,
1947                          client,
1948                          cp,
1949                          krbtgt,
1950                          krbtgt_etype,
1951                          spp,
1952                          &rspac,
1953                          &enc_pa_data,
1954                          e_text,
1955                          reply);
1956         
1957 out:
1958     free(spn);
1959     free(cpn);
1960         
1961     krb5_data_free(&rspac);
1962     krb5_free_keyblock_contents(context, &sessionkey);
1963     if(server)
1964         _kdc_free_ent(context, server);
1965     if(client)
1966         _kdc_free_ent(context, client);
1967
1968     if (client_principal && client_principal != cp)
1969         krb5_free_principal(context, client_principal);
1970     if (cp)
1971         krb5_free_principal(context, cp);
1972     if (sp)
1973         krb5_free_principal(context, sp);
1974     if (ref_realm)
1975         free(ref_realm);
1976     free_METHOD_DATA(&enc_pa_data);
1977
1978     free_EncTicketPart(&adtkt);
1979
1980     return ret;
1981 }
1982
1983 /*
1984  *
1985  */
1986
1987 krb5_error_code
1988 _kdc_tgs_rep(krb5_context context,
1989              krb5_kdc_configuration *config,
1990              KDC_REQ *req,
1991              krb5_data *data,
1992              const char *from,
1993              struct sockaddr *from_addr,
1994              int datagram_reply)
1995 {
1996     AuthorizationData *auth_data = NULL;
1997     krb5_error_code ret;
1998     int i = 0;
1999     const PA_DATA *tgs_req;
2000
2001     hdb_entry_ex *krbtgt = NULL;
2002     krb5_ticket *ticket = NULL;
2003     const char *e_text = NULL;
2004     krb5_enctype krbtgt_etype = ETYPE_NULL;
2005
2006     time_t *csec = NULL;
2007     int *cusec = NULL;
2008
2009     if(req->padata == NULL){
2010         ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2011         kdc_log(context, config, 0,
2012                 "TGS-REQ from %s without PA-DATA", from);
2013         goto out;
2014     }
2015
2016     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2017
2018     if(tgs_req == NULL){
2019         ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2020         
2021         kdc_log(context, config, 0,
2022                 "TGS-REQ from %s without PA-TGS-REQ", from);
2023         goto out;
2024     }
2025     ret = tgs_parse_request(context, config,
2026                             &req->req_body, tgs_req,
2027                             &krbtgt,
2028                             &krbtgt_etype,
2029                             &ticket,
2030                             &e_text,
2031                             from, from_addr,
2032                             &csec, &cusec,
2033                             &auth_data);
2034     if (ret) {
2035         kdc_log(context, config, 0,
2036                 "Failed parsing TGS-REQ from %s", from);
2037         goto out;
2038     }
2039
2040     ret = tgs_build_reply(context,
2041                           config,
2042                           req,
2043                           &req->req_body,
2044                           krbtgt,
2045                           krbtgt_etype,
2046                           ticket,
2047                           data,
2048                           from,
2049                           &e_text,
2050                           &auth_data,
2051                           from_addr,
2052                           datagram_reply);
2053     if (ret) {
2054         kdc_log(context, config, 0,
2055                 "Failed building TGS-REP to %s", from);
2056         goto out;
2057     }
2058
2059     /* */
2060     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2061         krb5_data_free(data);
2062         ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2063         e_text = "Reply packet too large";
2064     }
2065
2066 out:
2067     if(ret && data->data == NULL){
2068         krb5_mk_error(context,
2069                       ret,
2070                       NULL,
2071                       NULL,
2072                       NULL,
2073                       NULL,
2074                       csec,
2075                       cusec,
2076                       data);
2077     }
2078     free(csec);
2079     free(cusec);
2080     if (ticket)
2081         krb5_free_ticket(context, ticket);
2082     if(krbtgt)
2083         _kdc_free_ent(context, krbtgt);
2084
2085     if (auth_data) {
2086         free_AuthorizationData(auth_data);
2087         free(auth_data);
2088     }
2089
2090     return 0;
2091 }