1 /*        $NetBSD: krb5tgs.c,v 1.4 2023/06/19 21:41:41 christos Exp $ */
2 
3 /*
4  * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "kdc_locl.h"
37 
38 /*
39  * return the realm of a krbtgt-ticket or NULL
40  */
41 
42 static Realm
get_krbtgt_realm(const PrincipalName * p)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
find_KRB5SignedPath(krb5_context context,const AuthorizationData * ad,krb5_data * data)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
_kdc_add_KRB5SignedPath(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * krbtgt,krb5_enctype enctype,krb5_const_principal client,krb5_const_principal server,krb5_principals principals,EncTicketPart * tkt)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 client,
110                               krb5_const_principal server,
111                               krb5_principals principals,
112                               EncTicketPart *tkt)
113 {
114     krb5_error_code ret;
115     KRB5SignedPath sp;
116     krb5_data data;
117     krb5_crypto crypto = NULL;
118     size_t size = 0;
119 
120     if (server && principals) {
121           ret = add_Principals(principals, server);
122           if (ret)
123               return ret;
124     }
125 
126     {
127           KRB5SignedPathData spd;
128 
129           spd.client = rk_UNCONST(client);
130           spd.authtime = tkt->authtime;
131           spd.delegated = principals;
132           spd.method_data = NULL;
133 
134           ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
135                                  &spd, &size, ret);
136           if (ret)
137               return ret;
138           if (data.length != size)
139               krb5_abortx(context, "internal asn.1 encoder error");
140     }
141 
142     {
143           Key *key;
144           ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
145           if (ret == 0)
146               ret = krb5_crypto_init(context, &key->key, 0, &crypto);
147           if (ret) {
148               free(data.data);
149               return ret;
150           }
151     }
152 
153     /*
154      * Fill in KRB5SignedPath
155      */
156 
157     sp.etype = enctype;
158     sp.delegated = principals;
159     sp.method_data = NULL;
160 
161     ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
162                                      data.data, data.length, &sp.cksum);
163     krb5_crypto_destroy(context, crypto);
164     free(data.data);
165     if (ret)
166           return ret;
167 
168     ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
169     free_Checksum(&sp.cksum);
170     if (ret)
171           return ret;
172     if (data.length != size)
173           krb5_abortx(context, "internal asn.1 encoder error");
174 
175 
176     /*
177      * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178      * authorization data field.
179      */
180 
181     ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
182                                               KRB5_AUTHDATA_SIGNTICKET, &data);
183     krb5_data_free(&data);
184 
185     return ret;
186 }
187 
188 static krb5_error_code
check_KRB5SignedPath(krb5_context context,krb5_kdc_configuration * config,hdb_entry_ex * krbtgt,krb5_principal cp,EncTicketPart * tkt,krb5_principals * delegated,int * signedpath)189 check_KRB5SignedPath(krb5_context context,
190                          krb5_kdc_configuration *config,
191                          hdb_entry_ex *krbtgt,
192                          krb5_principal cp,
193                          EncTicketPart *tkt,
194                          krb5_principals *delegated,
195                          int *signedpath)
196 {
197     krb5_error_code ret;
198     krb5_data data;
199     krb5_crypto crypto = NULL;
200 
201     if (delegated)
202           *delegated = NULL;
203 
204     ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
205     if (ret == 0) {
206           KRB5SignedPathData spd;
207           KRB5SignedPath sp;
208           size_t size = 0;
209 
210           ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
211           krb5_data_free(&data);
212           if (ret)
213               return ret;
214 
215           spd.client = cp;
216           spd.authtime = tkt->authtime;
217           spd.delegated = sp.delegated;
218           spd.method_data = sp.method_data;
219 
220           ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221                                  &spd, &size, ret);
222           if (ret) {
223               free_KRB5SignedPath(&sp);
224               return ret;
225           }
226           if (data.length != size)
227               krb5_abortx(context, "internal asn.1 encoder error");
228 
229           {
230               Key *key;
231               ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
232                                           sp.etype, &key);
233               if (ret == 0)
234                     ret = krb5_crypto_init(context, &key->key, 0, &crypto);
235               if (ret) {
236                     free(data.data);
237                     free_KRB5SignedPath(&sp);
238                     return ret;
239               }
240           }
241           ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
242                                            data.data, data.length,
243                                            &sp.cksum);
244           krb5_crypto_destroy(context, crypto);
245           free(data.data);
246           if (ret) {
247               free_KRB5SignedPath(&sp);
248               kdc_log(context, config, 5,
249                         "KRB5SignedPath not signed correctly, not marking as signed");
250               return 0;
251           }
252 
253           if (delegated && sp.delegated) {
254 
255               *delegated = malloc(sizeof(*sp.delegated));
256               if (*delegated == NULL) {
257                     free_KRB5SignedPath(&sp);
258                     return ENOMEM;
259               }
260 
261               ret = copy_Principals(*delegated, sp.delegated);
262               if (ret) {
263                     free_KRB5SignedPath(&sp);
264                     free(*delegated);
265                     *delegated = NULL;
266                     return ret;
267               }
268           }
269           free_KRB5SignedPath(&sp);
270 
271           *signedpath = 1;
272     }
273 
274     return 0;
275 }
276 
277 /*
278  *
279  */
280 
281 static krb5_error_code
check_PAC(krb5_context context,krb5_kdc_configuration * config,const krb5_principal client_principal,const krb5_principal delegated_proxy_principal,hdb_entry_ex * client,hdb_entry_ex * server,hdb_entry_ex * krbtgt,const EncryptionKey * server_check_key,const EncryptionKey * server_sign_key,const EncryptionKey * krbtgt_sign_key,EncTicketPart * tkt,krb5_data * rspac,int * signedpath)282 check_PAC(krb5_context context,
283             krb5_kdc_configuration *config,
284             const krb5_principal client_principal,
285             const krb5_principal delegated_proxy_principal,
286             hdb_entry_ex *client,
287             hdb_entry_ex *server,
288             hdb_entry_ex *krbtgt,
289             const EncryptionKey *server_check_key,
290             const EncryptionKey *server_sign_key,
291             const EncryptionKey *krbtgt_sign_key,
292             EncTicketPart *tkt,
293             krb5_data *rspac,
294             int *signedpath)
295 {
296     AuthorizationData *ad = tkt->authorization_data;
297     unsigned i, j;
298     krb5_error_code ret;
299 
300     if (ad == NULL || ad->len == 0)
301           return 0;
302 
303     for (i = 0; i < ad->len; i++) {
304           AuthorizationData child;
305 
306           if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
307               continue;
308 
309           ret = decode_AuthorizationData(ad->val[i].ad_data.data,
310                                                ad->val[i].ad_data.length,
311                                                &child,
312                                                NULL);
313           if (ret) {
314               krb5_set_error_message(context, ret, "Failed to decode "
315                                            "IF_RELEVANT with %d", ret);
316               return ret;
317           }
318           for (j = 0; j < child.len; j++) {
319 
320               if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
321                     int signed_pac = 0;
322                     krb5_pac pac;
323 
324                     /* Found PAC */
325                     ret = krb5_pac_parse(context,
326                                              child.val[j].ad_data.data,
327                                              child.val[j].ad_data.length,
328                                              &pac);
329                     free_AuthorizationData(&child);
330                     if (ret)
331                         return ret;
332 
333                     ret = krb5_pac_verify(context, pac, tkt->authtime,
334                                               client_principal,
335                                               server_check_key, NULL);
336                     if (ret) {
337                         krb5_pac_free(context, pac);
338                         return ret;
339                     }
340 
341                     ret = _kdc_pac_verify(context, client_principal,
342                                               delegated_proxy_principal,
343                                               client, server, krbtgt, &pac, &signed_pac);
344                     if (ret) {
345                         krb5_pac_free(context, pac);
346                         return ret;
347                     }
348 
349                     /*
350                      * Only re-sign PAC if we could verify it with the PAC
351                      * function. The no-verify case happens when we get in
352                      * a PAC from cross realm from a Windows domain and
353                      * that there is no PAC verification function.
354                      */
355                     if (signed_pac) {
356                         *signedpath = 1;
357                         ret = _krb5_pac_sign(context, pac, tkt->authtime,
358                                                    client_principal,
359                                                    server_sign_key, krbtgt_sign_key, rspac);
360                     }
361                     krb5_pac_free(context, pac);
362 
363                     return ret;
364               }
365           }
366           free_AuthorizationData(&child);
367     }
368     return 0;
369 }
370 
371 static krb5_boolean
is_anon_tgs_request_p(const KDC_REQ_BODY * b,const EncTicketPart * tgt)372 is_anon_tgs_request_p(const KDC_REQ_BODY *b,
373                           const EncTicketPart *tgt)
374 {
375     KDCOptions f = b->kdc_options;
376 
377     /*
378      * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
379      * request-anonymous and cname-in-addl-tkt flags for constrained
380      * delegation requests. A true anonymous TGS request will only
381      * have the request-anonymous flag set. (A corollary of this is
382      * that it is not possible to support anonymous constrained
383      * delegation requests, although they would be of limited utility.)
384      */
385     return tgt->flags.anonymous ||
386           (f.request_anonymous && !f.cname_in_addl_tkt && !b->additional_tickets);
387 }
388 
389 /*
390  *
391  */
392 
393 static krb5_error_code
check_tgs_flags(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,krb5_const_principal tgt_name,const EncTicketPart * tgt,EncTicketPart * et)394 check_tgs_flags(krb5_context context,
395                     krb5_kdc_configuration *config,
396                     KDC_REQ_BODY *b,
397                     krb5_const_principal tgt_name,
398                     const EncTicketPart *tgt,
399                     EncTicketPart *et)
400 {
401     KDCOptions f = b->kdc_options;
402 
403     if(f.validate){
404           if(!tgt->flags.invalid || tgt->starttime == NULL){
405               kdc_log(context, config, 0,
406                         "Bad request to validate ticket");
407               return KRB5KDC_ERR_BADOPTION;
408           }
409           if(*tgt->starttime > kdc_time){
410               kdc_log(context, config, 0,
411                         "Early request to validate ticket");
412               return KRB5KRB_AP_ERR_TKT_NYV;
413           }
414           /* XXX  tkt = tgt */
415           et->flags.invalid = 0;
416     }else if(tgt->flags.invalid){
417           kdc_log(context, config, 0,
418                     "Ticket-granting ticket has INVALID flag set");
419           return KRB5KRB_AP_ERR_TKT_INVALID;
420     }
421 
422     if(f.forwardable){
423           if(!tgt->flags.forwardable){
424               kdc_log(context, config, 0,
425                         "Bad request for forwardable ticket");
426               return KRB5KDC_ERR_BADOPTION;
427           }
428           et->flags.forwardable = 1;
429     }
430     if(f.forwarded){
431           if(!tgt->flags.forwardable){
432               kdc_log(context, config, 0,
433                         "Request to forward non-forwardable ticket");
434               return KRB5KDC_ERR_BADOPTION;
435           }
436           et->flags.forwarded = 1;
437           et->caddr = b->addresses;
438     }
439     if(tgt->flags.forwarded)
440           et->flags.forwarded = 1;
441 
442     if(f.proxiable){
443           if(!tgt->flags.proxiable){
444               kdc_log(context, config, 0,
445                         "Bad request for proxiable ticket");
446               return KRB5KDC_ERR_BADOPTION;
447           }
448           et->flags.proxiable = 1;
449     }
450     if(f.proxy){
451           if(!tgt->flags.proxiable){
452               kdc_log(context, config, 0,
453                         "Request to proxy non-proxiable ticket");
454               return KRB5KDC_ERR_BADOPTION;
455           }
456           et->flags.proxy = 1;
457           et->caddr = b->addresses;
458     }
459     if(tgt->flags.proxy)
460           et->flags.proxy = 1;
461 
462     if(f.allow_postdate){
463           if(!tgt->flags.may_postdate){
464               kdc_log(context, config, 0,
465                         "Bad request for post-datable ticket");
466               return KRB5KDC_ERR_BADOPTION;
467           }
468           et->flags.may_postdate = 1;
469     }
470     if(f.postdated){
471           if(!tgt->flags.may_postdate){
472               kdc_log(context, config, 0,
473                         "Bad request for postdated ticket");
474               return KRB5KDC_ERR_BADOPTION;
475           }
476           if(b->from)
477               *et->starttime = *b->from;
478           et->flags.postdated = 1;
479           et->flags.invalid = 1;
480     }else if(b->from && *b->from > kdc_time + context->max_skew){
481           kdc_log(context, config, 0, "Ticket cannot be postdated");
482           return KRB5KDC_ERR_CANNOT_POSTDATE;
483     }
484 
485     if(f.renewable){
486           if(!tgt->flags.renewable || tgt->renew_till == NULL){
487               kdc_log(context, config, 0,
488                         "Bad request for renewable ticket");
489               return KRB5KDC_ERR_BADOPTION;
490           }
491           et->flags.renewable = 1;
492           ALLOC(et->renew_till);
493           _kdc_fix_time(&b->rtime);
494           *et->renew_till = *b->rtime;
495     }
496     if(f.renew){
497           time_t old_life;
498           if(!tgt->flags.renewable || tgt->renew_till == NULL){
499               kdc_log(context, config, 0,
500                         "Request to renew non-renewable ticket");
501               return KRB5KDC_ERR_BADOPTION;
502           }
503           old_life = tgt->endtime;
504           if(tgt->starttime)
505               old_life -= *tgt->starttime;
506           else
507               old_life -= tgt->authtime;
508           et->endtime = *et->starttime + old_life;
509           if (et->renew_till != NULL)
510               et->endtime = min(*et->renew_till, et->endtime);
511     }
512 
513     /*
514      * RFC 8062 section 3 defines an anonymous ticket as one containing
515      * the anonymous principal and the anonymous ticket flag.
516      */
517     if (tgt->flags.anonymous &&
518           !_kdc_is_anonymous(context, tgt_name)) {
519           kdc_log(context, config, 0,
520                     "Anonymous ticket flag set without anonymous principal");
521           return KRB5KDC_ERR_BADOPTION;
522     }
523 
524     /*
525      * RFC 8062 section 4.2 states that if the TGT is anonymous, the
526      * anonymous KDC option SHOULD be set, but it is not required.
527      * Treat an anonymous TGT as if the anonymous flag was set.
528      */
529     if (is_anon_tgs_request_p(b, tgt))
530           et->flags.anonymous = 1;
531 
532     return 0;
533 }
534 
535 /*
536  * Determine if constrained delegation is allowed from this client to this server
537  */
538 
539 static krb5_error_code
check_constrained_delegation(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,hdb_entry_ex * server,krb5_const_principal target)540 check_constrained_delegation(krb5_context context,
541                                    krb5_kdc_configuration *config,
542                                    HDB *clientdb,
543                                    hdb_entry_ex *client,
544                                    hdb_entry_ex *server,
545                                    krb5_const_principal target)
546 {
547     const HDB_Ext_Constrained_delegation_acl *acl;
548     krb5_error_code ret;
549     size_t i;
550 
551     /*
552      * constrained_delegation (S4U2Proxy) only works within
553      * the same realm. We use the already canonicalized version
554      * of the principals here, while "target" is the principal
555      * provided by the client.
556      */
557     if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
558           ret = KRB5KDC_ERR_BADOPTION;
559           kdc_log(context, config, 0,
560               "Bad request for constrained delegation");
561           return ret;
562     }
563 
564     if (clientdb->hdb_check_constrained_delegation) {
565           ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
566           if (ret == 0)
567               return 0;
568     } else {
569           /* if client delegates to itself, that ok */
570           if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
571               return 0;
572 
573           ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
574           if (ret) {
575               krb5_clear_error_message(context);
576               return ret;
577           }
578 
579           if (acl) {
580               for (i = 0; i < acl->len; i++) {
581                     if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
582                         return 0;
583               }
584           }
585           ret = KRB5KDC_ERR_BADOPTION;
586     }
587     kdc_log(context, config, 0,
588               "Bad request for constrained delegation");
589     return ret;
590 }
591 
592 /*
593  * Determine if s4u2self is allowed from this client to this server
594  *
595  * For example, regardless of the principal being impersonated, if the
596  * 'client' and 'server' are the same, then it's safe.
597  */
598 
599 static krb5_error_code
check_s4u2self(krb5_context context,krb5_kdc_configuration * config,HDB * clientdb,hdb_entry_ex * client,krb5_const_principal server)600 check_s4u2self(krb5_context context,
601                  krb5_kdc_configuration *config,
602                  HDB *clientdb,
603                  hdb_entry_ex *client,
604                  krb5_const_principal server)
605 {
606     krb5_error_code ret;
607 
608     /* if client does a s4u2self to itself, that ok */
609     if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
610           return 0;
611 
612     if (clientdb->hdb_check_s4u2self) {
613           ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
614           if (ret == 0)
615               return 0;
616     } else {
617           ret = KRB5KDC_ERR_BADOPTION;
618     }
619     return ret;
620 }
621 
622 /*
623  *
624  */
625 
626 static krb5_error_code
verify_flags(krb5_context context,krb5_kdc_configuration * config,const EncTicketPart * et,const char * pstr)627 verify_flags (krb5_context context,
628                 krb5_kdc_configuration *config,
629                 const EncTicketPart *et,
630                 const char *pstr)
631 {
632     if(et->endtime < kdc_time){
633           kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
634           return KRB5KRB_AP_ERR_TKT_EXPIRED;
635     }
636     if(et->flags.invalid){
637           kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
638           return KRB5KRB_AP_ERR_TKT_NYV;
639     }
640     return 0;
641 }
642 
643 /*
644  *
645  */
646 
647 static krb5_error_code
fix_transited_encoding(krb5_context context,krb5_kdc_configuration * config,krb5_boolean check_policy,const TransitedEncoding * tr,EncTicketPart * et,const char * client_realm,const char * server_realm,const char * tgt_realm)648 fix_transited_encoding(krb5_context context,
649                            krb5_kdc_configuration *config,
650                            krb5_boolean check_policy,
651                            const TransitedEncoding *tr,
652                            EncTicketPart *et,
653                            const char *client_realm,
654                            const char *server_realm,
655                            const char *tgt_realm)
656 {
657     krb5_error_code ret = 0;
658     char **realms, **tmp;
659     unsigned int num_realms;
660     size_t i;
661 
662     switch (tr->tr_type) {
663     case DOMAIN_X500_COMPRESS:
664           break;
665     case 0:
666           /*
667            * Allow empty content of type 0 because that is was Microsoft
668            * generates in their TGT.
669            */
670           if (tr->contents.length == 0)
671               break;
672           kdc_log(context, config, 0,
673                     "Transited type 0 with non empty content");
674           return KRB5KDC_ERR_TRTYPE_NOSUPP;
675     default:
676           kdc_log(context, config, 0,
677                     "Unknown transited type: %u", tr->tr_type);
678           return KRB5KDC_ERR_TRTYPE_NOSUPP;
679     }
680 
681     ret = krb5_domain_x500_decode(context,
682                                           tr->contents,
683                                           &realms,
684                                           &num_realms,
685                                           client_realm,
686                                           server_realm);
687     if(ret){
688           krb5_warn(context, ret,
689                       "Decoding transited encoding");
690           return ret;
691     }
692 
693     /*
694      * If the realm of the presented tgt is neither the client nor the server
695      * realm, it is a transit realm and must be added to transited set.
696      */
697     if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
698           if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
699               ret = ERANGE;
700               goto free_realms;
701           }
702           tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
703           if(tmp == NULL){
704               ret = ENOMEM;
705               goto free_realms;
706           }
707           realms = tmp;
708           realms[num_realms] = strdup(tgt_realm);
709           if(realms[num_realms] == NULL){
710               ret = ENOMEM;
711               goto free_realms;
712           }
713           num_realms++;
714     }
715     if(num_realms == 0) {
716           if(strcmp(client_realm, server_realm))
717               kdc_log(context, config, 0,
718                         "cross-realm %s -> %s", client_realm, server_realm);
719     } else {
720           size_t l = 0;
721           char *rs;
722           for(i = 0; i < num_realms; i++)
723               l += strlen(realms[i]) + 2;
724           rs = malloc(l);
725           if(rs != NULL) {
726               *rs = '\0';
727               for(i = 0; i < num_realms; i++) {
728                     if(i > 0)
729                         strlcat(rs, ", ", l);
730                     strlcat(rs, realms[i], l);
731               }
732               kdc_log(context, config, 0,
733                         "cross-realm %s -> %s via [%s]",
734                         client_realm, server_realm, rs);
735               free(rs);
736           }
737     }
738     if(check_policy) {
739           ret = krb5_check_transited(context, client_realm,
740                                            server_realm,
741                                            realms, num_realms, NULL);
742           if(ret) {
743               krb5_warn(context, ret, "cross-realm %s -> %s",
744                           client_realm, server_realm);
745               goto free_realms;
746           }
747           et->flags.transited_policy_checked = 1;
748     }
749     et->transited.tr_type = DOMAIN_X500_COMPRESS;
750     ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
751     if(ret)
752           krb5_warn(context, ret, "Encoding transited encoding");
753   free_realms:
754     for(i = 0; i < num_realms; i++)
755           free(realms[i]);
756     free(realms);
757     return ret;
758 }
759 
760 
761 static krb5_error_code
tgs_make_reply(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,krb5_const_principal tgt_name,const EncTicketPart * tgt,const krb5_keyblock * replykey,int rk_is_subkey,const EncryptionKey * serverkey,const krb5_keyblock * sessionkey,krb5_kvno kvno,AuthorizationData * auth_data,hdb_entry_ex * server,krb5_principal server_principal,const char * server_name,hdb_entry_ex * client,krb5_principal client_principal,const char * tgt_realm,hdb_entry_ex * krbtgt,krb5_enctype krbtgt_etype,krb5_principals spp,const krb5_data * rspac,const METHOD_DATA * enc_pa_data,const char ** e_text,krb5_data * reply)762 tgs_make_reply(krb5_context context,
763                  krb5_kdc_configuration *config,
764                  KDC_REQ_BODY *b,
765                  krb5_const_principal tgt_name,
766                  const EncTicketPart *tgt,
767                  const krb5_keyblock *replykey,
768                  int rk_is_subkey,
769                  const EncryptionKey *serverkey,
770                  const krb5_keyblock *sessionkey,
771                  krb5_kvno kvno,
772                  AuthorizationData *auth_data,
773                  hdb_entry_ex *server,
774                  krb5_principal server_principal,
775                  const char *server_name,
776                  hdb_entry_ex *client,
777                  krb5_principal client_principal,
778                const char *tgt_realm,
779                  hdb_entry_ex *krbtgt,
780                  krb5_enctype krbtgt_etype,
781                  krb5_principals spp,
782                  const krb5_data *rspac,
783                  const METHOD_DATA *enc_pa_data,
784                  const char **e_text,
785                  krb5_data *reply)
786 {
787     KDC_REP rep;
788     EncKDCRepPart ek;
789     EncTicketPart et;
790     KDCOptions f = b->kdc_options;
791     krb5_error_code ret;
792     int is_weak = 0;
793 
794     memset(&rep, 0, sizeof(rep));
795     memset(&et, 0, sizeof(et));
796     memset(&ek, 0, sizeof(ek));
797 
798     rep.pvno = 5;
799     rep.msg_type = krb_tgs_rep;
800 
801     et.authtime = tgt->authtime;
802     _kdc_fix_time(&b->till);
803     et.endtime = min(tgt->endtime, *b->till);
804     ALLOC(et.starttime);
805     *et.starttime = kdc_time;
806 
807     ret = check_tgs_flags(context, config, b, tgt_name, tgt, &et);
808     if(ret)
809           goto out;
810 
811     /* We should check the transited encoding if:
812        1) the request doesn't ask not to be checked
813        2) globally enforcing a check
814        3) principal requires checking
815        4) we allow non-check per-principal, but principal isn't marked as allowing this
816        5) we don't globally allow this
817     */
818 
819 #define GLOBAL_FORCE_TRANSITED_CHECK              \
820     (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
821 #define GLOBAL_ALLOW_PER_PRINCIPAL                          \
822     (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
823 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK                          \
824     (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
825 
826 /* these will consult the database in future release */
827 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P)                  0
828 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P)          0
829 
830     ret = fix_transited_encoding(context, config,
831                                          !f.disable_transited_check ||
832                                          GLOBAL_FORCE_TRANSITED_CHECK ||
833                                          PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
834                                          !((GLOBAL_ALLOW_PER_PRINCIPAL &&
835                                             PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
836                                            GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
837                                          &tgt->transited, &et,
838                                          krb5_principal_get_realm(context, client_principal),
839                                          krb5_principal_get_realm(context, server->entry.principal),
840                                          tgt_realm);
841     if(ret)
842           goto out;
843 
844     ret = copy_Realm(&server_principal->realm, &rep.ticket.realm);
845     if (ret)
846           goto out;
847     _krb5_principal2principalname(&rep.ticket.sname, server_principal);
848     ret = copy_Realm(&tgt_name->realm, &rep.crealm);
849     if (ret)
850           goto out;
851 
852     /*
853      * RFC 8062 states "if the ticket in the TGS request is an anonymous
854      * one, the client and client realm are copied from that ticket". So
855      * whilst the TGT flag check below is superfluous, it is included in
856      * order to follow the specification to its letter.
857      */
858     if (et.flags.anonymous && !tgt->flags.anonymous)
859           _kdc_make_anonymous_principalname(&rep.cname);
860     else
861           ret = copy_PrincipalName(&tgt_name->name, &rep.cname);
862     if (ret)
863           goto out;
864     rep.ticket.tkt_vno = 5;
865 
866     ek.caddr = et.caddr;
867 
868     {
869           time_t life;
870           life = et.endtime - *et.starttime;
871           if(client && client->entry.max_life)
872               life = min(life, *client->entry.max_life);
873           if(server->entry.max_life)
874               life = min(life, *server->entry.max_life);
875           et.endtime = *et.starttime + life;
876     }
877     if(f.renewable_ok && tgt->flags.renewable &&
878        et.renew_till == NULL && et.endtime < *b->till &&
879        tgt->renew_till != NULL)
880     {
881           et.flags.renewable = 1;
882           ALLOC(et.renew_till);
883           *et.renew_till = *b->till;
884     }
885     if(et.renew_till){
886           time_t renew;
887           renew = *et.renew_till - *et.starttime;
888           if(client && client->entry.max_renew)
889               renew = min(renew, *client->entry.max_renew);
890           if(server->entry.max_renew)
891               renew = min(renew, *server->entry.max_renew);
892           *et.renew_till = *et.starttime + renew;
893     }
894 
895     if(et.renew_till){
896           *et.renew_till = min(*et.renew_till, *tgt->renew_till);
897           *et.starttime = min(*et.starttime, *et.renew_till);
898           et.endtime = min(et.endtime, *et.renew_till);
899     }
900 
901     *et.starttime = min(*et.starttime, et.endtime);
902 
903     if(*et.starttime == et.endtime){
904           ret = KRB5KDC_ERR_NEVER_VALID;
905           goto out;
906     }
907     if(et.renew_till && et.endtime == *et.renew_till){
908           free(et.renew_till);
909           et.renew_till = NULL;
910           et.flags.renewable = 0;
911     }
912 
913     et.flags.pre_authent = tgt->flags.pre_authent;
914     et.flags.hw_authent  = tgt->flags.hw_authent;
915     et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
916 
917     /* See MS-KILE 3.3.5.1 */
918     if (!server->entry.flags.forwardable)
919           et.flags.forwardable = 0;
920     if (!server->entry.flags.proxiable)
921           et.flags.proxiable = 0;
922 
923     /*
924      * For anonymous tickets, we should filter out positive authorization data
925      * that could reveal the client's identity, and return a policy error for
926      * restrictive authorization data. Policy for unknown authorization types
927      * is implementation dependent.
928      */
929     if (rspac->length && !et.flags.anonymous) {
930           /*
931            * No not need to filter out the any PAC from the
932            * auth_data since it's signed by the KDC.
933            */
934           ret = _kdc_tkt_add_if_relevant_ad(context, &et,
935                                                     KRB5_AUTHDATA_WIN2K_PAC, rspac);
936           if (ret)
937               goto out;
938     }
939 
940     if (auth_data) {
941           unsigned int i = 0;
942 
943           /* XXX check authdata */
944 
945           if (et.authorization_data == NULL) {
946               et.authorization_data = calloc(1, sizeof(*et.authorization_data));
947               if (et.authorization_data == NULL) {
948                     ret = ENOMEM;
949                     krb5_set_error_message(context, ret, "malloc: out of memory");
950                     goto out;
951               }
952           }
953           for(i = 0; i < auth_data->len ; i++) {
954               ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
955               if (ret) {
956                     krb5_set_error_message(context, ret, "malloc: out of memory");
957                     goto out;
958               }
959           }
960 
961           /* Filter out type KRB5SignedPath */
962           ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
963           if (ret == 0) {
964               if (et.authorization_data->len == 1) {
965                     free_AuthorizationData(et.authorization_data);
966                     free(et.authorization_data);
967                     et.authorization_data = NULL;
968               } else {
969                     AuthorizationData *ad = et.authorization_data;
970                     free_AuthorizationDataElement(&ad->val[ad->len - 1]);
971                     ad->len--;
972               }
973           }
974     }
975 
976     ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
977     if (ret)
978           goto out;
979     et.crealm = rep.crealm;
980     et.cname = rep.cname;
981 
982     ek.key = et.key;
983     /* MIT must have at least one last_req */
984     ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
985     if (ek.last_req.val == NULL) {
986           ret = ENOMEM;
987           goto out;
988     }
989     ek.last_req.len = 1; /* set after alloc to avoid null deref on cleanup */
990     ek.nonce = b->nonce;
991     ek.flags = et.flags;
992     ek.authtime = et.authtime;
993     ek.starttime = et.starttime;
994     ek.endtime = et.endtime;
995     ek.renew_till = et.renew_till;
996     ek.srealm = rep.ticket.realm;
997     ek.sname = rep.ticket.sname;
998 
999     _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
1000                            et.endtime, et.renew_till);
1001 
1002     /* Don't sign cross realm tickets, they can't be checked anyway */
1003     {
1004           char *r = get_krbtgt_realm(&ek.sname);
1005 
1006           if (r == NULL || strcmp(r, ek.srealm) == 0) {
1007               ret = _kdc_add_KRB5SignedPath(context,
1008                                                     config,
1009                                                     krbtgt,
1010                                                     krbtgt_etype,
1011                                                     client_principal,
1012                                                     NULL,
1013                                                     spp,
1014                                                     &et);
1015               if (ret)
1016                     goto out;
1017           }
1018     }
1019 
1020     if (enc_pa_data->len) {
1021           rep.padata = calloc(1, sizeof(*rep.padata));
1022           if (rep.padata == NULL) {
1023               ret = ENOMEM;
1024               goto out;
1025           }
1026           ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
1027           if (ret)
1028               goto out;
1029     }
1030 
1031     if (krb5_enctype_valid(context, serverkey->keytype) != 0
1032           && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
1033     {
1034           krb5_enctype_enable(context, serverkey->keytype);
1035           is_weak = 1;
1036     }
1037 
1038 
1039     /* It is somewhat unclear where the etype in the following
1040        encryption should come from. What we have is a session
1041        key in the passed tgt, and a list of preferred etypes
1042        *for the new ticket*. Should we pick the best possible
1043        etype, given the keytype in the tgt, or should we look
1044        at the etype list here as well?  What if the tgt
1045        session key is DES3 and we want a ticket with a (say)
1046        CAST session key. Should the DES3 etype be added to the
1047        etype list, even if we don't want a session key with
1048        DES3? */
1049     ret = _kdc_encode_reply(context, config, NULL, 0,
1050                                   &rep, &et, &ek, serverkey->keytype,
1051                                   kvno,
1052                                   serverkey, 0, replykey, rk_is_subkey,
1053                                   e_text, reply);
1054     if (is_weak)
1055           krb5_enctype_disable(context, serverkey->keytype);
1056 
1057 out:
1058     free_TGS_REP(&rep);
1059     free_TransitedEncoding(&et.transited);
1060     if(et.starttime)
1061           free(et.starttime);
1062     if(et.renew_till)
1063           free(et.renew_till);
1064     if(et.authorization_data) {
1065           free_AuthorizationData(et.authorization_data);
1066           free(et.authorization_data);
1067     }
1068     free_LastReq(&ek.last_req);
1069     memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1070     free_EncryptionKey(&et.key);
1071     return ret;
1072 }
1073 
1074 static krb5_error_code
tgs_check_authenticator(krb5_context context,krb5_kdc_configuration * config,krb5_auth_context ac,KDC_REQ_BODY * b,const char ** e_text,krb5_keyblock * key)1075 tgs_check_authenticator(krb5_context context,
1076                               krb5_kdc_configuration *config,
1077                           krb5_auth_context ac,
1078                               KDC_REQ_BODY *b,
1079                               const char **e_text,
1080                               krb5_keyblock *key)
1081 {
1082     krb5_authenticator auth;
1083     size_t len = 0;
1084     unsigned char *buf;
1085     size_t buf_size;
1086     krb5_error_code ret;
1087     krb5_crypto crypto;
1088 
1089     krb5_auth_con_getauthenticator(context, ac, &auth);
1090     if(auth->cksum == NULL){
1091           kdc_log(context, config, 0, "No authenticator in request");
1092           ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1093           goto out;
1094     }
1095     /*
1096      * according to RFC1510 it doesn't need to be keyed,
1097      * but according to the latest draft it needs to.
1098      */
1099     if (
1100 #if 0
1101 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1102           ||
1103 #endif
1104  !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1105           kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1106                     auth->cksum->cksumtype);
1107           ret =  KRB5KRB_AP_ERR_INAPP_CKSUM;
1108           goto out;
1109     }
1110 
1111     /* XXX should not re-encode this */
1112     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1113     if(ret){
1114           const char *msg = krb5_get_error_message(context, ret);
1115           kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1116           krb5_free_error_message(context, msg);
1117           goto out;
1118     }
1119     if(buf_size != len) {
1120           free(buf);
1121           kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1122           *e_text = "KDC internal error";
1123           ret = KRB5KRB_ERR_GENERIC;
1124           goto out;
1125     }
1126     ret = krb5_crypto_init(context, key, 0, &crypto);
1127     if (ret) {
1128           const char *msg = krb5_get_error_message(context, ret);
1129           free(buf);
1130           kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1131           krb5_free_error_message(context, msg);
1132           goto out;
1133     }
1134     ret = krb5_verify_checksum(context,
1135                                      crypto,
1136                                      KRB5_KU_TGS_REQ_AUTH_CKSUM,
1137                                      buf,
1138                                      len,
1139                                      auth->cksum);
1140     free(buf);
1141     krb5_crypto_destroy(context, crypto);
1142     if(ret){
1143           const char *msg = krb5_get_error_message(context, ret);
1144           kdc_log(context, config, 0,
1145                     "Failed to verify authenticator checksum: %s", msg);
1146           krb5_free_error_message(context, msg);
1147     }
1148 out:
1149     free_Authenticator(auth);
1150     free(auth);
1151     return ret;
1152 }
1153 
1154 static krb5_boolean
need_referral(krb5_context context,krb5_kdc_configuration * config,const KDCOptions * const options,krb5_principal server,krb5_realm ** realms)1155 need_referral(krb5_context context, krb5_kdc_configuration *config,
1156                 const KDCOptions * const options, krb5_principal server,
1157                 krb5_realm **realms)
1158 {
1159     const char *name;
1160 
1161     if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1162           return FALSE;
1163 
1164     if (server->name.name_string.len == 1)
1165           name = server->name.name_string.val[0];
1166     else if (server->name.name_string.len == 3) {
1167           /*
1168             This is used to give referrals for the
1169             E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
1170             SPN form, which is used for inter-domain communication in AD
1171            */
1172           name = server->name.name_string.val[2];
1173           kdc_log(context, config, 0, "Giving 3 part referral for %s", name);
1174           *realms = malloc(sizeof(char *)*2);
1175           if (*realms == NULL) {
1176               krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1177               return FALSE;
1178           }
1179           (*realms)[0] = strdup(name);
1180           (*realms)[1] = NULL;
1181           return TRUE;
1182     } else if (server->name.name_string.len > 1)
1183           name = server->name.name_string.val[1];
1184     else
1185           return FALSE;
1186 
1187     kdc_log(context, config, 0, "Searching referral for %s", name);
1188 
1189     return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1190 }
1191 
1192 static krb5_error_code
tgs_parse_request(krb5_context context,krb5_kdc_configuration * config,KDC_REQ_BODY * b,const PA_DATA * tgs_req,hdb_entry_ex ** krbtgt,krb5_enctype * krbtgt_etype,krb5_ticket ** ticket,const char ** e_text,const char * from,const struct sockaddr * from_addr,time_t ** csec,int ** cusec,AuthorizationData ** auth_data,krb5_keyblock ** replykey,int * rk_is_subkey)1193 tgs_parse_request(krb5_context context,
1194                       krb5_kdc_configuration *config,
1195                       KDC_REQ_BODY *b,
1196                       const PA_DATA *tgs_req,
1197                       hdb_entry_ex **krbtgt,
1198                       krb5_enctype *krbtgt_etype,
1199                       krb5_ticket **ticket,
1200                       const char **e_text,
1201                       const char *from,
1202                       const struct sockaddr *from_addr,
1203                       time_t **csec,
1204                       int **cusec,
1205                       AuthorizationData **auth_data,
1206                       krb5_keyblock **replykey,
1207                       int *rk_is_subkey)
1208 {
1209     static char failed[] = "<unparse_name failed>";
1210     krb5_ap_req ap_req;
1211     krb5_error_code ret;
1212     krb5_principal princ;
1213     krb5_auth_context ac = NULL;
1214     krb5_flags ap_req_options;
1215     krb5_flags verify_ap_req_flags;
1216     krb5_crypto crypto;
1217     krb5uint32 krbtgt_kvno;     /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1218     krb5uint32 krbtgt_kvno_try;
1219     int kvno_search_tries = 4;  /* number of kvnos to try when tkt_vno == 0 */
1220     const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1221     Key *tkey;
1222     krb5_keyblock *subkey = NULL;
1223     unsigned usage;
1224 
1225     *auth_data = NULL;
1226     *csec  = NULL;
1227     *cusec = NULL;
1228     *replykey = NULL;
1229 
1230     memset(&ap_req, 0, sizeof(ap_req));
1231     ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1232     if(ret){
1233           const char *msg = krb5_get_error_message(context, ret);
1234           kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1235           krb5_free_error_message(context, msg);
1236           goto out;
1237     }
1238 
1239     if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1240           /* XXX check for ticket.sname == req.sname */
1241           kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1242           ret = KRB5KDC_ERR_POLICY; /* ? */
1243           goto out;
1244     }
1245 
1246     _krb5_principalname2krb5_principal(context,
1247                                                &princ,
1248                                                ap_req.ticket.sname,
1249                                                ap_req.ticket.realm);
1250 
1251     krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1252     ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
1253                               &krbtgt_kvno, NULL, krbtgt);
1254 
1255     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1256           /* XXX Factor out this unparsing of the same princ all over */
1257           char *p;
1258           ret = krb5_unparse_name(context, princ, &p);
1259           if (ret != 0)
1260               p = failed;
1261           krb5_free_principal(context, princ);
1262           kdc_log(context, config, 5,
1263                     "Ticket-granting ticket account %s does not have secrets at "
1264                     "this KDC, need to proxy", p);
1265           if (ret == 0)
1266               free(p);
1267           ret = HDB_ERR_NOT_FOUND_HERE;
1268           goto out;
1269     } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1270           char *p;
1271           ret = krb5_unparse_name(context, princ, &p);
1272           if (ret != 0)
1273               p = failed;
1274           krb5_free_principal(context, princ);
1275           kdc_log(context, config, 5,
1276                     "Ticket-granting ticket account %s does not have keys for "
1277                     "kvno %d at this KDC", p, krbtgt_kvno);
1278           if (ret == 0)
1279               free(p);
1280           ret = HDB_ERR_KVNO_NOT_FOUND;
1281           goto out;
1282     } else if (ret == HDB_ERR_NO_MKEY) {
1283           char *p;
1284           ret = krb5_unparse_name(context, princ, &p);
1285           if (ret != 0)
1286               p = failed;
1287           krb5_free_principal(context, princ);
1288           kdc_log(context, config, 5,
1289                     "Missing master key for decrypting keys for ticket-granting "
1290                     "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1291           if (ret == 0)
1292               free(p);
1293           ret = HDB_ERR_KVNO_NOT_FOUND;
1294           goto out;
1295     } else if (ret) {
1296           const char *msg = krb5_get_error_message(context, ret);
1297           char *p;
1298           ret = krb5_unparse_name(context, princ, &p);
1299           if (ret != 0)
1300               p = failed;
1301           krb5_free_principal(context, princ);
1302           kdc_log(context, config, 0,
1303                     "Ticket-granting ticket not found in database: %s", msg);
1304           krb5_free_error_message(context, msg);
1305           if (ret == 0)
1306               free(p);
1307           ret = KRB5KRB_AP_ERR_NOT_US;
1308           goto out;
1309     }
1310 
1311     krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1312     *krbtgt_etype = ap_req.ticket.enc_part.etype;
1313 
1314 next_kvno:
1315     krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
1316     ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
1317                                 ap_req.ticket.enc_part.etype, &tkey);
1318     if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1319           kvno_search_tries--;
1320           krbtgt_kvno_try--;
1321           goto next_kvno;
1322     } else if (ret) {
1323           char *str = NULL, *p = NULL;
1324 
1325           krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1326           krb5_unparse_name(context, princ, &p);
1327           kdc_log(context, config, 0,
1328                     "No server key with enctype %s found for %s",
1329                     str ? str : "<unknown enctype>",
1330                     p ? p : "<unparse_name failed>");
1331           free(str);
1332           free(p);
1333           ret = KRB5KRB_AP_ERR_BADKEYVER;
1334           goto out;
1335     }
1336 
1337     if (b->kdc_options.validate)
1338           verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1339     else
1340           verify_ap_req_flags = 0;
1341 
1342     ret = krb5_verify_ap_req2(context,
1343                                     &ac,
1344                                     &ap_req,
1345                                     princ,
1346                                     &tkey->key,
1347                                     verify_ap_req_flags,
1348                                     &ap_req_options,
1349                                     ticket,
1350                                     KRB5_KU_TGS_REQ_AUTH);
1351     if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1352           kvno_search_tries--;
1353           krbtgt_kvno_try--;
1354           goto next_kvno;
1355     }
1356 
1357     krb5_free_principal(context, princ);
1358     if(ret) {
1359           const char *msg = krb5_get_error_message(context, ret);
1360           kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1361           krb5_free_error_message(context, msg);
1362           goto out;
1363     }
1364 
1365     {
1366           krb5_authenticator auth;
1367 
1368           ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1369           if (ret == 0) {
1370               *csec   = malloc(sizeof(**csec));
1371               if (*csec == NULL) {
1372                     krb5_free_authenticator(context, &auth);
1373                     kdc_log(context, config, 0, "malloc failed");
1374                     goto out;
1375               }
1376               **csec  = auth->ctime;
1377               *cusec  = malloc(sizeof(**cusec));
1378               if (*cusec == NULL) {
1379                     krb5_free_authenticator(context, &auth);
1380                     kdc_log(context, config, 0, "malloc failed");
1381                     goto out;
1382               }
1383               **cusec  = auth->cusec;
1384               krb5_free_authenticator(context, &auth);
1385           }
1386     }
1387 
1388     ret = tgs_check_authenticator(context, config,
1389                                           ac, b, e_text, &(*ticket)->ticket.key);
1390     if (ret) {
1391           krb5_auth_con_free(context, ac);
1392           goto out;
1393     }
1394 
1395     usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1396     *rk_is_subkey = 1;
1397 
1398     ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1399     if(ret){
1400           const char *msg = krb5_get_error_message(context, ret);
1401           krb5_auth_con_free(context, ac);
1402           kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1403           krb5_free_error_message(context, msg);
1404           goto out;
1405     }
1406     if(subkey == NULL){
1407           usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1408           *rk_is_subkey = 0;
1409 
1410           ret = krb5_auth_con_getkey(context, ac, &subkey);
1411           if(ret) {
1412               const char *msg = krb5_get_error_message(context, ret);
1413               krb5_auth_con_free(context, ac);
1414               kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1415               krb5_free_error_message(context, msg);
1416               goto out;
1417           }
1418     }
1419     if(subkey == NULL){
1420           krb5_auth_con_free(context, ac);
1421           kdc_log(context, config, 0,
1422                     "Failed to get key for enc-authorization-data");
1423           ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1424           goto out;
1425     }
1426 
1427     *replykey = subkey;
1428 
1429     if (b->enc_authorization_data) {
1430           krb5_data ad;
1431 
1432           ret = krb5_crypto_init(context, subkey, 0, &crypto);
1433           if (ret) {
1434               const char *msg = krb5_get_error_message(context, ret);
1435               krb5_auth_con_free(context, ac);
1436               kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1437               krb5_free_error_message(context, msg);
1438               goto out;
1439           }
1440           ret = krb5_decrypt_EncryptedData (context,
1441                                                     crypto,
1442                                                     usage,
1443                                                     b->enc_authorization_data,
1444                                                     &ad);
1445           krb5_crypto_destroy(context, crypto);
1446           if(ret){
1447               krb5_auth_con_free(context, ac);
1448               kdc_log(context, config, 0,
1449                         "Failed to decrypt enc-authorization-data");
1450               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1451               goto out;
1452           }
1453           ALLOC(*auth_data);
1454           if (*auth_data == NULL) {
1455               krb5_auth_con_free(context, ac);
1456               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1457               goto out;
1458           }
1459           ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1460           if(ret){
1461               krb5_auth_con_free(context, ac);
1462               free(*auth_data);
1463               *auth_data = NULL;
1464               kdc_log(context, config, 0, "Failed to decode authorization data");
1465               ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1466               goto out;
1467           }
1468     }
1469 
1470     krb5_auth_con_free(context, ac);
1471 
1472 out:
1473     free_AP_REQ(&ap_req);
1474 
1475     return ret;
1476 }
1477 
1478 static krb5_error_code
build_server_referral(krb5_context context,krb5_kdc_configuration * config,krb5_crypto session,krb5_const_realm referred_realm,const PrincipalName * true_principal_name,const PrincipalName * requested_principal,krb5_data * outdata)1479 build_server_referral(krb5_context context,
1480                           krb5_kdc_configuration *config,
1481                           krb5_crypto session,
1482                           krb5_const_realm referred_realm,
1483                           const PrincipalName *true_principal_name,
1484                           const PrincipalName *requested_principal,
1485                           krb5_data *outdata)
1486 {
1487     PA_ServerReferralData ref;
1488     krb5_error_code ret;
1489     EncryptedData ed;
1490     krb5_data data;
1491     size_t size = 0;
1492 
1493     memset(&ref, 0, sizeof(ref));
1494 
1495     if (referred_realm) {
1496           ALLOC(ref.referred_realm);
1497           if (ref.referred_realm == NULL)
1498               goto eout;
1499           *ref.referred_realm = strdup(referred_realm);
1500           if (*ref.referred_realm == NULL)
1501               goto eout;
1502     }
1503     if (true_principal_name) {
1504           ALLOC(ref.true_principal_name);
1505           if (ref.true_principal_name == NULL)
1506               goto eout;
1507           ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1508           if (ret)
1509               goto eout;
1510     }
1511     if (requested_principal) {
1512           ALLOC(ref.requested_principal_name);
1513           if (ref.requested_principal_name == NULL)
1514               goto eout;
1515           ret = copy_PrincipalName(requested_principal,
1516                                          ref.requested_principal_name);
1517           if (ret)
1518               goto eout;
1519     }
1520 
1521     ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1522                            data.data, data.length,
1523                            &ref, &size, ret);
1524     free_PA_ServerReferralData(&ref);
1525     if (ret)
1526           return ret;
1527     if (data.length != size)
1528           krb5_abortx(context, "internal asn.1 encoder error");
1529 
1530     ret = krb5_encrypt_EncryptedData(context, session,
1531                                              KRB5_KU_PA_SERVER_REFERRAL,
1532                                              data.data, data.length,
1533                                              0 /* kvno */, &ed);
1534     free(data.data);
1535     if (ret)
1536           return ret;
1537 
1538     ASN1_MALLOC_ENCODE(EncryptedData,
1539                            outdata->data, outdata->length,
1540                            &ed, &size, ret);
1541     free_EncryptedData(&ed);
1542     if (ret)
1543           return ret;
1544     if (outdata->length != size)
1545           krb5_abortx(context, "internal asn.1 encoder error");
1546 
1547     return 0;
1548 eout:
1549     free_PA_ServerReferralData(&ref);
1550     krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1551     return ENOMEM;
1552 }
1553 
1554 static krb5_error_code
tgs_build_reply(krb5_context context,krb5_kdc_configuration * config,KDC_REQ * req,KDC_REQ_BODY * b,hdb_entry_ex * krbtgt,krb5_enctype krbtgt_etype,const krb5_keyblock * replykey,int rk_is_subkey,krb5_ticket * ticket,krb5_data * reply,const char * from,const char ** e_text,AuthorizationData ** auth_data,const struct sockaddr * from_addr)1555 tgs_build_reply(krb5_context context,
1556                     krb5_kdc_configuration *config,
1557                     KDC_REQ *req,
1558                     KDC_REQ_BODY *b,
1559                     hdb_entry_ex *krbtgt,
1560                     krb5_enctype krbtgt_etype,
1561                     const krb5_keyblock *replykey,
1562                     int rk_is_subkey,
1563                     krb5_ticket *ticket,
1564                     krb5_data *reply,
1565                     const char *from,
1566                     const char **e_text,
1567                     AuthorizationData **auth_data,
1568                     const struct sockaddr *from_addr)
1569 {
1570     krb5_error_code ret, ret2;
1571     krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1572     krb5_principal krbtgt_out_principal = NULL;
1573     char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1574     hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1575     HDB *clientdb, *s4u2self_impersonated_clientdb;
1576     krb5_realm ref_realm = NULL;
1577     EncTicketPart *tgt = &ticket->ticket;
1578     krb5_principals spp = NULL;
1579     const EncryptionKey *ekey;
1580     krb5_keyblock sessionkey;
1581     krb5_kvno kvno;
1582     krb5_data rspac;
1583     const char *tgt_realm = /* Realm of TGT issuer */
1584         krb5_principal_get_realm(context, krbtgt->entry.principal);
1585     const char *our_realm = /* Realm of this KDC */
1586         krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1587     char **capath = NULL;
1588     size_t num_capath = 0;
1589 
1590     hdb_entry_ex *krbtgt_out = NULL;
1591 
1592     METHOD_DATA enc_pa_data;
1593 
1594     PrincipalName *s;
1595     Realm r;
1596     EncTicketPart adtkt;
1597     char opt_str[128];
1598     int signedpath = 0;
1599 
1600     Key *tkey_check;
1601     Key *tkey_sign;
1602     int flags = HDB_F_FOR_TGS_REQ;
1603 
1604     memset(&sessionkey, 0, sizeof(sessionkey));
1605     memset(&adtkt, 0, sizeof(adtkt));
1606     krb5_data_zero(&rspac);
1607     memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1608 
1609     s = b->sname;
1610     r = b->realm;
1611 
1612     /*
1613      * Always to do CANON, see comment below about returned server principal (rsp).
1614      */
1615     flags |= HDB_F_CANON;
1616 
1617     if(b->kdc_options.enc_tkt_in_skey){
1618           Ticket *t;
1619           hdb_entry_ex *uu;
1620           krb5_principal p;
1621           Key *uukey;
1622           krb5uint32 second_kvno = 0;
1623           krb5uint32 *kvno_ptr = NULL;
1624 
1625           if(b->additional_tickets == NULL ||
1626              b->additional_tickets->len == 0){
1627               ret = KRB5KDC_ERR_BADOPTION; /* ? */
1628               kdc_log(context, config, 0,
1629                         "No second ticket present in request");
1630               goto out;
1631           }
1632           t = &b->additional_tickets->val[0];
1633           if(!get_krbtgt_realm(&t->sname)){
1634               kdc_log(context, config, 0,
1635                         "Additional ticket is not a ticket-granting ticket");
1636               ret = KRB5KDC_ERR_POLICY;
1637               goto out;
1638           }
1639           _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1640           if(t->enc_part.kvno){
1641               second_kvno = *t->enc_part.kvno;
1642               kvno_ptr = &second_kvno;
1643           }
1644           ret = _kdc_db_fetch(context, config, p,
1645                                   HDB_F_GET_KRBTGT, kvno_ptr,
1646                                   NULL, &uu);
1647           krb5_free_principal(context, p);
1648           if(ret){
1649               if (ret == HDB_ERR_NOENTRY)
1650                     ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1651               goto out;
1652           }
1653           ret = hdb_enctype2key(context, &uu->entry, NULL,
1654                                     t->enc_part.etype, &uukey);
1655           if(ret){
1656               _kdc_free_ent(context, uu);
1657               ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1658               goto out;
1659           }
1660           ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1661           _kdc_free_ent(context, uu);
1662           if(ret)
1663               goto out;
1664 
1665           ret = verify_flags(context, config, &adtkt, spn);
1666           if (ret)
1667               goto out;
1668 
1669           s = &adtkt.cname;
1670           r = adtkt.crealm;
1671     } else if (s == NULL) {
1672           ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1673           kdc_log(context, config, 0, "No server in request");
1674           goto out;
1675     }
1676 
1677     _krb5_principalname2krb5_principal(context, &sp, *s, r);
1678     ret = krb5_unparse_name(context, sp, &spn);
1679     if (ret)
1680           goto out;
1681     _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1682     ret = krb5_unparse_name(context, cp, &cpn);
1683     if (ret)
1684           goto out;
1685     unparse_flags (KDCOptions2int(b->kdc_options),
1686                        asn1_KDCOptions_units(),
1687                        opt_str, sizeof(opt_str));
1688     if(*opt_str)
1689           kdc_log(context, config, 0,
1690                     "TGS-REQ %s from %s for %s [%s]",
1691                     cpn, from, spn, opt_str);
1692     else
1693           kdc_log(context, config, 0,
1694                     "TGS-REQ %s from %s for %s", cpn, from, spn);
1695 
1696     /*
1697      * Fetch server
1698      */
1699 
1700 server_lookup:
1701     ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1702                               NULL, NULL, &server);
1703 
1704     if (ret == HDB_ERR_NOT_FOUND_HERE) {
1705           kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1706           goto out;
1707     } else if (ret == HDB_ERR_WRONG_REALM) {
1708         free(ref_realm);
1709           ref_realm = strdup(server->entry.principal->realm);
1710           if (ref_realm == NULL) {
1711             ret = krb5_enomem(context);
1712               goto out;
1713           }
1714 
1715           kdc_log(context, config, 5,
1716                     "Returning a referral to realm %s for "
1717                     "server %s.",
1718                     ref_realm, spn);
1719           krb5_free_principal(context, sp);
1720           sp = NULL;
1721           ret = krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1722                                           ref_realm, NULL);
1723           if (ret)
1724               goto out;
1725           free(spn);
1726         spn = NULL;
1727           ret = krb5_unparse_name(context, sp, &spn);
1728           if (ret)
1729               goto out;
1730 
1731           goto server_lookup;
1732     } else if (ret) {
1733           const char *new_rlm, *msg;
1734           Realm req_rlm;
1735           krb5_realm *realms;
1736 
1737           if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1738             if (capath == NULL) {
1739                 /* With referalls, hierarchical capaths are always enabled */
1740                 ret2 = _krb5_find_capath(context, tgt->crealm, our_realm,
1741                                          req_rlm, TRUE, &capath, &num_capath);
1742                 if (ret2) {
1743                     ret = ret2;
1744                     goto out;
1745                 }
1746             }
1747             new_rlm = num_capath > 0 ? capath[--num_capath] : NULL;
1748             if (new_rlm) {
1749                 kdc_log(context, config, 5, "krbtgt from %s via %s for "
1750                         "realm %s not found, trying %s", tgt->crealm,
1751                         our_realm, req_rlm, new_rlm);
1752 
1753                 free(ref_realm);
1754                 ref_realm = strdup(new_rlm);
1755                 if (ref_realm == NULL) {
1756                     ret = krb5_enomem(context);
1757                     goto out;
1758                 }
1759 
1760                 krb5_free_principal(context, sp);
1761                 sp = NULL;
1762                 krb5_make_principal(context, &sp, r,
1763                                     KRB5_TGS_NAME, ref_realm, NULL);
1764                 free(spn);
1765                 spn = NULL;
1766                 ret = krb5_unparse_name(context, sp, &spn);
1767                 if (ret)
1768                     goto out;
1769                 goto server_lookup;
1770             }
1771           } else if (need_referral(context, config, &b->kdc_options, sp, &realms)) {
1772               if (strcmp(realms[0], sp->realm) != 0) {
1773                     kdc_log(context, config, 5,
1774                               "Returning a referral to realm %s for "
1775                               "server %s that was not found",
1776                               realms[0], spn);
1777                     krb5_free_principal(context, sp);
1778                 sp = NULL;
1779                     krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1780                                             realms[0], NULL);
1781                     free(spn);
1782                 spn = NULL;
1783                     ret = krb5_unparse_name(context, sp, &spn);
1784                     if (ret) {
1785                         krb5_free_host_realm(context, realms);
1786                         goto out;
1787                     }
1788 
1789                 free(ref_realm);
1790                     ref_realm = strdup(realms[0]);
1791 
1792                     krb5_free_host_realm(context, realms);
1793                     goto server_lookup;
1794               }
1795               krb5_free_host_realm(context, realms);
1796           }
1797           msg = krb5_get_error_message(context, ret);
1798           kdc_log(context, config, 0,
1799                     "Server not found in database: %s: %s", spn, msg);
1800           krb5_free_error_message(context, msg);
1801           if (ret == HDB_ERR_NOENTRY)
1802               ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1803           goto out;
1804     }
1805 
1806     /* the name returned to the client depend on what was asked for,
1807      * return canonical name if kdc_options.canonicalize was set, the
1808      * client wants the true name of the principal, if not it just
1809      * wants the name its asked for.
1810      */
1811 
1812     if (b->kdc_options.canonicalize)
1813           rsp = server->entry.principal;
1814     else
1815           rsp = sp;
1816 
1817 
1818     /*
1819      * Select enctype, return key and kvno.
1820      */
1821 
1822     {
1823           krb5_enctype etype;
1824 
1825           if(b->kdc_options.enc_tkt_in_skey) {
1826               size_t i;
1827               ekey = &adtkt.key;
1828               for(i = 0; i < b->etype.len; i++)
1829                     if (b->etype.val[i] == adtkt.key.keytype)
1830                         break;
1831               if(i == b->etype.len) {
1832                     kdc_log(context, config, 0,
1833                               "Addition ticket have not matching etypes");
1834                     krb5_clear_error_message(context);
1835                     ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1836                     goto out;
1837               }
1838               etype = b->etype.val[i];
1839               kvno = 0;
1840           } else {
1841               Key *skey;
1842 
1843               ret = _kdc_find_etype(context,
1844                                           krb5_principal_is_krbtgt(context, sp) ?
1845                                           config->tgt_use_strongest_session_key :
1846                                           config->svc_use_strongest_session_key, FALSE,
1847                                           server, b->etype.val, b->etype.len, &etype,
1848                                           NULL);
1849               if(ret) {
1850                     kdc_log(context, config, 0,
1851                               "Server (%s) has no support for etypes", spn);
1852                     goto out;
1853               }
1854               ret = _kdc_get_preferred_key(context, config, server, spn,
1855                                                    NULL, &skey);
1856               if(ret) {
1857                     kdc_log(context, config, 0,
1858                               "Server (%s) has no supported etypes", spn);
1859                     goto out;
1860               }
1861               ekey = &skey->key;
1862               kvno = server->entry.kvno;
1863           }
1864 
1865           ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1866           if (ret)
1867               goto out;
1868     }
1869 
1870     /*
1871      * Check that service is in the same realm as the krbtgt. If it's
1872      * not the same, it's someone that is using a uni-directional trust
1873      * backward.
1874      */
1875 
1876     /*
1877      * Validate authoriation data
1878      */
1879 
1880     ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1881                                 krbtgt_etype, &tkey_check);
1882     if(ret) {
1883           kdc_log(context, config, 0,
1884                         "Failed to find key for krbtgt PAC check");
1885           goto out;
1886     }
1887 
1888     /*
1889      * Now refetch the primary krbtgt, and get the current kvno (the
1890      * sign check may have been on an old kvno, and the server may
1891      * have been an incoming trust)
1892      */
1893 
1894     ret = krb5_make_principal(context,
1895                               &krbtgt_out_principal,
1896                               our_realm,
1897                               KRB5_TGS_NAME,
1898                               our_realm,
1899                               NULL);
1900     if (ret) {
1901         kdc_log(context, config, 0,
1902                 "Failed to make krbtgt principal name object for "
1903                 "authz-data signatures");
1904         goto out;
1905     }
1906     ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1907     if (ret) {
1908         kdc_log(context, config, 0,
1909                 "Failed to make krbtgt principal name object for "
1910                 "authz-data signatures");
1911         goto out;
1912     }
1913 
1914     ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1915                               HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1916     if (ret) {
1917           char *ktpn = NULL;
1918           ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1919           kdc_log(context, config, 0,
1920                     "No such principal %s (needed for authz-data signature keys) "
1921                     "while processing TGS-REQ for service %s with krbtg %s",
1922                     krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1923           free(ktpn);
1924           ret = KRB5KRB_AP_ERR_NOT_US;
1925           goto out;
1926     }
1927 
1928     /*
1929      * The first realm is the realm of the service, the second is
1930      * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1931      * encrypted to.  The redirection via the krbtgt_out entry allows
1932      * the DB to possibly correct the case of the realm (Samba4 does
1933      * this) before the strcmp()
1934      */
1935     if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1936                  krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1937           char *ktpn;
1938           ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1939           kdc_log(context, config, 0,
1940                     "Request with wrong krbtgt: %s",
1941                     (ret == 0) ? ktpn : "<unknown>");
1942           if(ret == 0)
1943               free(ktpn);
1944           ret = KRB5KRB_AP_ERR_NOT_US;
1945           goto out;
1946     }
1947 
1948     ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1949                                          NULL, &tkey_sign);
1950     if (ret) {
1951           kdc_log(context, config, 0,
1952                         "Failed to find key for krbtgt PAC signature");
1953           goto out;
1954     }
1955     ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1956                                 tkey_sign->key.keytype, &tkey_sign);
1957     if(ret) {
1958           kdc_log(context, config, 0,
1959                         "Failed to find key for krbtgt PAC signature");
1960           goto out;
1961     }
1962 
1963     ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1964                               NULL, &clientdb, &client);
1965     if(ret == HDB_ERR_NOT_FOUND_HERE) {
1966           /* This is OK, we are just trying to find out if they have
1967            * been disabled or deleted in the meantime, missing secrets
1968            * is OK */
1969     } else if(ret){
1970           const char *krbtgt_realm, *msg;
1971 
1972           /*
1973            * If the client belongs to the same realm as our krbtgt, it
1974            * should exist in the local database.
1975            *
1976            */
1977 
1978           krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1979 
1980           if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1981               if (ret == HDB_ERR_NOENTRY)
1982                     ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1983               kdc_log(context, config, 1, "Client no longer in database: %s",
1984                         cpn);
1985               goto out;
1986           }
1987 
1988           msg = krb5_get_error_message(context, ret);
1989           kdc_log(context, config, 1, "Client not found in database: %s", msg);
1990           krb5_free_error_message(context, msg);
1991     }
1992 
1993     ret = check_PAC(context, config, cp, NULL,
1994                         client, server, krbtgt,
1995                         &tkey_check->key,
1996                         ekey, &tkey_sign->key,
1997                         tgt, &rspac, &signedpath);
1998     if (ret) {
1999           const char *msg = krb5_get_error_message(context, ret);
2000           kdc_log(context, config, 0,
2001                     "Verify PAC failed for %s (%s) from %s with %s",
2002                     spn, cpn, from, msg);
2003           krb5_free_error_message(context, msg);
2004           goto out;
2005     }
2006 
2007     /* also check the krbtgt for signature */
2008     ret = check_KRB5SignedPath(context,
2009                                      config,
2010                                      krbtgt,
2011                                      cp,
2012                                      tgt,
2013                                      &spp,
2014                                      &signedpath);
2015     if (ret) {
2016           const char *msg = krb5_get_error_message(context, ret);
2017           kdc_log(context, config, 0,
2018                     "KRB5SignedPath check failed for %s (%s) from %s with %s",
2019                     spn, cpn, from, msg);
2020           krb5_free_error_message(context, msg);
2021           goto out;
2022     }
2023 
2024     /*
2025      * Process request
2026      */
2027 
2028     /* by default the tgt principal matches the client principal */
2029     tp = cp;
2030     tpn = cpn;
2031 
2032     if (client) {
2033           const PA_DATA *sdata;
2034           int i = 0;
2035 
2036           sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
2037           if (sdata) {
2038               krb5_crypto crypto;
2039               krb5_data datack;
2040               PA_S4U2Self self;
2041               const char *str;
2042 
2043               ret = decode_PA_S4U2Self(sdata->padata_value.data,
2044                                              sdata->padata_value.length,
2045                                              &self, NULL);
2046               if (ret) {
2047                     kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
2048                     goto out;
2049               }
2050 
2051               if (!krb5_checksum_is_keyed(context, self.cksum.cksumtype)) {
2052                     free_PA_S4U2Self(&self);
2053                     kdc_log(context, config, 0, "Reject PA-S4U2Self with unkeyed checksum");
2054                     ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
2055                     goto out;
2056               }
2057 
2058               ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
2059               if (ret)
2060                     goto out;
2061 
2062               ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
2063               if (ret) {
2064                     const char *msg = krb5_get_error_message(context, ret);
2065                     free_PA_S4U2Self(&self);
2066                     krb5_data_free(&datack);
2067                     kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
2068                     krb5_free_error_message(context, msg);
2069                     goto out;
2070               }
2071 
2072               /* Allow HMAC_MD5 checksum with any key type */
2073               if (self.cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
2074                     unsigned char csdata[16];
2075                     Checksum cs;
2076 
2077                     cs.checksum.length = sizeof(csdata);
2078                     cs.checksum.data = &csdata;
2079 
2080                     ret = _krb5_HMAC_MD5_checksum(context, &crypto->key,
2081                                                         datack.data, datack.length,
2082                                                         KRB5_KU_OTHER_CKSUM, &cs);
2083                     if (ret == 0 &&
2084                         krb5_data_ct_cmp(&cs.checksum, &self.cksum.checksum) != 0)
2085                         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2086               }
2087               else {
2088                     ret = krb5_verify_checksum(context,
2089                                                      crypto,
2090                                                      KRB5_KU_OTHER_CKSUM,
2091                                                      datack.data,
2092                                                      datack.length,
2093                                                      &self.cksum);
2094               }
2095               krb5_data_free(&datack);
2096               krb5_crypto_destroy(context, crypto);
2097               if (ret) {
2098                     const char *msg = krb5_get_error_message(context, ret);
2099                     free_PA_S4U2Self(&self);
2100                     kdc_log(context, config, 0,
2101                               "krb5_verify_checksum failed for S4U2Self: %s", msg);
2102                     krb5_free_error_message(context, msg);
2103                     goto out;
2104               }
2105 
2106               ret = _krb5_principalname2krb5_principal(context,
2107                                                                  &tp,
2108                                                                  self.name,
2109                                                                  self.realm);
2110               free_PA_S4U2Self(&self);
2111               if (ret)
2112                     goto out;
2113 
2114               ret = krb5_unparse_name(context, tp, &tpn);
2115               if (ret)
2116                     goto out;
2117 
2118               ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2119                                         NULL, &s4u2self_impersonated_clientdb,
2120                                         &s4u2self_impersonated_client);
2121               if (ret) {
2122                     const char *msg;
2123 
2124                     /*
2125                      * If the client belongs to the same realm as our krbtgt, it
2126                      * should exist in the local database.
2127                      *
2128                      */
2129 
2130                     if (ret == HDB_ERR_NOENTRY)
2131                         ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2132                     msg = krb5_get_error_message(context, ret);
2133                     kdc_log(context, config, 2,
2134                               "S4U2Self principal to impersonate %s not found in database: %s",
2135                               tpn, msg);
2136                     krb5_free_error_message(context, msg);
2137                     goto out;
2138               }
2139 
2140               /* Ignore require_pwchange and pw_end attributes (as Windows does),
2141                * since S4U2Self is not password authentication. */
2142               s4u2self_impersonated_client->entry.flags.require_pwchange = FALSE;
2143               free(s4u2self_impersonated_client->entry.pw_end);
2144               s4u2self_impersonated_client->entry.pw_end = NULL;
2145 
2146               ret = kdc_check_flags(context, config, s4u2self_impersonated_client, tpn,
2147                                           NULL, NULL, FALSE);
2148               if (ret)
2149                     goto out;
2150 
2151               /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2152               if(rspac.data) {
2153                     krb5_pac p = NULL;
2154                     krb5_data_free(&rspac);
2155                     ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2156                     if (ret) {
2157                         kdc_log(context, config, 0, "PAC generation failed for -- %s",
2158                                   tpn);
2159                         goto out;
2160                     }
2161                     if (p != NULL) {
2162                         ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2163                                                    s4u2self_impersonated_client->entry.principal,
2164                                                    ekey, &tkey_sign->key,
2165                                                    &rspac);
2166                         krb5_pac_free(context, p);
2167                         if (ret) {
2168                               kdc_log(context, config, 0, "PAC signing failed for -- %s",
2169                                         tpn);
2170                               goto out;
2171                         }
2172                     }
2173               }
2174 
2175               /*
2176                * Check that service doing the impersonating is
2177                * requesting a ticket to it-self.
2178                */
2179               ret = check_s4u2self(context, config, clientdb, client, sp);
2180               if (ret) {
2181                     kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2182                               "to impersonate to service "
2183                               "(tried for user %s to service %s)",
2184                               cpn, tpn, spn);
2185                     goto out;
2186               }
2187 
2188               /*
2189                * If the service isn't trusted for authentication to
2190                * delegation or if the impersonate client is disallowed
2191                * forwardable, remove the forwardable flag.
2192                */
2193 
2194               if (client->entry.flags.trusted_for_delegation &&
2195                     s4u2self_impersonated_client->entry.flags.forwardable) {
2196                     str = "[forwardable]";
2197               } else {
2198                     b->kdc_options.forwardable = 0;
2199                     str = "";
2200               }
2201               kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2202                         "service %s %s", cpn, tpn, spn, str);
2203           }
2204     }
2205 
2206     /*
2207      * Constrained delegation
2208      */
2209 
2210     if (client != NULL
2211           && b->additional_tickets != NULL
2212           && b->additional_tickets->len != 0
2213           && b->kdc_options.cname_in_addl_tkt
2214           && b->kdc_options.enc_tkt_in_skey == 0)
2215     {
2216           int ad_signedpath = 0;
2217           Key *clientkey;
2218           Ticket *t;
2219 
2220           /*
2221            * Require that the KDC have issued the service's krbtgt (not
2222            * self-issued ticket with kimpersonate(1).
2223            */
2224           if (!signedpath) {
2225               ret = KRB5KDC_ERR_BADOPTION;
2226               kdc_log(context, config, 0,
2227                         "Constrained delegation done on service ticket %s/%s",
2228                         cpn, spn);
2229               goto out;
2230           }
2231 
2232           t = &b->additional_tickets->val[0];
2233 
2234           ret = hdb_enctype2key(context, &client->entry,
2235                                     hdb_kvno2keys(context, &client->entry,
2236                                                       t->enc_part.kvno ? * t->enc_part.kvno : 0),
2237                                     t->enc_part.etype, &clientkey);
2238           if(ret){
2239               ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2240               goto out;
2241           }
2242 
2243           ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2244           if (ret) {
2245               kdc_log(context, config, 0,
2246                         "failed to decrypt ticket for "
2247                         "constrained delegation from %s to %s ", cpn, spn);
2248               goto out;
2249           }
2250 
2251           ret = _krb5_principalname2krb5_principal(context,
2252                                                              &tp,
2253                                                              adtkt.cname,
2254                                                              adtkt.crealm);
2255           if (ret)
2256               goto out;
2257 
2258           ret = krb5_unparse_name(context, tp, &tpn);
2259           if (ret)
2260               goto out;
2261 
2262           ret = _krb5_principalname2krb5_principal(context,
2263                                                              &dp,
2264                                                              t->sname,
2265                                                              t->realm);
2266           if (ret)
2267               goto out;
2268 
2269           ret = krb5_unparse_name(context, dp, &dpn);
2270           if (ret)
2271               goto out;
2272 
2273           /* check that ticket is valid */
2274           if (adtkt.flags.forwardable == 0) {
2275               kdc_log(context, config, 0,
2276                         "Missing forwardable flag on ticket for "
2277                         "constrained delegation from %s (%s) as %s to %s ",
2278                         cpn, dpn, tpn, spn);
2279               ret = KRB5KDC_ERR_BADOPTION;
2280               goto out;
2281           }
2282 
2283           ret = check_constrained_delegation(context, config, clientdb,
2284                                                      client, server, sp);
2285           if (ret) {
2286               kdc_log(context, config, 0,
2287                         "constrained delegation from %s (%s) as %s to %s not allowed",
2288                         cpn, dpn, tpn, spn);
2289               goto out;
2290           }
2291 
2292           ret = verify_flags(context, config, &adtkt, tpn);
2293           if (ret) {
2294               goto out;
2295           }
2296 
2297           krb5_data_free(&rspac);
2298 
2299           /*
2300            * generate the PAC for the user.
2301            *
2302            * TODO: pass in t->sname and t->realm and build
2303            * a S4U_DELEGATION_INFO blob to the PAC.
2304            */
2305           ret = check_PAC(context, config, tp, dp,
2306                               client, server, krbtgt,
2307                               &clientkey->key,
2308                               ekey, &tkey_sign->key,
2309                               &adtkt, &rspac, &ad_signedpath);
2310           if (ret) {
2311               const char *msg = krb5_get_error_message(context, ret);
2312               kdc_log(context, config, 0,
2313                         "Verify delegated PAC failed to %s for client"
2314                         "%s (%s) as %s from %s with %s",
2315                         spn, cpn, dpn, tpn, from, msg);
2316               krb5_free_error_message(context, msg);
2317               goto out;
2318           }
2319 
2320           /*
2321            * Check that the KDC issued the user's ticket.
2322            */
2323           ret = check_KRB5SignedPath(context,
2324                                            config,
2325                                            krbtgt,
2326                                            cp,
2327                                            &adtkt,
2328                                            NULL,
2329                                            &ad_signedpath);
2330           if (ret) {
2331               const char *msg = krb5_get_error_message(context, ret);
2332               kdc_log(context, config, 0,
2333                         "KRB5SignedPath check from service %s failed "
2334                         "for delegation to %s for client %s (%s)"
2335                         "from %s failed with %s",
2336                         spn, tpn, dpn, cpn, from, msg);
2337               krb5_free_error_message(context, msg);
2338               goto out;
2339           }
2340 
2341           if (!ad_signedpath) {
2342               ret = KRB5KDC_ERR_BADOPTION;
2343               kdc_log(context, config, 0,
2344                         "Ticket not signed with PAC nor SignedPath service %s failed "
2345                         "for delegation to %s for client %s (%s)"
2346                         "from %s",
2347                         spn, tpn, dpn, cpn, from);
2348               goto out;
2349           }
2350 
2351           kdc_log(context, config, 0, "constrained delegation for %s "
2352                     "from %s (%s) to %s", tpn, cpn, dpn, spn);
2353     }
2354 
2355     /*
2356      * Check flags
2357      */
2358 
2359     ret = kdc_check_flags(context, config,
2360                                 client, cpn,
2361                                 server, spn,
2362                                 FALSE);
2363     if(ret)
2364           goto out;
2365 
2366     if((b->kdc_options.validate || b->kdc_options.renew) &&
2367        !krb5_principal_compare(context,
2368                                      krbtgt->entry.principal,
2369                                      server->entry.principal)){
2370           kdc_log(context, config, 0, "Inconsistent request.");
2371           ret = KRB5KDC_ERR_SERVER_NOMATCH;
2372           goto out;
2373     }
2374 
2375     /* check for valid set of addresses */
2376     if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2377           ret = KRB5KRB_AP_ERR_BADADDR;
2378           kdc_log(context, config, 0, "Request from wrong address");
2379           goto out;
2380     }
2381 
2382     /* check local and per-principal anonymous ticket issuance policy */
2383     if (is_anon_tgs_request_p(b, tgt)) {
2384           ret = _kdc_check_anon_policy(context, config, client, server);
2385           if (ret)
2386               goto out;
2387     }
2388 
2389     /*
2390      * If this is an referral, add server referral data to the
2391      * auth_data reply .
2392      */
2393     if (ref_realm) {
2394           PA_DATA pa;
2395           krb5_crypto crypto;
2396 
2397           kdc_log(context, config, 0,
2398                     "Adding server referral to %s", ref_realm);
2399 
2400           ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2401           if (ret)
2402               goto out;
2403 
2404           ret = build_server_referral(context, config, crypto, ref_realm,
2405                                             NULL, s, &pa.padata_value);
2406           krb5_crypto_destroy(context, crypto);
2407           if (ret) {
2408               kdc_log(context, config, 0,
2409                         "Failed building server referral");
2410               goto out;
2411           }
2412           pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2413 
2414           ret = add_METHOD_DATA(&enc_pa_data, &pa);
2415           krb5_data_free(&pa.padata_value);
2416           if (ret) {
2417               kdc_log(context, config, 0,
2418                         "Add server referral METHOD-DATA failed");
2419               goto out;
2420           }
2421     }
2422 
2423     /*
2424      *
2425      */
2426 
2427     ret = tgs_make_reply(context,
2428                                config,
2429                                b,
2430                                tp,
2431                                tgt,
2432                                replykey,
2433                                rk_is_subkey,
2434                                ekey,
2435                                &sessionkey,
2436                                kvno,
2437                                *auth_data,
2438                                server,
2439                                rsp,
2440                                spn,
2441                                client,
2442                                cp,
2443                          tgt_realm,
2444                                krbtgt_out,
2445                                tkey_sign->key.keytype,
2446                                spp,
2447                                &rspac,
2448                                &enc_pa_data,
2449                                e_text,
2450                                reply);
2451 
2452 out:
2453     if (tpn != cpn)
2454               free(tpn);
2455     free(spn);
2456     free(cpn);
2457     free(dpn);
2458     free(krbtgt_out_n);
2459     _krb5_free_capath(context, capath);
2460 
2461     krb5_data_free(&rspac);
2462     krb5_free_keyblock_contents(context, &sessionkey);
2463     if(krbtgt_out)
2464           _kdc_free_ent(context, krbtgt_out);
2465     if(server)
2466           _kdc_free_ent(context, server);
2467     if(client)
2468           _kdc_free_ent(context, client);
2469     if(s4u2self_impersonated_client)
2470           _kdc_free_ent(context, s4u2self_impersonated_client);
2471 
2472     if (tp && tp != cp)
2473           krb5_free_principal(context, tp);
2474     krb5_free_principal(context, cp);
2475     krb5_free_principal(context, dp);
2476     krb5_free_principal(context, sp);
2477     krb5_free_principal(context, krbtgt_out_principal);
2478     free(ref_realm);
2479     free_METHOD_DATA(&enc_pa_data);
2480 
2481     free_EncTicketPart(&adtkt);
2482 
2483     return ret;
2484 }
2485 
2486 /*
2487  *
2488  */
2489 
2490 krb5_error_code
_kdc_tgs_rep(krb5_context context,krb5_kdc_configuration * config,KDC_REQ * req,krb5_data * data,const char * from,struct sockaddr * from_addr,int datagram_reply)2491 _kdc_tgs_rep(krb5_context context,
2492                krb5_kdc_configuration *config,
2493                KDC_REQ *req,
2494                krb5_data *data,
2495                const char *from,
2496                struct sockaddr *from_addr,
2497                int datagram_reply)
2498 {
2499     AuthorizationData *auth_data = NULL;
2500     krb5_error_code ret;
2501     int i = 0;
2502     const PA_DATA *tgs_req;
2503 
2504     hdb_entry_ex *krbtgt = NULL;
2505     krb5_ticket *ticket = NULL;
2506     const char *e_text = NULL;
2507     krb5_enctype krbtgt_etype = ETYPE_NULL;
2508 
2509     krb5_keyblock *replykey = NULL;
2510     int rk_is_subkey = 0;
2511     time_t *csec = NULL;
2512     int *cusec = NULL;
2513 
2514     if(req->padata == NULL){
2515           ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2516           kdc_log(context, config, 0,
2517                     "TGS-REQ from %s without PA-DATA", from);
2518           goto out;
2519     }
2520 
2521     tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2522 
2523     if(tgs_req == NULL){
2524           ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2525 
2526           kdc_log(context, config, 0,
2527                     "TGS-REQ from %s without PA-TGS-REQ", from);
2528           goto out;
2529     }
2530     ret = tgs_parse_request(context, config,
2531                                   &req->req_body, tgs_req,
2532                                   &krbtgt,
2533                                   &krbtgt_etype,
2534                                   &ticket,
2535                                   &e_text,
2536                                   from, from_addr,
2537                                   &csec, &cusec,
2538                                   &auth_data,
2539                                   &replykey,
2540                                   &rk_is_subkey);
2541     if (ret == HDB_ERR_NOT_FOUND_HERE) {
2542           /* kdc_log() is called in tgs_parse_request() */
2543           goto out;
2544     }
2545     if (ret) {
2546           kdc_log(context, config, 0,
2547                     "Failed parsing TGS-REQ from %s", from);
2548           goto out;
2549     }
2550 
2551     {
2552           const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2553           if (pa)
2554               kdc_log(context, config, 10, "Got TGS FAST request");
2555     }
2556 
2557 
2558     ret = tgs_build_reply(context,
2559                                 config,
2560                                 req,
2561                                 &req->req_body,
2562                                 krbtgt,
2563                                 krbtgt_etype,
2564                                 replykey,
2565                                 rk_is_subkey,
2566                                 ticket,
2567                                 data,
2568                                 from,
2569                                 &e_text,
2570                                 &auth_data,
2571                                 from_addr);
2572     if (ret) {
2573           kdc_log(context, config, 0,
2574                     "Failed building TGS-REP to %s", from);
2575           goto out;
2576     }
2577 
2578     /* */
2579     if (datagram_reply && data->length > config->max_datagram_reply_length) {
2580           krb5_data_free(data);
2581           ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2582           e_text = "Reply packet too large";
2583     }
2584 
2585 out:
2586     if (replykey)
2587           krb5_free_keyblock(context, replykey);
2588 
2589     if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2590           /* XXX add fast wrapping on the error */
2591           METHOD_DATA error_method = { 0, NULL };
2592 
2593 
2594           kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2595           ret = _kdc_fast_mk_error(context, NULL,
2596                                          &error_method,
2597                                          NULL,
2598                                          NULL,
2599                                          ret, NULL,
2600                                          NULL,
2601                                          NULL, NULL,
2602                                          csec, cusec,
2603                                          data);
2604           free_METHOD_DATA(&error_method);
2605     }
2606     free(csec);
2607     free(cusec);
2608     if (ticket)
2609           krb5_free_ticket(context, ticket);
2610     if(krbtgt)
2611           _kdc_free_ent(context, krbtgt);
2612 
2613     if (auth_data) {
2614           free_AuthorizationData(auth_data);
2615           free(auth_data);
2616     }
2617 
2618     return ret;
2619 }
2620