Remove building with NOCRYPTO option
[minix.git] / crypto / external / bsd / heimdal / dist / kdc / krb5tgs.c
blob71a04f1bed58c9870c4f2c9a77ce37fc7f469efb
1 /* $NetBSD: krb5tgs.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $ */
3 /*
4 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
36 #include "kdc_locl.h"
39 * return the realm of a krbtgt-ticket or NULL
42 static Realm
43 get_krbtgt_realm(const PrincipalName *p)
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;
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.
57 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58 * entry of type KRB5SignedPath.
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context,
63 const AuthorizationData *ad,
64 krb5_data *data)
66 AuthorizationData child;
67 krb5_error_code ret;
68 int pos;
70 if (ad == NULL || ad->len == 0)
71 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
73 pos = ad->len - 1;
75 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
76 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
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;
88 if (child.len != 1) {
89 free_AuthorizationData(&child);
90 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
93 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
94 free_AuthorizationData(&child);
95 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
98 if (data)
99 ret = der_copy_octet_string(&child.val[0].ad_data, data);
100 free_AuthorizationData(&child);
101 return ret;
104 krb5_error_code
105 _kdc_add_KRB5SignedPath(krb5_context context,
106 krb5_kdc_configuration *config,
107 hdb_entry_ex *krbtgt,
108 krb5_enctype enctype,
109 krb5_principal client,
110 krb5_const_principal server,
111 krb5_principals principals,
112 EncTicketPart *tkt)
114 krb5_error_code ret;
115 KRB5SignedPath sp;
116 krb5_data data;
117 krb5_crypto crypto = NULL;
118 size_t size = 0;
120 if (server && principals) {
121 ret = add_Principals(principals, server);
122 if (ret)
123 return ret;
127 KRB5SignedPathData spd;
129 spd.client = client;
130 spd.authtime = tkt->authtime;
131 spd.delegated = principals;
132 spd.method_data = NULL;
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");
143 Key *key;
144 ret = hdb_enctype2key(context, &krbtgt->entry, enctype, &key);
145 if (ret == 0)
146 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
147 if (ret) {
148 free(data.data);
149 return ret;
154 * Fill in KRB5SignedPath
157 sp.etype = enctype;
158 sp.delegated = principals;
159 sp.method_data = NULL;
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;
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");
177 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178 * authorization data field.
181 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
182 KRB5_AUTHDATA_SIGNTICKET, &data);
183 krb5_data_free(&data);
185 return ret;
188 static krb5_error_code
189 check_KRB5SignedPath(krb5_context context,
190 krb5_kdc_configuration *config,
191 hdb_entry_ex *krbtgt,
192 krb5_principal cp,
193 EncTicketPart *tkt,
194 krb5_principals *delegated,
195 int *signedpath)
197 krb5_error_code ret;
198 krb5_data data;
199 krb5_crypto crypto = NULL;
201 if (delegated)
202 *delegated = NULL;
204 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
205 if (ret == 0) {
206 KRB5SignedPathData spd;
207 KRB5SignedPath sp;
208 size_t size = 0;
210 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
211 krb5_data_free(&data);
212 if (ret)
213 return ret;
215 spd.client = cp;
216 spd.authtime = tkt->authtime;
217 spd.delegated = sp.delegated;
218 spd.method_data = sp.method_data;
220 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
221 &spd, &size, ret);
222 if (ret) {
223 free_KRB5SignedPath(&sp);
224 return ret;
226 if (data.length != size)
227 krb5_abortx(context, "internal asn.1 encoder error");
230 Key *key;
231 ret = hdb_enctype2key(context, &krbtgt->entry, sp.etype, &key);
232 if (ret == 0)
233 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
234 if (ret) {
235 free(data.data);
236 free_KRB5SignedPath(&sp);
237 return ret;
240 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
241 data.data, data.length,
242 &sp.cksum);
243 krb5_crypto_destroy(context, crypto);
244 free(data.data);
245 if (ret) {
246 free_KRB5SignedPath(&sp);
247 kdc_log(context, config, 5,
248 "KRB5SignedPath not signed correctly, not marking as signed");
249 return 0;
252 if (delegated && sp.delegated) {
254 *delegated = malloc(sizeof(*sp.delegated));
255 if (*delegated == NULL) {
256 free_KRB5SignedPath(&sp);
257 return ENOMEM;
260 ret = copy_Principals(*delegated, sp.delegated);
261 if (ret) {
262 free_KRB5SignedPath(&sp);
263 free(*delegated);
264 *delegated = NULL;
265 return ret;
268 free_KRB5SignedPath(&sp);
270 *signedpath = 1;
273 return 0;
280 static krb5_error_code
281 check_PAC(krb5_context context,
282 krb5_kdc_configuration *config,
283 const krb5_principal client_principal,
284 const krb5_principal delegated_proxy_principal,
285 hdb_entry_ex *client,
286 hdb_entry_ex *server,
287 hdb_entry_ex *krbtgt,
288 const EncryptionKey *server_check_key,
289 const EncryptionKey *krbtgt_check_key,
290 const EncryptionKey *server_sign_key,
291 const EncryptionKey *krbtgt_sign_key,
292 EncTicketPart *tkt,
293 krb5_data *rspac,
294 int *signedpath)
296 AuthorizationData *ad = tkt->authorization_data;
297 unsigned i, j;
298 krb5_error_code ret;
300 if (ad == NULL || ad->len == 0)
301 return 0;
303 for (i = 0; i < ad->len; i++) {
304 AuthorizationData child;
306 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
307 continue;
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;
318 for (j = 0; j < child.len; j++) {
320 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
321 int signed_pac = 0;
322 krb5_pac pac;
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;
333 ret = krb5_pac_verify(context, pac, tkt->authtime,
334 client_principal,
335 server_check_key, krbtgt_check_key);
336 if (ret) {
337 krb5_pac_free(context, pac);
338 return ret;
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;
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.
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);
361 krb5_pac_free(context, pac);
363 return ret;
366 free_AuthorizationData(&child);
368 return 0;
375 static krb5_error_code
376 check_tgs_flags(krb5_context context,
377 krb5_kdc_configuration *config,
378 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
380 KDCOptions f = b->kdc_options;
382 if(f.validate){
383 if(!tgt->flags.invalid || tgt->starttime == NULL){
384 kdc_log(context, config, 0,
385 "Bad request to validate ticket");
386 return KRB5KDC_ERR_BADOPTION;
388 if(*tgt->starttime > kdc_time){
389 kdc_log(context, config, 0,
390 "Early request to validate ticket");
391 return KRB5KRB_AP_ERR_TKT_NYV;
393 /* XXX tkt = tgt */
394 et->flags.invalid = 0;
395 }else if(tgt->flags.invalid){
396 kdc_log(context, config, 0,
397 "Ticket-granting ticket has INVALID flag set");
398 return KRB5KRB_AP_ERR_TKT_INVALID;
401 if(f.forwardable){
402 if(!tgt->flags.forwardable){
403 kdc_log(context, config, 0,
404 "Bad request for forwardable ticket");
405 return KRB5KDC_ERR_BADOPTION;
407 et->flags.forwardable = 1;
409 if(f.forwarded){
410 if(!tgt->flags.forwardable){
411 kdc_log(context, config, 0,
412 "Request to forward non-forwardable ticket");
413 return KRB5KDC_ERR_BADOPTION;
415 et->flags.forwarded = 1;
416 et->caddr = b->addresses;
418 if(tgt->flags.forwarded)
419 et->flags.forwarded = 1;
421 if(f.proxiable){
422 if(!tgt->flags.proxiable){
423 kdc_log(context, config, 0,
424 "Bad request for proxiable ticket");
425 return KRB5KDC_ERR_BADOPTION;
427 et->flags.proxiable = 1;
429 if(f.proxy){
430 if(!tgt->flags.proxiable){
431 kdc_log(context, config, 0,
432 "Request to proxy non-proxiable ticket");
433 return KRB5KDC_ERR_BADOPTION;
435 et->flags.proxy = 1;
436 et->caddr = b->addresses;
438 if(tgt->flags.proxy)
439 et->flags.proxy = 1;
441 if(f.allow_postdate){
442 if(!tgt->flags.may_postdate){
443 kdc_log(context, config, 0,
444 "Bad request for post-datable ticket");
445 return KRB5KDC_ERR_BADOPTION;
447 et->flags.may_postdate = 1;
449 if(f.postdated){
450 if(!tgt->flags.may_postdate){
451 kdc_log(context, config, 0,
452 "Bad request for postdated ticket");
453 return KRB5KDC_ERR_BADOPTION;
455 if(b->from)
456 *et->starttime = *b->from;
457 et->flags.postdated = 1;
458 et->flags.invalid = 1;
459 }else if(b->from && *b->from > kdc_time + context->max_skew){
460 kdc_log(context, config, 0, "Ticket cannot be postdated");
461 return KRB5KDC_ERR_CANNOT_POSTDATE;
464 if(f.renewable){
465 if(!tgt->flags.renewable || tgt->renew_till == NULL){
466 kdc_log(context, config, 0,
467 "Bad request for renewable ticket");
468 return KRB5KDC_ERR_BADOPTION;
470 et->flags.renewable = 1;
471 ALLOC(et->renew_till);
472 _kdc_fix_time(&b->rtime);
473 *et->renew_till = *b->rtime;
475 if(f.renew){
476 time_t old_life;
477 if(!tgt->flags.renewable || tgt->renew_till == NULL){
478 kdc_log(context, config, 0,
479 "Request to renew non-renewable ticket");
480 return KRB5KDC_ERR_BADOPTION;
482 old_life = tgt->endtime;
483 if(tgt->starttime)
484 old_life -= *tgt->starttime;
485 else
486 old_life -= tgt->authtime;
487 et->endtime = *et->starttime + old_life;
488 if (et->renew_till != NULL)
489 et->endtime = min(*et->renew_till, et->endtime);
492 #if 0
493 /* checks for excess flags */
494 if(f.request_anonymous && !config->allow_anonymous){
495 kdc_log(context, config, 0,
496 "Request for anonymous ticket");
497 return KRB5KDC_ERR_BADOPTION;
499 #endif
500 return 0;
504 * Determine if constrained delegation is allowed from this client to this server
507 static krb5_error_code
508 check_constrained_delegation(krb5_context context,
509 krb5_kdc_configuration *config,
510 HDB *clientdb,
511 hdb_entry_ex *client,
512 hdb_entry_ex *server,
513 krb5_const_principal target)
515 const HDB_Ext_Constrained_delegation_acl *acl;
516 krb5_error_code ret;
517 size_t i;
520 * constrained_delegation (S4U2Proxy) only works within
521 * the same realm. We use the already canonicalized version
522 * of the principals here, while "target" is the principal
523 * provided by the client.
525 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
526 ret = KRB5KDC_ERR_BADOPTION;
527 kdc_log(context, config, 0,
528 "Bad request for constrained delegation");
529 return ret;
532 if (clientdb->hdb_check_constrained_delegation) {
533 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
534 if (ret == 0)
535 return 0;
536 } else {
537 /* if client delegates to itself, that ok */
538 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
539 return 0;
541 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
542 if (ret) {
543 krb5_clear_error_message(context);
544 return ret;
547 if (acl) {
548 for (i = 0; i < acl->len; i++) {
549 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
550 return 0;
553 ret = KRB5KDC_ERR_BADOPTION;
555 kdc_log(context, config, 0,
556 "Bad request for constrained delegation");
557 return ret;
561 * Determine if s4u2self is allowed from this client to this server
563 * For example, regardless of the principal being impersonated, if the
564 * 'client' and 'server' are the same, then it's safe.
567 static krb5_error_code
568 check_s4u2self(krb5_context context,
569 krb5_kdc_configuration *config,
570 HDB *clientdb,
571 hdb_entry_ex *client,
572 krb5_const_principal server)
574 krb5_error_code ret;
576 /* if client does a s4u2self to itself, that ok */
577 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
578 return 0;
580 if (clientdb->hdb_check_s4u2self) {
581 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
582 if (ret == 0)
583 return 0;
584 } else {
585 ret = KRB5KDC_ERR_BADOPTION;
587 return ret;
594 static krb5_error_code
595 verify_flags (krb5_context context,
596 krb5_kdc_configuration *config,
597 const EncTicketPart *et,
598 const char *pstr)
600 if(et->endtime < kdc_time){
601 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
602 return KRB5KRB_AP_ERR_TKT_EXPIRED;
604 if(et->flags.invalid){
605 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
606 return KRB5KRB_AP_ERR_TKT_NYV;
608 return 0;
615 static krb5_error_code
616 fix_transited_encoding(krb5_context context,
617 krb5_kdc_configuration *config,
618 krb5_boolean check_policy,
619 const TransitedEncoding *tr,
620 EncTicketPart *et,
621 const char *client_realm,
622 const char *server_realm,
623 const char *tgt_realm)
625 krb5_error_code ret = 0;
626 char **realms, **tmp;
627 unsigned int num_realms;
628 size_t i;
630 switch (tr->tr_type) {
631 case DOMAIN_X500_COMPRESS:
632 break;
633 case 0:
635 * Allow empty content of type 0 because that is was Microsoft
636 * generates in their TGT.
638 if (tr->contents.length == 0)
639 break;
640 kdc_log(context, config, 0,
641 "Transited type 0 with non empty content");
642 return KRB5KDC_ERR_TRTYPE_NOSUPP;
643 default:
644 kdc_log(context, config, 0,
645 "Unknown transited type: %u", tr->tr_type);
646 return KRB5KDC_ERR_TRTYPE_NOSUPP;
649 ret = krb5_domain_x500_decode(context,
650 tr->contents,
651 &realms,
652 &num_realms,
653 client_realm,
654 server_realm);
655 if(ret){
656 krb5_warn(context, ret,
657 "Decoding transited encoding");
658 return ret;
660 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
661 /* not us, so add the previous realm to transited set */
662 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
663 ret = ERANGE;
664 goto free_realms;
666 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
667 if(tmp == NULL){
668 ret = ENOMEM;
669 goto free_realms;
671 realms = tmp;
672 realms[num_realms] = strdup(tgt_realm);
673 if(realms[num_realms] == NULL){
674 ret = ENOMEM;
675 goto free_realms;
677 num_realms++;
679 if(num_realms == 0) {
680 if(strcmp(client_realm, server_realm))
681 kdc_log(context, config, 0,
682 "cross-realm %s -> %s", client_realm, server_realm);
683 } else {
684 size_t l = 0;
685 char *rs;
686 for(i = 0; i < num_realms; i++)
687 l += strlen(realms[i]) + 2;
688 rs = malloc(l);
689 if(rs != NULL) {
690 *rs = '\0';
691 for(i = 0; i < num_realms; i++) {
692 if(i > 0)
693 strlcat(rs, ", ", l);
694 strlcat(rs, realms[i], l);
696 kdc_log(context, config, 0,
697 "cross-realm %s -> %s via [%s]",
698 client_realm, server_realm, rs);
699 free(rs);
702 if(check_policy) {
703 ret = krb5_check_transited(context, client_realm,
704 server_realm,
705 realms, num_realms, NULL);
706 if(ret) {
707 krb5_warn(context, ret, "cross-realm %s -> %s",
708 client_realm, server_realm);
709 goto free_realms;
711 et->flags.transited_policy_checked = 1;
713 et->transited.tr_type = DOMAIN_X500_COMPRESS;
714 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
715 if(ret)
716 krb5_warn(context, ret, "Encoding transited encoding");
717 free_realms:
718 for(i = 0; i < num_realms; i++)
719 free(realms[i]);
720 free(realms);
721 return ret;
725 static krb5_error_code
726 tgs_make_reply(krb5_context context,
727 krb5_kdc_configuration *config,
728 KDC_REQ_BODY *b,
729 krb5_const_principal tgt_name,
730 const EncTicketPart *tgt,
731 const krb5_keyblock *replykey,
732 int rk_is_subkey,
733 const EncryptionKey *serverkey,
734 const krb5_keyblock *sessionkey,
735 krb5_kvno kvno,
736 AuthorizationData *auth_data,
737 hdb_entry_ex *server,
738 krb5_principal server_principal,
739 const char *server_name,
740 hdb_entry_ex *client,
741 krb5_principal client_principal,
742 hdb_entry_ex *krbtgt,
743 krb5_enctype krbtgt_etype,
744 krb5_principals spp,
745 const krb5_data *rspac,
746 const METHOD_DATA *enc_pa_data,
747 const char **e_text,
748 krb5_data *reply)
750 KDC_REP rep;
751 EncKDCRepPart ek;
752 EncTicketPart et;
753 KDCOptions f = b->kdc_options;
754 krb5_error_code ret;
755 int is_weak = 0;
757 memset(&rep, 0, sizeof(rep));
758 memset(&et, 0, sizeof(et));
759 memset(&ek, 0, sizeof(ek));
761 rep.pvno = 5;
762 rep.msg_type = krb_tgs_rep;
764 et.authtime = tgt->authtime;
765 _kdc_fix_time(&b->till);
766 et.endtime = min(tgt->endtime, *b->till);
767 ALLOC(et.starttime);
768 *et.starttime = kdc_time;
770 ret = check_tgs_flags(context, config, b, tgt, &et);
771 if(ret)
772 goto out;
774 /* We should check the transited encoding if:
775 1) the request doesn't ask not to be checked
776 2) globally enforcing a check
777 3) principal requires checking
778 4) we allow non-check per-principal, but principal isn't marked as allowing this
779 5) we don't globally allow this
782 #define GLOBAL_FORCE_TRANSITED_CHECK \
783 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
784 #define GLOBAL_ALLOW_PER_PRINCIPAL \
785 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
786 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
787 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
789 /* these will consult the database in future release */
790 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
791 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
793 ret = fix_transited_encoding(context, config,
794 !f.disable_transited_check ||
795 GLOBAL_FORCE_TRANSITED_CHECK ||
796 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
797 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
798 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
799 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
800 &tgt->transited, &et,
801 krb5_principal_get_realm(context, client_principal),
802 krb5_principal_get_realm(context, server->entry.principal),
803 krb5_principal_get_realm(context, krbtgt->entry.principal));
804 if(ret)
805 goto out;
807 copy_Realm(&server_principal->realm, &rep.ticket.realm);
808 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
809 copy_Realm(&tgt_name->realm, &rep.crealm);
811 if (f.request_anonymous)
812 _kdc_make_anonymous_principalname (&rep.cname);
813 else */
815 copy_PrincipalName(&tgt_name->name, &rep.cname);
816 rep.ticket.tkt_vno = 5;
818 ek.caddr = et.caddr;
819 if(et.caddr == NULL)
820 et.caddr = tgt->caddr;
823 time_t life;
824 life = et.endtime - *et.starttime;
825 if(client && client->entry.max_life)
826 life = min(life, *client->entry.max_life);
827 if(server->entry.max_life)
828 life = min(life, *server->entry.max_life);
829 et.endtime = *et.starttime + life;
831 if(f.renewable_ok && tgt->flags.renewable &&
832 et.renew_till == NULL && et.endtime < *b->till &&
833 tgt->renew_till != NULL)
835 et.flags.renewable = 1;
836 ALLOC(et.renew_till);
837 *et.renew_till = *b->till;
839 if(et.renew_till){
840 time_t renew;
841 renew = *et.renew_till - *et.starttime;
842 if(client && client->entry.max_renew)
843 renew = min(renew, *client->entry.max_renew);
844 if(server->entry.max_renew)
845 renew = min(renew, *server->entry.max_renew);
846 *et.renew_till = *et.starttime + renew;
849 if(et.renew_till){
850 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
851 *et.starttime = min(*et.starttime, *et.renew_till);
852 et.endtime = min(et.endtime, *et.renew_till);
855 *et.starttime = min(*et.starttime, et.endtime);
857 if(*et.starttime == et.endtime){
858 ret = KRB5KDC_ERR_NEVER_VALID;
859 goto out;
861 if(et.renew_till && et.endtime == *et.renew_till){
862 free(et.renew_till);
863 et.renew_till = NULL;
864 et.flags.renewable = 0;
867 et.flags.pre_authent = tgt->flags.pre_authent;
868 et.flags.hw_authent = tgt->flags.hw_authent;
869 et.flags.anonymous = tgt->flags.anonymous;
870 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
872 if(rspac->length) {
874 * No not need to filter out the any PAC from the
875 * auth_data since it's signed by the KDC.
877 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
878 KRB5_AUTHDATA_WIN2K_PAC, rspac);
879 if (ret)
880 goto out;
883 if (auth_data) {
884 unsigned int i = 0;
886 /* XXX check authdata */
888 if (et.authorization_data == NULL) {
889 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
890 if (et.authorization_data == NULL) {
891 ret = ENOMEM;
892 krb5_set_error_message(context, ret, "malloc: out of memory");
893 goto out;
896 for(i = 0; i < auth_data->len ; i++) {
897 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
898 if (ret) {
899 krb5_set_error_message(context, ret, "malloc: out of memory");
900 goto out;
904 /* Filter out type KRB5SignedPath */
905 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
906 if (ret == 0) {
907 if (et.authorization_data->len == 1) {
908 free_AuthorizationData(et.authorization_data);
909 free(et.authorization_data);
910 et.authorization_data = NULL;
911 } else {
912 AuthorizationData *ad = et.authorization_data;
913 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
914 ad->len--;
919 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
920 if (ret)
921 goto out;
922 et.crealm = tgt_name->realm;
923 et.cname = tgt_name->name;
925 ek.key = et.key;
926 /* MIT must have at least one last_req */
927 ek.last_req.len = 1;
928 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
929 if (ek.last_req.val == NULL) {
930 ret = ENOMEM;
931 goto out;
933 ek.nonce = b->nonce;
934 ek.flags = et.flags;
935 ek.authtime = et.authtime;
936 ek.starttime = et.starttime;
937 ek.endtime = et.endtime;
938 ek.renew_till = et.renew_till;
939 ek.srealm = rep.ticket.realm;
940 ek.sname = rep.ticket.sname;
942 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
943 et.endtime, et.renew_till);
945 /* Don't sign cross realm tickets, they can't be checked anyway */
947 char *r = get_krbtgt_realm(&ek.sname);
949 if (r == NULL || strcmp(r, ek.srealm) == 0) {
950 ret = _kdc_add_KRB5SignedPath(context,
951 config,
952 krbtgt,
953 krbtgt_etype,
954 client_principal,
955 NULL,
956 spp,
957 &et);
958 if (ret)
959 goto out;
963 if (enc_pa_data->len) {
964 rep.padata = calloc(1, sizeof(*rep.padata));
965 if (rep.padata == NULL) {
966 ret = ENOMEM;
967 goto out;
969 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
970 if (ret)
971 goto out;
974 if (krb5_enctype_valid(context, serverkey->keytype) != 0
975 && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
977 krb5_enctype_enable(context, serverkey->keytype);
978 is_weak = 1;
982 /* It is somewhat unclear where the etype in the following
983 encryption should come from. What we have is a session
984 key in the passed tgt, and a list of preferred etypes
985 *for the new ticket*. Should we pick the best possible
986 etype, given the keytype in the tgt, or should we look
987 at the etype list here as well? What if the tgt
988 session key is DES3 and we want a ticket with a (say)
989 CAST session key. Should the DES3 etype be added to the
990 etype list, even if we don't want a session key with
991 DES3? */
992 ret = _kdc_encode_reply(context, config,
993 &rep, &et, &ek, serverkey->keytype,
994 kvno,
995 serverkey, 0, replykey, rk_is_subkey,
996 e_text, reply);
997 if (is_weak)
998 krb5_enctype_disable(context, serverkey->keytype);
1000 out:
1001 free_TGS_REP(&rep);
1002 free_TransitedEncoding(&et.transited);
1003 if(et.starttime)
1004 free(et.starttime);
1005 if(et.renew_till)
1006 free(et.renew_till);
1007 if(et.authorization_data) {
1008 free_AuthorizationData(et.authorization_data);
1009 free(et.authorization_data);
1011 free_LastReq(&ek.last_req);
1012 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1013 free_EncryptionKey(&et.key);
1014 return ret;
1017 static krb5_error_code
1018 tgs_check_authenticator(krb5_context context,
1019 krb5_kdc_configuration *config,
1020 krb5_auth_context ac,
1021 KDC_REQ_BODY *b,
1022 const char **e_text,
1023 krb5_keyblock *key)
1025 krb5_authenticator auth;
1026 size_t len = 0;
1027 unsigned char *buf;
1028 size_t buf_size;
1029 krb5_error_code ret;
1030 krb5_crypto crypto;
1032 krb5_auth_con_getauthenticator(context, ac, &auth);
1033 if(auth->cksum == NULL){
1034 kdc_log(context, config, 0, "No authenticator in request");
1035 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1036 goto out;
1039 * according to RFC1510 it doesn't need to be keyed,
1040 * but according to the latest draft it needs to.
1042 if (
1043 #if 0
1044 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1046 #endif
1047 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1048 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1049 auth->cksum->cksumtype);
1050 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1051 goto out;
1054 /* XXX should not re-encode this */
1055 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1056 if(ret){
1057 const char *msg = krb5_get_error_message(context, ret);
1058 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1059 krb5_free_error_message(context, msg);
1060 goto out;
1062 if(buf_size != len) {
1063 free(buf);
1064 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1065 *e_text = "KDC internal error";
1066 ret = KRB5KRB_ERR_GENERIC;
1067 goto out;
1069 ret = krb5_crypto_init(context, key, 0, &crypto);
1070 if (ret) {
1071 const char *msg = krb5_get_error_message(context, ret);
1072 free(buf);
1073 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1074 krb5_free_error_message(context, msg);
1075 goto out;
1077 ret = krb5_verify_checksum(context,
1078 crypto,
1079 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1080 buf,
1081 len,
1082 auth->cksum);
1083 free(buf);
1084 krb5_crypto_destroy(context, crypto);
1085 if(ret){
1086 const char *msg = krb5_get_error_message(context, ret);
1087 kdc_log(context, config, 0,
1088 "Failed to verify authenticator checksum: %s", msg);
1089 krb5_free_error_message(context, msg);
1091 out:
1092 free_Authenticator(auth);
1093 free(auth);
1094 return ret;
1101 static const char *
1102 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1104 const char *new_realm = krb5_config_get_string(context,
1105 NULL,
1106 "capaths",
1107 crealm,
1108 srealm,
1109 NULL);
1110 return new_realm;
1114 static krb5_boolean
1115 need_referral(krb5_context context, krb5_kdc_configuration *config,
1116 const KDCOptions * const options, krb5_principal server,
1117 krb5_realm **realms)
1119 const char *name;
1121 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1122 return FALSE;
1124 if (server->name.name_string.len == 1)
1125 name = server->name.name_string.val[0];
1126 else if (server->name.name_string.len > 1)
1127 name = server->name.name_string.val[1];
1128 else
1129 return FALSE;
1131 kdc_log(context, config, 0, "Searching referral for %s", name);
1133 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1136 static krb5_error_code
1137 tgs_parse_request(krb5_context context,
1138 krb5_kdc_configuration *config,
1139 KDC_REQ_BODY *b,
1140 const PA_DATA *tgs_req,
1141 hdb_entry_ex **krbtgt,
1142 krb5_enctype *krbtgt_etype,
1143 krb5_ticket **ticket,
1144 const char **e_text,
1145 const char *from,
1146 const struct sockaddr *from_addr,
1147 time_t **csec,
1148 int **cusec,
1149 AuthorizationData **auth_data,
1150 krb5_keyblock **replykey,
1151 int *rk_is_subkey)
1153 static char failed[] = "<unparse_name failed>";
1154 krb5_ap_req ap_req;
1155 krb5_error_code ret;
1156 krb5_principal princ;
1157 krb5_auth_context ac = NULL;
1158 krb5_flags ap_req_options;
1159 krb5_flags verify_ap_req_flags;
1160 krb5_crypto crypto;
1161 Key *tkey;
1162 krb5_keyblock *subkey = NULL;
1163 unsigned usage;
1165 *auth_data = NULL;
1166 *csec = NULL;
1167 *cusec = NULL;
1168 *replykey = NULL;
1170 memset(&ap_req, 0, sizeof(ap_req));
1171 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1172 if(ret){
1173 const char *msg = krb5_get_error_message(context, ret);
1174 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1175 krb5_free_error_message(context, msg);
1176 goto out;
1179 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1180 /* XXX check for ticket.sname == req.sname */
1181 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1182 ret = KRB5KDC_ERR_POLICY; /* ? */
1183 goto out;
1186 _krb5_principalname2krb5_principal(context,
1187 &princ,
1188 ap_req.ticket.sname,
1189 ap_req.ticket.realm);
1191 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, ap_req.ticket.enc_part.kvno, NULL, krbtgt);
1193 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1194 char *p;
1195 ret = krb5_unparse_name(context, princ, &p);
1196 if (ret != 0)
1197 p = failed;
1198 krb5_free_principal(context, princ);
1199 kdc_log(context, config, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p);
1200 if (ret == 0)
1201 free(p);
1202 ret = HDB_ERR_NOT_FOUND_HERE;
1203 goto out;
1204 } else if(ret){
1205 const char *msg = krb5_get_error_message(context, ret);
1206 char *p;
1207 ret = krb5_unparse_name(context, princ, &p);
1208 if (ret != 0)
1209 p = failed;
1210 krb5_free_principal(context, princ);
1211 kdc_log(context, config, 0,
1212 "Ticket-granting ticket not found in database: %s", msg);
1213 krb5_free_error_message(context, msg);
1214 if (ret == 0)
1215 free(p);
1216 ret = KRB5KRB_AP_ERR_NOT_US;
1217 goto out;
1220 if(ap_req.ticket.enc_part.kvno &&
1221 *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
1222 char *p;
1224 ret = krb5_unparse_name (context, princ, &p);
1225 krb5_free_principal(context, princ);
1226 if (ret != 0)
1227 p = failed;
1228 kdc_log(context, config, 0,
1229 "Ticket kvno = %d, DB kvno = %d (%s)",
1230 *ap_req.ticket.enc_part.kvno,
1231 (*krbtgt)->entry.kvno,
1233 if (ret == 0)
1234 free (p);
1235 ret = KRB5KRB_AP_ERR_BADKEYVER;
1236 goto out;
1239 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1241 ret = hdb_enctype2key(context, &(*krbtgt)->entry,
1242 ap_req.ticket.enc_part.etype, &tkey);
1243 if(ret){
1244 char *str = NULL, *p = NULL;
1246 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1247 krb5_unparse_name(context, princ, &p);
1248 kdc_log(context, config, 0,
1249 "No server key with enctype %s found for %s",
1250 str ? str : "<unknown enctype>",
1251 p ? p : "<unparse_name failed>");
1252 free(str);
1253 free(p);
1254 ret = KRB5KRB_AP_ERR_BADKEYVER;
1255 goto out;
1258 if (b->kdc_options.validate)
1259 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1260 else
1261 verify_ap_req_flags = 0;
1263 ret = krb5_verify_ap_req2(context,
1264 &ac,
1265 &ap_req,
1266 princ,
1267 &tkey->key,
1268 verify_ap_req_flags,
1269 &ap_req_options,
1270 ticket,
1271 KRB5_KU_TGS_REQ_AUTH);
1273 krb5_free_principal(context, princ);
1274 if(ret) {
1275 const char *msg = krb5_get_error_message(context, ret);
1276 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1277 krb5_free_error_message(context, msg);
1278 goto out;
1282 krb5_authenticator auth;
1284 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1285 if (ret == 0) {
1286 *csec = malloc(sizeof(**csec));
1287 if (*csec == NULL) {
1288 krb5_free_authenticator(context, &auth);
1289 kdc_log(context, config, 0, "malloc failed");
1290 goto out;
1292 **csec = auth->ctime;
1293 *cusec = malloc(sizeof(**cusec));
1294 if (*cusec == NULL) {
1295 krb5_free_authenticator(context, &auth);
1296 kdc_log(context, config, 0, "malloc failed");
1297 goto out;
1299 **cusec = auth->cusec;
1300 krb5_free_authenticator(context, &auth);
1304 ret = tgs_check_authenticator(context, config,
1305 ac, b, e_text, &(*ticket)->ticket.key);
1306 if (ret) {
1307 krb5_auth_con_free(context, ac);
1308 goto out;
1311 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1312 *rk_is_subkey = 1;
1314 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1315 if(ret){
1316 const char *msg = krb5_get_error_message(context, ret);
1317 krb5_auth_con_free(context, ac);
1318 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1319 krb5_free_error_message(context, msg);
1320 goto out;
1322 if(subkey == NULL){
1323 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1324 *rk_is_subkey = 0;
1326 ret = krb5_auth_con_getkey(context, ac, &subkey);
1327 if(ret) {
1328 const char *msg = krb5_get_error_message(context, ret);
1329 krb5_auth_con_free(context, ac);
1330 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1331 krb5_free_error_message(context, msg);
1332 goto out;
1335 if(subkey == NULL){
1336 krb5_auth_con_free(context, ac);
1337 kdc_log(context, config, 0,
1338 "Failed to get key for enc-authorization-data");
1339 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1340 goto out;
1343 *replykey = subkey;
1345 if (b->enc_authorization_data) {
1346 krb5_data ad;
1348 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1349 if (ret) {
1350 const char *msg = krb5_get_error_message(context, ret);
1351 krb5_auth_con_free(context, ac);
1352 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1353 krb5_free_error_message(context, msg);
1354 goto out;
1356 ret = krb5_decrypt_EncryptedData (context,
1357 crypto,
1358 usage,
1359 b->enc_authorization_data,
1360 &ad);
1361 krb5_crypto_destroy(context, crypto);
1362 if(ret){
1363 krb5_auth_con_free(context, ac);
1364 kdc_log(context, config, 0,
1365 "Failed to decrypt enc-authorization-data");
1366 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1367 goto out;
1369 ALLOC(*auth_data);
1370 if (*auth_data == NULL) {
1371 krb5_auth_con_free(context, ac);
1372 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1373 goto out;
1375 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1376 if(ret){
1377 krb5_auth_con_free(context, ac);
1378 free(*auth_data);
1379 *auth_data = NULL;
1380 kdc_log(context, config, 0, "Failed to decode authorization data");
1381 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1382 goto out;
1386 krb5_auth_con_free(context, ac);
1388 out:
1389 free_AP_REQ(&ap_req);
1391 return ret;
1394 static krb5_error_code
1395 build_server_referral(krb5_context context,
1396 krb5_kdc_configuration *config,
1397 krb5_crypto session,
1398 krb5_const_realm referred_realm,
1399 const PrincipalName *true_principal_name,
1400 const PrincipalName *requested_principal,
1401 krb5_data *outdata)
1403 PA_ServerReferralData ref;
1404 krb5_error_code ret;
1405 EncryptedData ed;
1406 krb5_data data;
1407 size_t size = 0;
1409 memset(&ref, 0, sizeof(ref));
1411 if (referred_realm) {
1412 ALLOC(ref.referred_realm);
1413 if (ref.referred_realm == NULL)
1414 goto eout;
1415 *ref.referred_realm = strdup(referred_realm);
1416 if (*ref.referred_realm == NULL)
1417 goto eout;
1419 if (true_principal_name) {
1420 ALLOC(ref.true_principal_name);
1421 if (ref.true_principal_name == NULL)
1422 goto eout;
1423 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1424 if (ret)
1425 goto eout;
1427 if (requested_principal) {
1428 ALLOC(ref.requested_principal_name);
1429 if (ref.requested_principal_name == NULL)
1430 goto eout;
1431 ret = copy_PrincipalName(requested_principal,
1432 ref.requested_principal_name);
1433 if (ret)
1434 goto eout;
1437 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1438 data.data, data.length,
1439 &ref, &size, ret);
1440 free_PA_ServerReferralData(&ref);
1441 if (ret)
1442 return ret;
1443 if (data.length != size)
1444 krb5_abortx(context, "internal asn.1 encoder error");
1446 ret = krb5_encrypt_EncryptedData(context, session,
1447 KRB5_KU_PA_SERVER_REFERRAL,
1448 data.data, data.length,
1449 0 /* kvno */, &ed);
1450 free(data.data);
1451 if (ret)
1452 return ret;
1454 ASN1_MALLOC_ENCODE(EncryptedData,
1455 outdata->data, outdata->length,
1456 &ed, &size, ret);
1457 free_EncryptedData(&ed);
1458 if (ret)
1459 return ret;
1460 if (outdata->length != size)
1461 krb5_abortx(context, "internal asn.1 encoder error");
1463 return 0;
1464 eout:
1465 free_PA_ServerReferralData(&ref);
1466 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1467 return ENOMEM;
1470 static krb5_error_code
1471 tgs_build_reply(krb5_context context,
1472 krb5_kdc_configuration *config,
1473 KDC_REQ *req,
1474 KDC_REQ_BODY *b,
1475 hdb_entry_ex *krbtgt,
1476 krb5_enctype krbtgt_etype,
1477 const krb5_keyblock *replykey,
1478 int rk_is_subkey,
1479 krb5_ticket *ticket,
1480 krb5_data *reply,
1481 const char *from,
1482 const char **e_text,
1483 AuthorizationData **auth_data,
1484 const struct sockaddr *from_addr)
1486 krb5_error_code ret;
1487 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1488 krb5_principal krbtgt_principal = NULL;
1489 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL;
1490 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1491 HDB *clientdb, *s4u2self_impersonated_clientdb;
1492 krb5_realm ref_realm = NULL;
1493 EncTicketPart *tgt = &ticket->ticket;
1494 krb5_principals spp = NULL;
1495 const EncryptionKey *ekey;
1496 krb5_keyblock sessionkey;
1497 krb5_kvno kvno;
1498 krb5_data rspac;
1500 hdb_entry_ex *krbtgt_out = NULL;
1502 METHOD_DATA enc_pa_data;
1504 PrincipalName *s;
1505 Realm r;
1506 int nloop = 0;
1507 EncTicketPart adtkt;
1508 char opt_str[128];
1509 int signedpath = 0;
1511 Key *tkey_check;
1512 Key *tkey_sign;
1513 int flags = HDB_F_FOR_TGS_REQ;
1515 memset(&sessionkey, 0, sizeof(sessionkey));
1516 memset(&adtkt, 0, sizeof(adtkt));
1517 krb5_data_zero(&rspac);
1518 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1520 s = b->sname;
1521 r = b->realm;
1524 * Always to do CANON, see comment below about returned server principal (rsp).
1526 flags |= HDB_F_CANON;
1528 if(b->kdc_options.enc_tkt_in_skey){
1529 Ticket *t;
1530 hdb_entry_ex *uu;
1531 krb5_principal p;
1532 Key *uukey;
1534 if(b->additional_tickets == NULL ||
1535 b->additional_tickets->len == 0){
1536 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1537 kdc_log(context, config, 0,
1538 "No second ticket present in request");
1539 goto out;
1541 t = &b->additional_tickets->val[0];
1542 if(!get_krbtgt_realm(&t->sname)){
1543 kdc_log(context, config, 0,
1544 "Additional ticket is not a ticket-granting ticket");
1545 ret = KRB5KDC_ERR_POLICY;
1546 goto out;
1548 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1549 ret = _kdc_db_fetch(context, config, p,
1550 HDB_F_GET_KRBTGT, t->enc_part.kvno,
1551 NULL, &uu);
1552 krb5_free_principal(context, p);
1553 if(ret){
1554 if (ret == HDB_ERR_NOENTRY)
1555 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1556 goto out;
1558 ret = hdb_enctype2key(context, &uu->entry,
1559 t->enc_part.etype, &uukey);
1560 if(ret){
1561 _kdc_free_ent(context, uu);
1562 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1563 goto out;
1565 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1566 _kdc_free_ent(context, uu);
1567 if(ret)
1568 goto out;
1570 ret = verify_flags(context, config, &adtkt, spn);
1571 if (ret)
1572 goto out;
1574 s = &adtkt.cname;
1575 r = adtkt.crealm;
1578 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1579 ret = krb5_unparse_name(context, sp, &spn);
1580 if (ret)
1581 goto out;
1582 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1583 ret = krb5_unparse_name(context, cp, &cpn);
1584 if (ret)
1585 goto out;
1586 unparse_flags (KDCOptions2int(b->kdc_options),
1587 asn1_KDCOptions_units(),
1588 opt_str, sizeof(opt_str));
1589 if(*opt_str)
1590 kdc_log(context, config, 0,
1591 "TGS-REQ %s from %s for %s [%s]",
1592 cpn, from, spn, opt_str);
1593 else
1594 kdc_log(context, config, 0,
1595 "TGS-REQ %s from %s for %s", cpn, from, spn);
1598 * Fetch server
1601 server_lookup:
1602 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1603 NULL, NULL, &server);
1605 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1606 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1607 goto out;
1608 } else if(ret){
1609 const char *new_rlm, *msg;
1610 Realm req_rlm;
1611 krb5_realm *realms;
1613 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1614 if(nloop++ < 2) {
1615 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1616 if(new_rlm) {
1617 kdc_log(context, config, 5, "krbtgt for realm %s "
1618 "not found, trying %s",
1619 req_rlm, new_rlm);
1620 krb5_free_principal(context, sp);
1621 free(spn);
1622 krb5_make_principal(context, &sp, r,
1623 KRB5_TGS_NAME, new_rlm, NULL);
1624 ret = krb5_unparse_name(context, sp, &spn);
1625 if (ret)
1626 goto out;
1628 if (ref_realm)
1629 free(ref_realm);
1630 ref_realm = strdup(new_rlm);
1631 goto server_lookup;
1634 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1635 if (strcmp(realms[0], sp->realm) != 0) {
1636 kdc_log(context, config, 5,
1637 "Returning a referral to realm %s for "
1638 "server %s that was not found",
1639 realms[0], spn);
1640 krb5_free_principal(context, sp);
1641 free(spn);
1642 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1643 realms[0], NULL);
1644 ret = krb5_unparse_name(context, sp, &spn);
1645 if (ret)
1646 goto out;
1648 if (ref_realm)
1649 free(ref_realm);
1650 ref_realm = strdup(realms[0]);
1652 krb5_free_host_realm(context, realms);
1653 goto server_lookup;
1655 krb5_free_host_realm(context, realms);
1657 msg = krb5_get_error_message(context, ret);
1658 kdc_log(context, config, 0,
1659 "Server not found in database: %s: %s", spn, msg);
1660 krb5_free_error_message(context, msg);
1661 if (ret == HDB_ERR_NOENTRY)
1662 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1663 goto out;
1666 /* the name returned to the client depend on what was asked for,
1667 * return canonical name if kdc_options.canonicalize was set, the
1668 * client wants the true name of the principal, if not it just
1669 * wants the name its asked for.
1672 if (b->kdc_options.canonicalize)
1673 rsp = server->entry.principal;
1674 else
1675 rsp = sp;
1679 * Select enctype, return key and kvno.
1683 krb5_enctype etype;
1685 if(b->kdc_options.enc_tkt_in_skey) {
1686 size_t i;
1687 ekey = &adtkt.key;
1688 for(i = 0; i < b->etype.len; i++)
1689 if (b->etype.val[i] == adtkt.key.keytype)
1690 break;
1691 if(i == b->etype.len) {
1692 kdc_log(context, config, 0,
1693 "Addition ticket have not matching etypes");
1694 krb5_clear_error_message(context);
1695 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1696 goto out;
1698 etype = b->etype.val[i];
1699 kvno = 0;
1700 } else {
1701 Key *skey;
1703 ret = _kdc_find_etype(context,
1704 krb5_principal_is_krbtgt(context, sp) ?
1705 config->tgt_use_strongest_session_key :
1706 config->svc_use_strongest_session_key, FALSE,
1707 server, b->etype.val, b->etype.len, &etype,
1708 NULL);
1709 if(ret) {
1710 kdc_log(context, config, 0,
1711 "Server (%s) has no support for etypes", spn);
1712 goto out;
1714 ret = _kdc_get_preferred_key(context, config, server, spn,
1715 NULL, &skey);
1716 if(ret) {
1717 kdc_log(context, config, 0,
1718 "Server (%s) has no supported etypes", spn);
1719 goto out;
1721 ekey = &skey->key;
1722 kvno = server->entry.kvno;
1725 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1726 if (ret)
1727 goto out;
1731 * Check that service is in the same realm as the krbtgt. If it's
1732 * not the same, it's someone that is using a uni-directional trust
1733 * backward.
1737 * Validate authoriation data
1740 ret = hdb_enctype2key(context, &krbtgt->entry,
1741 krbtgt_etype, &tkey_check);
1742 if(ret) {
1743 kdc_log(context, config, 0,
1744 "Failed to find key for krbtgt PAC check");
1745 goto out;
1748 /* Now refetch the primary krbtgt, and get the current kvno (the
1749 * sign check may have been on an old kvno, and the server may
1750 * have been an incoming trust) */
1751 ret = krb5_make_principal(context, &krbtgt_principal,
1752 krb5_principal_get_comp_string(context,
1753 krbtgt->entry.principal,
1755 KRB5_TGS_NAME,
1756 krb5_principal_get_comp_string(context,
1757 krbtgt->entry.principal,
1758 1), NULL);
1759 if(ret) {
1760 kdc_log(context, config, 0,
1761 "Failed to generate krbtgt principal");
1762 goto out;
1765 ret = _kdc_db_fetch(context, config, krbtgt_principal, HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1766 krb5_free_principal(context, krbtgt_principal);
1767 if (ret) {
1768 krb5_error_code ret2;
1769 char *ktpn, *ktpn2;
1770 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1771 ret2 = krb5_unparse_name(context, krbtgt_principal, &ktpn2);
1772 kdc_log(context, config, 0,
1773 "Request with wrong krbtgt: %s, %s not found in our database",
1774 (ret == 0) ? ktpn : "<unknown>", (ret2 == 0) ? ktpn2 : "<unknown>");
1775 if(ret == 0)
1776 free(ktpn);
1777 if(ret2 == 0)
1778 free(ktpn2);
1779 ret = KRB5KRB_AP_ERR_NOT_US;
1780 goto out;
1783 /* The first realm is the realm of the service, the second is
1784 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1785 * encrypted to. The redirection via the krbtgt_out entry allows
1786 * the DB to possibly correct the case of the realm (Samba4 does
1787 * this) before the strcmp() */
1788 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1789 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1790 char *ktpn;
1791 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1792 kdc_log(context, config, 0,
1793 "Request with wrong krbtgt: %s",
1794 (ret == 0) ? ktpn : "<unknown>");
1795 if(ret == 0)
1796 free(ktpn);
1797 ret = KRB5KRB_AP_ERR_NOT_US;
1800 ret = hdb_enctype2key(context, &krbtgt_out->entry,
1801 krbtgt_etype, &tkey_sign);
1802 if(ret) {
1803 kdc_log(context, config, 0,
1804 "Failed to find key for krbtgt PAC signature");
1805 goto out;
1808 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1809 NULL, &clientdb, &client);
1810 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1811 /* This is OK, we are just trying to find out if they have
1812 * been disabled or deleted in the meantime, missing secrets
1813 * is OK */
1814 } else if(ret){
1815 const char *krbtgt_realm, *msg;
1818 * If the client belongs to the same realm as our krbtgt, it
1819 * should exist in the local database.
1823 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1825 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1826 if (ret == HDB_ERR_NOENTRY)
1827 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1828 kdc_log(context, config, 1, "Client no longer in database: %s",
1829 cpn);
1830 goto out;
1833 msg = krb5_get_error_message(context, ret);
1834 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1835 krb5_free_error_message(context, msg);
1838 ret = check_PAC(context, config, cp, NULL,
1839 client, server, krbtgt,
1840 &tkey_check->key, &tkey_check->key,
1841 ekey, &tkey_sign->key,
1842 tgt, &rspac, &signedpath);
1843 if (ret) {
1844 const char *msg = krb5_get_error_message(context, ret);
1845 kdc_log(context, config, 0,
1846 "Verify PAC failed for %s (%s) from %s with %s",
1847 spn, cpn, from, msg);
1848 krb5_free_error_message(context, msg);
1849 goto out;
1852 /* also check the krbtgt for signature */
1853 ret = check_KRB5SignedPath(context,
1854 config,
1855 krbtgt,
1857 tgt,
1858 &spp,
1859 &signedpath);
1860 if (ret) {
1861 const char *msg = krb5_get_error_message(context, ret);
1862 kdc_log(context, config, 0,
1863 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1864 spn, cpn, from, msg);
1865 krb5_free_error_message(context, msg);
1866 goto out;
1870 * Process request
1873 /* by default the tgt principal matches the client principal */
1874 tp = cp;
1875 tpn = cpn;
1877 if (client) {
1878 const PA_DATA *sdata;
1879 int i = 0;
1881 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1882 if (sdata) {
1883 krb5_crypto crypto;
1884 krb5_data datack;
1885 PA_S4U2Self self;
1886 const char *str;
1888 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1889 sdata->padata_value.length,
1890 &self, NULL);
1891 if (ret) {
1892 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1893 goto out;
1896 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1897 if (ret)
1898 goto out;
1900 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1901 if (ret) {
1902 const char *msg = krb5_get_error_message(context, ret);
1903 free_PA_S4U2Self(&self);
1904 krb5_data_free(&datack);
1905 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1906 krb5_free_error_message(context, msg);
1907 goto out;
1910 ret = krb5_verify_checksum(context,
1911 crypto,
1912 KRB5_KU_OTHER_CKSUM,
1913 datack.data,
1914 datack.length,
1915 &self.cksum);
1916 krb5_data_free(&datack);
1917 krb5_crypto_destroy(context, crypto);
1918 if (ret) {
1919 const char *msg = krb5_get_error_message(context, ret);
1920 free_PA_S4U2Self(&self);
1921 kdc_log(context, config, 0,
1922 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1923 krb5_free_error_message(context, msg);
1924 goto out;
1927 ret = _krb5_principalname2krb5_principal(context,
1928 &tp,
1929 self.name,
1930 self.realm);
1931 free_PA_S4U2Self(&self);
1932 if (ret)
1933 goto out;
1935 ret = krb5_unparse_name(context, tp, &tpn);
1936 if (ret)
1937 goto out;
1939 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1940 if(rspac.data) {
1941 krb5_pac p = NULL;
1942 krb5_data_free(&rspac);
1943 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
1944 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
1945 if (ret) {
1946 const char *msg;
1949 * If the client belongs to the same realm as our krbtgt, it
1950 * should exist in the local database.
1954 if (ret == HDB_ERR_NOENTRY)
1955 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1956 msg = krb5_get_error_message(context, ret);
1957 kdc_log(context, config, 1,
1958 "S2U4Self principal to impersonate %s not found in database: %s",
1959 tpn, msg);
1960 krb5_free_error_message(context, msg);
1961 goto out;
1963 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
1964 if (ret) {
1965 kdc_log(context, config, 0, "PAC generation failed for -- %s",
1966 tpn);
1967 goto out;
1969 if (p != NULL) {
1970 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
1971 s4u2self_impersonated_client->entry.principal,
1972 ekey, &tkey_sign->key,
1973 &rspac);
1974 krb5_pac_free(context, p);
1975 if (ret) {
1976 kdc_log(context, config, 0, "PAC signing failed for -- %s",
1977 tpn);
1978 goto out;
1984 * Check that service doing the impersonating is
1985 * requesting a ticket to it-self.
1987 ret = check_s4u2self(context, config, clientdb, client, sp);
1988 if (ret) {
1989 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
1990 "to impersonate to service "
1991 "(tried for user %s to service %s)",
1992 cpn, tpn, spn);
1993 goto out;
1997 * If the service isn't trusted for authentication to
1998 * delegation, remove the forward flag.
2001 if (client->entry.flags.trusted_for_delegation) {
2002 str = "[forwardable]";
2003 } else {
2004 b->kdc_options.forwardable = 0;
2005 str = "";
2007 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2008 "service %s %s", cpn, tpn, spn, str);
2013 * Constrained delegation
2016 if (client != NULL
2017 && b->additional_tickets != NULL
2018 && b->additional_tickets->len != 0
2019 && b->kdc_options.enc_tkt_in_skey == 0)
2021 int ad_signedpath = 0;
2022 Key *clientkey;
2023 Ticket *t;
2026 * Require that the KDC have issued the service's krbtgt (not
2027 * self-issued ticket with kimpersonate(1).
2029 if (!signedpath) {
2030 ret = KRB5KDC_ERR_BADOPTION;
2031 kdc_log(context, config, 0,
2032 "Constrained delegation done on service ticket %s/%s",
2033 cpn, spn);
2034 goto out;
2037 t = &b->additional_tickets->val[0];
2039 ret = hdb_enctype2key(context, &client->entry,
2040 t->enc_part.etype, &clientkey);
2041 if(ret){
2042 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2043 goto out;
2046 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2047 if (ret) {
2048 kdc_log(context, config, 0,
2049 "failed to decrypt ticket for "
2050 "constrained delegation from %s to %s ", cpn, spn);
2051 goto out;
2054 ret = _krb5_principalname2krb5_principal(context,
2055 &tp,
2056 adtkt.cname,
2057 adtkt.crealm);
2058 if (ret)
2059 goto out;
2061 ret = krb5_unparse_name(context, tp, &tpn);
2062 if (ret)
2063 goto out;
2065 ret = _krb5_principalname2krb5_principal(context,
2066 &dp,
2067 t->sname,
2068 t->realm);
2069 if (ret)
2070 goto out;
2072 ret = krb5_unparse_name(context, dp, &dpn);
2073 if (ret)
2074 goto out;
2076 /* check that ticket is valid */
2077 if (adtkt.flags.forwardable == 0) {
2078 kdc_log(context, config, 0,
2079 "Missing forwardable flag on ticket for "
2080 "constrained delegation from %s (%s) as %s to %s ",
2081 cpn, dpn, tpn, spn);
2082 ret = KRB5KDC_ERR_BADOPTION;
2083 goto out;
2086 ret = check_constrained_delegation(context, config, clientdb,
2087 client, server, sp);
2088 if (ret) {
2089 kdc_log(context, config, 0,
2090 "constrained delegation from %s (%s) as %s to %s not allowed",
2091 cpn, dpn, tpn, spn);
2092 goto out;
2095 ret = verify_flags(context, config, &adtkt, tpn);
2096 if (ret) {
2097 goto out;
2100 krb5_data_free(&rspac);
2103 * generate the PAC for the user.
2105 * TODO: pass in t->sname and t->realm and build
2106 * a S4U_DELEGATION_INFO blob to the PAC.
2108 ret = check_PAC(context, config, tp, dp,
2109 client, server, krbtgt,
2110 &clientkey->key, &tkey_check->key,
2111 ekey, &tkey_sign->key,
2112 &adtkt, &rspac, &ad_signedpath);
2113 if (ret) {
2114 const char *msg = krb5_get_error_message(context, ret);
2115 kdc_log(context, config, 0,
2116 "Verify delegated PAC failed to %s for client"
2117 "%s (%s) as %s from %s with %s",
2118 spn, cpn, dpn, tpn, from, msg);
2119 krb5_free_error_message(context, msg);
2120 goto out;
2124 * Check that the KDC issued the user's ticket.
2126 ret = check_KRB5SignedPath(context,
2127 config,
2128 krbtgt,
2130 &adtkt,
2131 NULL,
2132 &ad_signedpath);
2133 if (ret) {
2134 const char *msg = krb5_get_error_message(context, ret);
2135 kdc_log(context, config, 0,
2136 "KRB5SignedPath check from service %s failed "
2137 "for delegation to %s for client %s (%s)"
2138 "from %s failed with %s",
2139 spn, tpn, dpn, cpn, from, msg);
2140 krb5_free_error_message(context, msg);
2141 goto out;
2144 if (!ad_signedpath) {
2145 ret = KRB5KDC_ERR_BADOPTION;
2146 kdc_log(context, config, 0,
2147 "Ticket not signed with PAC nor SignedPath service %s failed "
2148 "for delegation to %s for client %s (%s)"
2149 "from %s",
2150 spn, tpn, dpn, cpn, from);
2151 goto out;
2154 kdc_log(context, config, 0, "constrained delegation for %s "
2155 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2159 * Check flags
2162 ret = kdc_check_flags(context, config,
2163 client, cpn,
2164 server, spn,
2165 FALSE);
2166 if(ret)
2167 goto out;
2169 if((b->kdc_options.validate || b->kdc_options.renew) &&
2170 !krb5_principal_compare(context,
2171 krbtgt->entry.principal,
2172 server->entry.principal)){
2173 kdc_log(context, config, 0, "Inconsistent request.");
2174 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2175 goto out;
2178 /* check for valid set of addresses */
2179 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2180 ret = KRB5KRB_AP_ERR_BADADDR;
2181 kdc_log(context, config, 0, "Request from wrong address");
2182 goto out;
2186 * If this is an referral, add server referral data to the
2187 * auth_data reply .
2189 if (ref_realm) {
2190 PA_DATA pa;
2191 krb5_crypto crypto;
2193 kdc_log(context, config, 0,
2194 "Adding server referral to %s", ref_realm);
2196 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2197 if (ret)
2198 goto out;
2200 ret = build_server_referral(context, config, crypto, ref_realm,
2201 NULL, s, &pa.padata_value);
2202 krb5_crypto_destroy(context, crypto);
2203 if (ret) {
2204 kdc_log(context, config, 0,
2205 "Failed building server referral");
2206 goto out;
2208 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2210 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2211 krb5_data_free(&pa.padata_value);
2212 if (ret) {
2213 kdc_log(context, config, 0,
2214 "Add server referral METHOD-DATA failed");
2215 goto out;
2223 ret = tgs_make_reply(context,
2224 config,
2227 tgt,
2228 replykey,
2229 rk_is_subkey,
2230 ekey,
2231 &sessionkey,
2232 kvno,
2233 *auth_data,
2234 server,
2235 rsp,
2236 spn,
2237 client,
2239 krbtgt_out,
2240 krbtgt_etype,
2241 spp,
2242 &rspac,
2243 &enc_pa_data,
2244 e_text,
2245 reply);
2247 out:
2248 if (tpn != cpn)
2249 free(tpn);
2250 free(spn);
2251 free(cpn);
2252 if (dpn)
2253 free(dpn);
2255 krb5_data_free(&rspac);
2256 krb5_free_keyblock_contents(context, &sessionkey);
2257 if(krbtgt_out)
2258 _kdc_free_ent(context, krbtgt_out);
2259 if(server)
2260 _kdc_free_ent(context, server);
2261 if(client)
2262 _kdc_free_ent(context, client);
2263 if(s4u2self_impersonated_client)
2264 _kdc_free_ent(context, s4u2self_impersonated_client);
2266 if (tp && tp != cp)
2267 krb5_free_principal(context, tp);
2268 if (cp)
2269 krb5_free_principal(context, cp);
2270 if (dp)
2271 krb5_free_principal(context, dp);
2272 if (sp)
2273 krb5_free_principal(context, sp);
2274 if (ref_realm)
2275 free(ref_realm);
2276 free_METHOD_DATA(&enc_pa_data);
2278 free_EncTicketPart(&adtkt);
2280 return ret;
2287 krb5_error_code
2288 _kdc_tgs_rep(krb5_context context,
2289 krb5_kdc_configuration *config,
2290 KDC_REQ *req,
2291 krb5_data *data,
2292 const char *from,
2293 struct sockaddr *from_addr,
2294 int datagram_reply)
2296 AuthorizationData *auth_data = NULL;
2297 krb5_error_code ret;
2298 int i = 0;
2299 const PA_DATA *tgs_req;
2301 hdb_entry_ex *krbtgt = NULL;
2302 krb5_ticket *ticket = NULL;
2303 const char *e_text = NULL;
2304 krb5_enctype krbtgt_etype = ETYPE_NULL;
2306 krb5_keyblock *replykey = NULL;
2307 int rk_is_subkey = 0;
2308 time_t *csec = NULL;
2309 int *cusec = NULL;
2311 if(req->padata == NULL){
2312 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2313 kdc_log(context, config, 0,
2314 "TGS-REQ from %s without PA-DATA", from);
2315 goto out;
2318 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2320 if(tgs_req == NULL){
2321 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2323 kdc_log(context, config, 0,
2324 "TGS-REQ from %s without PA-TGS-REQ", from);
2325 goto out;
2327 ret = tgs_parse_request(context, config,
2328 &req->req_body, tgs_req,
2329 &krbtgt,
2330 &krbtgt_etype,
2331 &ticket,
2332 &e_text,
2333 from, from_addr,
2334 &csec, &cusec,
2335 &auth_data,
2336 &replykey,
2337 &rk_is_subkey);
2338 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2339 /* kdc_log() is called in tgs_parse_request() */
2340 goto out;
2342 if (ret) {
2343 kdc_log(context, config, 0,
2344 "Failed parsing TGS-REQ from %s", from);
2345 goto out;
2348 ret = tgs_build_reply(context,
2349 config,
2350 req,
2351 &req->req_body,
2352 krbtgt,
2353 krbtgt_etype,
2354 replykey,
2355 rk_is_subkey,
2356 ticket,
2357 data,
2358 from,
2359 &e_text,
2360 &auth_data,
2361 from_addr);
2362 if (ret) {
2363 kdc_log(context, config, 0,
2364 "Failed building TGS-REP to %s", from);
2365 goto out;
2368 /* */
2369 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2370 krb5_data_free(data);
2371 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2372 e_text = "Reply packet too large";
2375 out:
2376 if (replykey)
2377 krb5_free_keyblock(context, replykey);
2378 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2379 krb5_mk_error(context,
2380 ret,
2381 NULL,
2382 NULL,
2383 NULL,
2384 NULL,
2385 csec,
2386 cusec,
2387 data);
2388 ret = 0;
2390 free(csec);
2391 free(cusec);
2392 if (ticket)
2393 krb5_free_ticket(context, ticket);
2394 if(krbtgt)
2395 _kdc_free_ent(context, krbtgt);
2397 if (auth_data) {
2398 free_AuthorizationData(auth_data);
2399 free(auth_data);
2402 return ret;