krb5: reject referrals in capath code paths
[heimdal.git] / kdc / krb5tgs.c
blobbaa03309f4e12e59da9805ca82a24a1f4d8f06d0
1 /*
2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "kdc_locl.h"
37 * return the realm of a krbtgt-ticket or NULL
40 static Realm
41 get_krbtgt_realm(const PrincipalName *p)
43 if(p->name_string.len == 2
44 && strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0)
45 return p->name_string.val[1];
46 else
47 return NULL;
51 * The KDC might add a signed path to the ticket authorization data
52 * field. This is to avoid server impersonating clients and the
53 * request constrained delegation.
55 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
56 * entry of type KRB5SignedPath.
59 static krb5_error_code
60 find_KRB5SignedPath(krb5_context context,
61 const AuthorizationData *ad,
62 krb5_data *data)
64 AuthorizationData child;
65 krb5_error_code ret;
66 int pos;
68 if (ad == NULL || ad->len == 0)
69 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
71 pos = ad->len - 1;
73 if (ad->val[pos].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
74 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
76 ret = decode_AuthorizationData(ad->val[pos].ad_data.data,
77 ad->val[pos].ad_data.length,
78 &child,
79 NULL);
80 if (ret) {
81 krb5_set_error_message(context, ret, "Failed to decode "
82 "IF_RELEVANT with %d", ret);
83 return ret;
86 if (child.len != 1) {
87 free_AuthorizationData(&child);
88 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
91 if (child.val[0].ad_type != KRB5_AUTHDATA_SIGNTICKET) {
92 free_AuthorizationData(&child);
93 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
96 if (data)
97 ret = der_copy_octet_string(&child.val[0].ad_data, data);
98 free_AuthorizationData(&child);
99 return ret;
102 krb5_error_code
103 _kdc_add_KRB5SignedPath(krb5_context context,
104 krb5_kdc_configuration *config,
105 hdb_entry_ex *krbtgt,
106 krb5_enctype enctype,
107 krb5_principal client,
108 krb5_const_principal server,
109 krb5_principals principals,
110 EncTicketPart *tkt)
112 krb5_error_code ret;
113 KRB5SignedPath sp;
114 krb5_data data;
115 krb5_crypto crypto = NULL;
116 size_t size = 0;
118 if (server && principals) {
119 ret = add_Principals(principals, server);
120 if (ret)
121 return ret;
125 KRB5SignedPathData spd;
127 spd.client = client;
128 spd.authtime = tkt->authtime;
129 spd.delegated = principals;
130 spd.method_data = NULL;
132 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
133 &spd, &size, ret);
134 if (ret)
135 return ret;
136 if (data.length != size)
137 krb5_abortx(context, "internal asn.1 encoder error");
141 Key *key;
142 ret = hdb_enctype2key(context, &krbtgt->entry, NULL, enctype, &key);
143 if (ret == 0)
144 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
145 if (ret) {
146 free(data.data);
147 return ret;
152 * Fill in KRB5SignedPath
155 sp.etype = enctype;
156 sp.delegated = principals;
157 sp.method_data = NULL;
159 ret = krb5_create_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH, 0,
160 data.data, data.length, &sp.cksum);
161 krb5_crypto_destroy(context, crypto);
162 free(data.data);
163 if (ret)
164 return ret;
166 ASN1_MALLOC_ENCODE(KRB5SignedPath, data.data, data.length, &sp, &size, ret);
167 free_Checksum(&sp.cksum);
168 if (ret)
169 return ret;
170 if (data.length != size)
171 krb5_abortx(context, "internal asn.1 encoder error");
175 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
176 * authorization data field.
179 ret = _kdc_tkt_add_if_relevant_ad(context, tkt,
180 KRB5_AUTHDATA_SIGNTICKET, &data);
181 krb5_data_free(&data);
183 return ret;
186 static krb5_error_code
187 check_KRB5SignedPath(krb5_context context,
188 krb5_kdc_configuration *config,
189 hdb_entry_ex *krbtgt,
190 krb5_principal cp,
191 EncTicketPart *tkt,
192 krb5_principals *delegated,
193 int *signedpath)
195 krb5_error_code ret;
196 krb5_data data;
197 krb5_crypto crypto = NULL;
199 if (delegated)
200 *delegated = NULL;
202 ret = find_KRB5SignedPath(context, tkt->authorization_data, &data);
203 if (ret == 0) {
204 KRB5SignedPathData spd;
205 KRB5SignedPath sp;
206 size_t size = 0;
208 ret = decode_KRB5SignedPath(data.data, data.length, &sp, NULL);
209 krb5_data_free(&data);
210 if (ret)
211 return ret;
213 spd.client = cp;
214 spd.authtime = tkt->authtime;
215 spd.delegated = sp.delegated;
216 spd.method_data = sp.method_data;
218 ASN1_MALLOC_ENCODE(KRB5SignedPathData, data.data, data.length,
219 &spd, &size, ret);
220 if (ret) {
221 free_KRB5SignedPath(&sp);
222 return ret;
224 if (data.length != size)
225 krb5_abortx(context, "internal asn.1 encoder error");
228 Key *key;
229 ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use correct kvno! */
230 sp.etype, &key);
231 if (ret == 0)
232 ret = krb5_crypto_init(context, &key->key, 0, &crypto);
233 if (ret) {
234 free(data.data);
235 free_KRB5SignedPath(&sp);
236 return ret;
239 ret = krb5_verify_checksum(context, crypto, KRB5_KU_KRB5SIGNEDPATH,
240 data.data, data.length,
241 &sp.cksum);
242 krb5_crypto_destroy(context, crypto);
243 free(data.data);
244 if (ret) {
245 free_KRB5SignedPath(&sp);
246 kdc_log(context, config, 5,
247 "KRB5SignedPath not signed correctly, not marking as signed");
248 return 0;
251 if (delegated && sp.delegated) {
253 *delegated = malloc(sizeof(*sp.delegated));
254 if (*delegated == NULL) {
255 free_KRB5SignedPath(&sp);
256 return ENOMEM;
259 ret = copy_Principals(*delegated, sp.delegated);
260 if (ret) {
261 free_KRB5SignedPath(&sp);
262 free(*delegated);
263 *delegated = NULL;
264 return ret;
267 free_KRB5SignedPath(&sp);
269 *signedpath = 1;
272 return 0;
279 static krb5_error_code
280 check_PAC(krb5_context context,
281 krb5_kdc_configuration *config,
282 const krb5_principal client_principal,
283 const krb5_principal delegated_proxy_principal,
284 hdb_entry_ex *client,
285 hdb_entry_ex *server,
286 hdb_entry_ex *krbtgt,
287 const EncryptionKey *server_check_key,
288 const EncryptionKey *krbtgt_check_key,
289 const EncryptionKey *server_sign_key,
290 const EncryptionKey *krbtgt_sign_key,
291 EncTicketPart *tkt,
292 krb5_data *rspac,
293 int *signedpath)
295 AuthorizationData *ad = tkt->authorization_data;
296 unsigned i, j;
297 krb5_error_code ret;
299 if (ad == NULL || ad->len == 0)
300 return 0;
302 for (i = 0; i < ad->len; i++) {
303 AuthorizationData child;
305 if (ad->val[i].ad_type != KRB5_AUTHDATA_IF_RELEVANT)
306 continue;
308 ret = decode_AuthorizationData(ad->val[i].ad_data.data,
309 ad->val[i].ad_data.length,
310 &child,
311 NULL);
312 if (ret) {
313 krb5_set_error_message(context, ret, "Failed to decode "
314 "IF_RELEVANT with %d", ret);
315 return ret;
317 for (j = 0; j < child.len; j++) {
319 if (child.val[j].ad_type == KRB5_AUTHDATA_WIN2K_PAC) {
320 int signed_pac = 0;
321 krb5_pac pac;
323 /* Found PAC */
324 ret = krb5_pac_parse(context,
325 child.val[j].ad_data.data,
326 child.val[j].ad_data.length,
327 &pac);
328 free_AuthorizationData(&child);
329 if (ret)
330 return ret;
332 ret = krb5_pac_verify(context, pac, tkt->authtime,
333 client_principal,
334 server_check_key, krbtgt_check_key);
335 if (ret) {
336 krb5_pac_free(context, pac);
337 return ret;
340 ret = _kdc_pac_verify(context, client_principal,
341 delegated_proxy_principal,
342 client, server, krbtgt, &pac, &signed_pac);
343 if (ret) {
344 krb5_pac_free(context, pac);
345 return ret;
349 * Only re-sign PAC if we could verify it with the PAC
350 * function. The no-verify case happens when we get in
351 * a PAC from cross realm from a Windows domain and
352 * that there is no PAC verification function.
354 if (signed_pac) {
355 *signedpath = 1;
356 ret = _krb5_pac_sign(context, pac, tkt->authtime,
357 client_principal,
358 server_sign_key, krbtgt_sign_key, rspac);
360 krb5_pac_free(context, pac);
362 return ret;
365 free_AuthorizationData(&child);
367 return 0;
374 static krb5_error_code
375 check_tgs_flags(krb5_context context,
376 krb5_kdc_configuration *config,
377 KDC_REQ_BODY *b, const EncTicketPart *tgt, EncTicketPart *et)
379 KDCOptions f = b->kdc_options;
381 if(f.validate){
382 if(!tgt->flags.invalid || tgt->starttime == NULL){
383 kdc_log(context, config, 0,
384 "Bad request to validate ticket");
385 return KRB5KDC_ERR_BADOPTION;
387 if(*tgt->starttime > kdc_time){
388 kdc_log(context, config, 0,
389 "Early request to validate ticket");
390 return KRB5KRB_AP_ERR_TKT_NYV;
392 /* XXX tkt = tgt */
393 et->flags.invalid = 0;
394 }else if(tgt->flags.invalid){
395 kdc_log(context, config, 0,
396 "Ticket-granting ticket has INVALID flag set");
397 return KRB5KRB_AP_ERR_TKT_INVALID;
400 if(f.forwardable){
401 if(!tgt->flags.forwardable){
402 kdc_log(context, config, 0,
403 "Bad request for forwardable ticket");
404 return KRB5KDC_ERR_BADOPTION;
406 et->flags.forwardable = 1;
408 if(f.forwarded){
409 if(!tgt->flags.forwardable){
410 kdc_log(context, config, 0,
411 "Request to forward non-forwardable ticket");
412 return KRB5KDC_ERR_BADOPTION;
414 et->flags.forwarded = 1;
415 et->caddr = b->addresses;
417 if(tgt->flags.forwarded)
418 et->flags.forwarded = 1;
420 if(f.proxiable){
421 if(!tgt->flags.proxiable){
422 kdc_log(context, config, 0,
423 "Bad request for proxiable ticket");
424 return KRB5KDC_ERR_BADOPTION;
426 et->flags.proxiable = 1;
428 if(f.proxy){
429 if(!tgt->flags.proxiable){
430 kdc_log(context, config, 0,
431 "Request to proxy non-proxiable ticket");
432 return KRB5KDC_ERR_BADOPTION;
434 et->flags.proxy = 1;
435 et->caddr = b->addresses;
437 if(tgt->flags.proxy)
438 et->flags.proxy = 1;
440 if(f.allow_postdate){
441 if(!tgt->flags.may_postdate){
442 kdc_log(context, config, 0,
443 "Bad request for post-datable ticket");
444 return KRB5KDC_ERR_BADOPTION;
446 et->flags.may_postdate = 1;
448 if(f.postdated){
449 if(!tgt->flags.may_postdate){
450 kdc_log(context, config, 0,
451 "Bad request for postdated ticket");
452 return KRB5KDC_ERR_BADOPTION;
454 if(b->from)
455 *et->starttime = *b->from;
456 et->flags.postdated = 1;
457 et->flags.invalid = 1;
458 }else if(b->from && *b->from > kdc_time + context->max_skew){
459 kdc_log(context, config, 0, "Ticket cannot be postdated");
460 return KRB5KDC_ERR_CANNOT_POSTDATE;
463 if(f.renewable){
464 if(!tgt->flags.renewable || tgt->renew_till == NULL){
465 kdc_log(context, config, 0,
466 "Bad request for renewable ticket");
467 return KRB5KDC_ERR_BADOPTION;
469 et->flags.renewable = 1;
470 ALLOC(et->renew_till);
471 _kdc_fix_time(&b->rtime);
472 *et->renew_till = *b->rtime;
474 if(f.renew){
475 time_t old_life;
476 if(!tgt->flags.renewable || tgt->renew_till == NULL){
477 kdc_log(context, config, 0,
478 "Request to renew non-renewable ticket");
479 return KRB5KDC_ERR_BADOPTION;
481 old_life = tgt->endtime;
482 if(tgt->starttime)
483 old_life -= *tgt->starttime;
484 else
485 old_life -= tgt->authtime;
486 et->endtime = *et->starttime + old_life;
487 if (et->renew_till != NULL)
488 et->endtime = min(*et->renew_till, et->endtime);
491 #if 0
492 /* checks for excess flags */
493 if(f.request_anonymous && !config->allow_anonymous){
494 kdc_log(context, config, 0,
495 "Request for anonymous ticket");
496 return KRB5KDC_ERR_BADOPTION;
498 #endif
499 return 0;
503 * Determine if constrained delegation is allowed from this client to this server
506 static krb5_error_code
507 check_constrained_delegation(krb5_context context,
508 krb5_kdc_configuration *config,
509 HDB *clientdb,
510 hdb_entry_ex *client,
511 hdb_entry_ex *server,
512 krb5_const_principal target)
514 const HDB_Ext_Constrained_delegation_acl *acl;
515 krb5_error_code ret;
516 size_t i;
519 * constrained_delegation (S4U2Proxy) only works within
520 * the same realm. We use the already canonicalized version
521 * of the principals here, while "target" is the principal
522 * provided by the client.
524 if(!krb5_realm_compare(context, client->entry.principal, server->entry.principal)) {
525 ret = KRB5KDC_ERR_BADOPTION;
526 kdc_log(context, config, 0,
527 "Bad request for constrained delegation");
528 return ret;
531 if (clientdb->hdb_check_constrained_delegation) {
532 ret = clientdb->hdb_check_constrained_delegation(context, clientdb, client, target);
533 if (ret == 0)
534 return 0;
535 } else {
536 /* if client delegates to itself, that ok */
537 if (krb5_principal_compare(context, client->entry.principal, server->entry.principal) == TRUE)
538 return 0;
540 ret = hdb_entry_get_ConstrainedDelegACL(&client->entry, &acl);
541 if (ret) {
542 krb5_clear_error_message(context);
543 return ret;
546 if (acl) {
547 for (i = 0; i < acl->len; i++) {
548 if (krb5_principal_compare(context, target, &acl->val[i]) == TRUE)
549 return 0;
552 ret = KRB5KDC_ERR_BADOPTION;
554 kdc_log(context, config, 0,
555 "Bad request for constrained delegation");
556 return ret;
560 * Determine if s4u2self is allowed from this client to this server
562 * For example, regardless of the principal being impersonated, if the
563 * 'client' and 'server' are the same, then it's safe.
566 static krb5_error_code
567 check_s4u2self(krb5_context context,
568 krb5_kdc_configuration *config,
569 HDB *clientdb,
570 hdb_entry_ex *client,
571 krb5_const_principal server)
573 krb5_error_code ret;
575 /* if client does a s4u2self to itself, that ok */
576 if (krb5_principal_compare(context, client->entry.principal, server) == TRUE)
577 return 0;
579 if (clientdb->hdb_check_s4u2self) {
580 ret = clientdb->hdb_check_s4u2self(context, clientdb, client, server);
581 if (ret == 0)
582 return 0;
583 } else {
584 ret = KRB5KDC_ERR_BADOPTION;
586 return ret;
593 static krb5_error_code
594 verify_flags (krb5_context context,
595 krb5_kdc_configuration *config,
596 const EncTicketPart *et,
597 const char *pstr)
599 if(et->endtime < kdc_time){
600 kdc_log(context, config, 0, "Ticket expired (%s)", pstr);
601 return KRB5KRB_AP_ERR_TKT_EXPIRED;
603 if(et->flags.invalid){
604 kdc_log(context, config, 0, "Ticket not valid (%s)", pstr);
605 return KRB5KRB_AP_ERR_TKT_NYV;
607 return 0;
614 static krb5_error_code
615 fix_transited_encoding(krb5_context context,
616 krb5_kdc_configuration *config,
617 krb5_boolean check_policy,
618 const TransitedEncoding *tr,
619 EncTicketPart *et,
620 const char *client_realm,
621 const char *server_realm,
622 const char *tgt_realm)
624 krb5_error_code ret = 0;
625 char **realms, **tmp;
626 unsigned int num_realms;
627 size_t i;
629 switch (tr->tr_type) {
630 case DOMAIN_X500_COMPRESS:
631 break;
632 case 0:
634 * Allow empty content of type 0 because that is was Microsoft
635 * generates in their TGT.
637 if (tr->contents.length == 0)
638 break;
639 kdc_log(context, config, 0,
640 "Transited type 0 with non empty content");
641 return KRB5KDC_ERR_TRTYPE_NOSUPP;
642 default:
643 kdc_log(context, config, 0,
644 "Unknown transited type: %u", tr->tr_type);
645 return KRB5KDC_ERR_TRTYPE_NOSUPP;
648 ret = krb5_domain_x500_decode(context,
649 tr->contents,
650 &realms,
651 &num_realms,
652 client_realm,
653 server_realm);
654 if(ret){
655 krb5_warn(context, ret,
656 "Decoding transited encoding");
657 return ret;
659 if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)) {
660 /* not us, so add the previous realm to transited set */
661 if (num_realms + 1 > UINT_MAX/sizeof(*realms)) {
662 ret = ERANGE;
663 goto free_realms;
665 tmp = realloc(realms, (num_realms + 1) * sizeof(*realms));
666 if(tmp == NULL){
667 ret = ENOMEM;
668 goto free_realms;
670 realms = tmp;
671 realms[num_realms] = strdup(tgt_realm);
672 if(realms[num_realms] == NULL){
673 ret = ENOMEM;
674 goto free_realms;
676 num_realms++;
678 if(num_realms == 0) {
679 if(strcmp(client_realm, server_realm))
680 kdc_log(context, config, 0,
681 "cross-realm %s -> %s", client_realm, server_realm);
682 } else {
683 size_t l = 0;
684 char *rs;
685 for(i = 0; i < num_realms; i++)
686 l += strlen(realms[i]) + 2;
687 rs = malloc(l);
688 if(rs != NULL) {
689 *rs = '\0';
690 for(i = 0; i < num_realms; i++) {
691 if(i > 0)
692 strlcat(rs, ", ", l);
693 strlcat(rs, realms[i], l);
695 kdc_log(context, config, 0,
696 "cross-realm %s -> %s via [%s]",
697 client_realm, server_realm, rs);
698 free(rs);
701 if(check_policy) {
702 ret = krb5_check_transited(context, client_realm,
703 server_realm,
704 realms, num_realms, NULL);
705 if(ret) {
706 krb5_warn(context, ret, "cross-realm %s -> %s",
707 client_realm, server_realm);
708 goto free_realms;
710 et->flags.transited_policy_checked = 1;
712 et->transited.tr_type = DOMAIN_X500_COMPRESS;
713 ret = krb5_domain_x500_encode(realms, num_realms, &et->transited.contents);
714 if(ret)
715 krb5_warn(context, ret, "Encoding transited encoding");
716 free_realms:
717 for(i = 0; i < num_realms; i++)
718 free(realms[i]);
719 free(realms);
720 return ret;
724 static krb5_error_code
725 tgs_make_reply(krb5_context context,
726 krb5_kdc_configuration *config,
727 KDC_REQ_BODY *b,
728 krb5_const_principal tgt_name,
729 const EncTicketPart *tgt,
730 const krb5_keyblock *replykey,
731 int rk_is_subkey,
732 const EncryptionKey *serverkey,
733 const krb5_keyblock *sessionkey,
734 krb5_kvno kvno,
735 AuthorizationData *auth_data,
736 hdb_entry_ex *server,
737 krb5_principal server_principal,
738 const char *server_name,
739 hdb_entry_ex *client,
740 krb5_principal client_principal,
741 hdb_entry_ex *krbtgt,
742 krb5_enctype krbtgt_etype,
743 krb5_principals spp,
744 const krb5_data *rspac,
745 const METHOD_DATA *enc_pa_data,
746 const char **e_text,
747 krb5_data *reply)
749 KDC_REP rep;
750 EncKDCRepPart ek;
751 EncTicketPart et;
752 KDCOptions f = b->kdc_options;
753 krb5_error_code ret;
754 int is_weak = 0;
756 memset(&rep, 0, sizeof(rep));
757 memset(&et, 0, sizeof(et));
758 memset(&ek, 0, sizeof(ek));
760 rep.pvno = 5;
761 rep.msg_type = krb_tgs_rep;
763 et.authtime = tgt->authtime;
764 _kdc_fix_time(&b->till);
765 et.endtime = min(tgt->endtime, *b->till);
766 ALLOC(et.starttime);
767 *et.starttime = kdc_time;
769 ret = check_tgs_flags(context, config, b, tgt, &et);
770 if(ret)
771 goto out;
773 /* We should check the transited encoding if:
774 1) the request doesn't ask not to be checked
775 2) globally enforcing a check
776 3) principal requires checking
777 4) we allow non-check per-principal, but principal isn't marked as allowing this
778 5) we don't globally allow this
781 #define GLOBAL_FORCE_TRANSITED_CHECK \
782 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
783 #define GLOBAL_ALLOW_PER_PRINCIPAL \
784 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
785 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
786 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
788 /* these will consult the database in future release */
789 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
790 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
792 ret = fix_transited_encoding(context, config,
793 !f.disable_transited_check ||
794 GLOBAL_FORCE_TRANSITED_CHECK ||
795 PRINCIPAL_FORCE_TRANSITED_CHECK(server) ||
796 !((GLOBAL_ALLOW_PER_PRINCIPAL &&
797 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server)) ||
798 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK),
799 &tgt->transited, &et,
800 krb5_principal_get_realm(context, client_principal),
801 krb5_principal_get_realm(context, server->entry.principal),
802 krb5_principal_get_realm(context, krbtgt->entry.principal));
803 if(ret)
804 goto out;
806 copy_Realm(&server_principal->realm, &rep.ticket.realm);
807 _krb5_principal2principalname(&rep.ticket.sname, server_principal);
808 copy_Realm(&tgt_name->realm, &rep.crealm);
810 if (f.request_anonymous)
811 _kdc_make_anonymous_principalname (&rep.cname);
812 else */
814 copy_PrincipalName(&tgt_name->name, &rep.cname);
815 rep.ticket.tkt_vno = 5;
817 ek.caddr = et.caddr;
818 if(et.caddr == NULL)
819 et.caddr = tgt->caddr;
822 time_t life;
823 life = et.endtime - *et.starttime;
824 if(client && client->entry.max_life)
825 life = min(life, *client->entry.max_life);
826 if(server->entry.max_life)
827 life = min(life, *server->entry.max_life);
828 et.endtime = *et.starttime + life;
830 if(f.renewable_ok && tgt->flags.renewable &&
831 et.renew_till == NULL && et.endtime < *b->till &&
832 tgt->renew_till != NULL)
834 et.flags.renewable = 1;
835 ALLOC(et.renew_till);
836 *et.renew_till = *b->till;
838 if(et.renew_till){
839 time_t renew;
840 renew = *et.renew_till - *et.starttime;
841 if(client && client->entry.max_renew)
842 renew = min(renew, *client->entry.max_renew);
843 if(server->entry.max_renew)
844 renew = min(renew, *server->entry.max_renew);
845 *et.renew_till = *et.starttime + renew;
848 if(et.renew_till){
849 *et.renew_till = min(*et.renew_till, *tgt->renew_till);
850 *et.starttime = min(*et.starttime, *et.renew_till);
851 et.endtime = min(et.endtime, *et.renew_till);
854 *et.starttime = min(*et.starttime, et.endtime);
856 if(*et.starttime == et.endtime){
857 ret = KRB5KDC_ERR_NEVER_VALID;
858 goto out;
860 if(et.renew_till && et.endtime == *et.renew_till){
861 free(et.renew_till);
862 et.renew_till = NULL;
863 et.flags.renewable = 0;
866 et.flags.pre_authent = tgt->flags.pre_authent;
867 et.flags.hw_authent = tgt->flags.hw_authent;
868 et.flags.anonymous = tgt->flags.anonymous;
869 et.flags.ok_as_delegate = server->entry.flags.ok_as_delegate;
871 if(rspac->length) {
873 * No not need to filter out the any PAC from the
874 * auth_data since it's signed by the KDC.
876 ret = _kdc_tkt_add_if_relevant_ad(context, &et,
877 KRB5_AUTHDATA_WIN2K_PAC, rspac);
878 if (ret)
879 goto out;
882 if (auth_data) {
883 unsigned int i = 0;
885 /* XXX check authdata */
887 if (et.authorization_data == NULL) {
888 et.authorization_data = calloc(1, sizeof(*et.authorization_data));
889 if (et.authorization_data == NULL) {
890 ret = ENOMEM;
891 krb5_set_error_message(context, ret, "malloc: out of memory");
892 goto out;
895 for(i = 0; i < auth_data->len ; i++) {
896 ret = add_AuthorizationData(et.authorization_data, &auth_data->val[i]);
897 if (ret) {
898 krb5_set_error_message(context, ret, "malloc: out of memory");
899 goto out;
903 /* Filter out type KRB5SignedPath */
904 ret = find_KRB5SignedPath(context, et.authorization_data, NULL);
905 if (ret == 0) {
906 if (et.authorization_data->len == 1) {
907 free_AuthorizationData(et.authorization_data);
908 free(et.authorization_data);
909 et.authorization_data = NULL;
910 } else {
911 AuthorizationData *ad = et.authorization_data;
912 free_AuthorizationDataElement(&ad->val[ad->len - 1]);
913 ad->len--;
918 ret = krb5_copy_keyblock_contents(context, sessionkey, &et.key);
919 if (ret)
920 goto out;
921 et.crealm = tgt_name->realm;
922 et.cname = tgt_name->name;
924 ek.key = et.key;
925 /* MIT must have at least one last_req */
926 ek.last_req.len = 1;
927 ek.last_req.val = calloc(1, sizeof(*ek.last_req.val));
928 if (ek.last_req.val == NULL) {
929 ret = ENOMEM;
930 goto out;
932 ek.nonce = b->nonce;
933 ek.flags = et.flags;
934 ek.authtime = et.authtime;
935 ek.starttime = et.starttime;
936 ek.endtime = et.endtime;
937 ek.renew_till = et.renew_till;
938 ek.srealm = rep.ticket.realm;
939 ek.sname = rep.ticket.sname;
941 _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime,
942 et.endtime, et.renew_till);
944 /* Don't sign cross realm tickets, they can't be checked anyway */
946 char *r = get_krbtgt_realm(&ek.sname);
948 if (r == NULL || strcmp(r, ek.srealm) == 0) {
949 ret = _kdc_add_KRB5SignedPath(context,
950 config,
951 krbtgt,
952 krbtgt_etype,
953 client_principal,
954 NULL,
955 spp,
956 &et);
957 if (ret)
958 goto out;
962 if (enc_pa_data->len) {
963 rep.padata = calloc(1, sizeof(*rep.padata));
964 if (rep.padata == NULL) {
965 ret = ENOMEM;
966 goto out;
968 ret = copy_METHOD_DATA(enc_pa_data, rep.padata);
969 if (ret)
970 goto out;
973 if (krb5_enctype_valid(context, serverkey->keytype) != 0
974 && _kdc_is_weak_exception(server->entry.principal, serverkey->keytype))
976 krb5_enctype_enable(context, serverkey->keytype);
977 is_weak = 1;
981 /* It is somewhat unclear where the etype in the following
982 encryption should come from. What we have is a session
983 key in the passed tgt, and a list of preferred etypes
984 *for the new ticket*. Should we pick the best possible
985 etype, given the keytype in the tgt, or should we look
986 at the etype list here as well? What if the tgt
987 session key is DES3 and we want a ticket with a (say)
988 CAST session key. Should the DES3 etype be added to the
989 etype list, even if we don't want a session key with
990 DES3? */
991 ret = _kdc_encode_reply(context, config, NULL, 0,
992 &rep, &et, &ek, serverkey->keytype,
993 kvno,
994 serverkey, 0, replykey, rk_is_subkey,
995 e_text, reply);
996 if (is_weak)
997 krb5_enctype_disable(context, serverkey->keytype);
999 out:
1000 free_TGS_REP(&rep);
1001 free_TransitedEncoding(&et.transited);
1002 if(et.starttime)
1003 free(et.starttime);
1004 if(et.renew_till)
1005 free(et.renew_till);
1006 if(et.authorization_data) {
1007 free_AuthorizationData(et.authorization_data);
1008 free(et.authorization_data);
1010 free_LastReq(&ek.last_req);
1011 memset(et.key.keyvalue.data, 0, et.key.keyvalue.length);
1012 free_EncryptionKey(&et.key);
1013 return ret;
1016 static krb5_error_code
1017 tgs_check_authenticator(krb5_context context,
1018 krb5_kdc_configuration *config,
1019 krb5_auth_context ac,
1020 KDC_REQ_BODY *b,
1021 const char **e_text,
1022 krb5_keyblock *key)
1024 krb5_authenticator auth;
1025 size_t len = 0;
1026 unsigned char *buf;
1027 size_t buf_size;
1028 krb5_error_code ret;
1029 krb5_crypto crypto;
1031 krb5_auth_con_getauthenticator(context, ac, &auth);
1032 if(auth->cksum == NULL){
1033 kdc_log(context, config, 0, "No authenticator in request");
1034 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1035 goto out;
1038 * according to RFC1510 it doesn't need to be keyed,
1039 * but according to the latest draft it needs to.
1041 if (
1042 #if 0
1043 !krb5_checksum_is_keyed(context, auth->cksum->cksumtype)
1045 #endif
1046 !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) {
1047 kdc_log(context, config, 0, "Bad checksum type in authenticator: %d",
1048 auth->cksum->cksumtype);
1049 ret = KRB5KRB_AP_ERR_INAPP_CKSUM;
1050 goto out;
1053 /* XXX should not re-encode this */
1054 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, b, &len, ret);
1055 if(ret){
1056 const char *msg = krb5_get_error_message(context, ret);
1057 kdc_log(context, config, 0, "Failed to encode KDC-REQ-BODY: %s", msg);
1058 krb5_free_error_message(context, msg);
1059 goto out;
1061 if(buf_size != len) {
1062 free(buf);
1063 kdc_log(context, config, 0, "Internal error in ASN.1 encoder");
1064 *e_text = "KDC internal error";
1065 ret = KRB5KRB_ERR_GENERIC;
1066 goto out;
1068 ret = krb5_crypto_init(context, key, 0, &crypto);
1069 if (ret) {
1070 const char *msg = krb5_get_error_message(context, ret);
1071 free(buf);
1072 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1073 krb5_free_error_message(context, msg);
1074 goto out;
1076 ret = krb5_verify_checksum(context,
1077 crypto,
1078 KRB5_KU_TGS_REQ_AUTH_CKSUM,
1079 buf,
1080 len,
1081 auth->cksum);
1082 free(buf);
1083 krb5_crypto_destroy(context, crypto);
1084 if(ret){
1085 const char *msg = krb5_get_error_message(context, ret);
1086 kdc_log(context, config, 0,
1087 "Failed to verify authenticator checksum: %s", msg);
1088 krb5_free_error_message(context, msg);
1090 out:
1091 free_Authenticator(auth);
1092 free(auth);
1093 return ret;
1100 static const char *
1101 find_rpath(krb5_context context, Realm crealm, Realm srealm)
1103 const char *new_realm = krb5_config_get_string(context,
1104 NULL,
1105 "capaths",
1106 crealm,
1107 srealm,
1108 NULL);
1109 return new_realm;
1113 static krb5_boolean
1114 need_referral(krb5_context context, krb5_kdc_configuration *config,
1115 const KDCOptions * const options, krb5_principal server,
1116 krb5_realm **realms)
1118 const char *name;
1120 if(!options->canonicalize && server->name.name_type != KRB5_NT_SRV_INST)
1121 return FALSE;
1123 if (server->name.name_string.len == 1)
1124 name = server->name.name_string.val[0];
1125 else if (server->name.name_string.len == 3 &&
1126 strcasecmp("E3514235-4B06-11D1-AB04-00C04FC2DCD2", server->name.name_string.val[0]) == 0) {
1128 This is used to give referrals for the
1129 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
1130 SPN form, which is used for inter-domain communication in AD
1132 name = server->name.name_string.val[2];
1133 kdc_log(context, config, 0, "Giving 3 part DRSUAPI referral for %s", name);
1134 *realms = malloc(sizeof(char *)*2);
1135 if (*realms == NULL) {
1136 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
1137 return FALSE;
1139 (*realms)[0] = strdup(name);
1140 (*realms)[1] = NULL;
1141 return TRUE;
1142 } else if (server->name.name_string.len > 1)
1143 name = server->name.name_string.val[1];
1144 else
1145 return FALSE;
1147 kdc_log(context, config, 0, "Searching referral for %s", name);
1149 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1152 static krb5_error_code
1153 tgs_parse_request(krb5_context context,
1154 krb5_kdc_configuration *config,
1155 KDC_REQ_BODY *b,
1156 const PA_DATA *tgs_req,
1157 hdb_entry_ex **krbtgt,
1158 krb5_enctype *krbtgt_etype,
1159 krb5_ticket **ticket,
1160 const char **e_text,
1161 const char *from,
1162 const struct sockaddr *from_addr,
1163 time_t **csec,
1164 int **cusec,
1165 AuthorizationData **auth_data,
1166 krb5_keyblock **replykey,
1167 int *rk_is_subkey)
1169 static char failed[] = "<unparse_name failed>";
1170 krb5_ap_req ap_req;
1171 krb5_error_code ret;
1172 krb5_principal princ;
1173 krb5_auth_context ac = NULL;
1174 krb5_flags ap_req_options;
1175 krb5_flags verify_ap_req_flags;
1176 krb5_crypto crypto;
1177 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1178 krb5uint32 krbtgt_kvno_try;
1179 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
1180 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1181 Key *tkey;
1182 krb5_keyblock *subkey = NULL;
1183 unsigned usage;
1185 *auth_data = NULL;
1186 *csec = NULL;
1187 *cusec = NULL;
1188 *replykey = NULL;
1190 memset(&ap_req, 0, sizeof(ap_req));
1191 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1192 if(ret){
1193 const char *msg = krb5_get_error_message(context, ret);
1194 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1195 krb5_free_error_message(context, msg);
1196 goto out;
1199 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1200 /* XXX check for ticket.sname == req.sname */
1201 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1202 ret = KRB5KDC_ERR_POLICY; /* ? */
1203 goto out;
1206 _krb5_principalname2krb5_principal(context,
1207 &princ,
1208 ap_req.ticket.sname,
1209 ap_req.ticket.realm);
1211 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1212 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
1213 &krbtgt_kvno, NULL, krbtgt);
1215 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1216 /* XXX Factor out this unparsing of the same princ all over */
1217 char *p;
1218 ret = krb5_unparse_name(context, princ, &p);
1219 if (ret != 0)
1220 p = failed;
1221 krb5_free_principal(context, princ);
1222 kdc_log(context, config, 5,
1223 "Ticket-granting ticket account %s does not have secrets at "
1224 "this KDC, need to proxy", p);
1225 if (ret == 0)
1226 free(p);
1227 ret = HDB_ERR_NOT_FOUND_HERE;
1228 goto out;
1229 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1230 char *p;
1231 ret = krb5_unparse_name(context, princ, &p);
1232 if (ret != 0)
1233 p = failed;
1234 krb5_free_principal(context, princ);
1235 kdc_log(context, config, 5,
1236 "Ticket-granting ticket account %s does not have keys for "
1237 "kvno %d at this KDC", p, krbtgt_kvno);
1238 if (ret == 0)
1239 free(p);
1240 ret = HDB_ERR_KVNO_NOT_FOUND;
1241 goto out;
1242 } else if (ret == HDB_ERR_NO_MKEY) {
1243 char *p;
1244 ret = krb5_unparse_name(context, princ, &p);
1245 if (ret != 0)
1246 p = failed;
1247 krb5_free_principal(context, princ);
1248 kdc_log(context, config, 5,
1249 "Missing master key for decrypting keys for ticket-granting "
1250 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1251 if (ret == 0)
1252 free(p);
1253 ret = HDB_ERR_KVNO_NOT_FOUND;
1254 goto out;
1255 } else if (ret) {
1256 const char *msg = krb5_get_error_message(context, ret);
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, 0,
1263 "Ticket-granting ticket not found in database: %s", msg);
1264 krb5_free_error_message(context, msg);
1265 if (ret == 0)
1266 free(p);
1267 ret = KRB5KRB_AP_ERR_NOT_US;
1268 goto out;
1271 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1272 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1274 next_kvno:
1275 krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
1276 ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
1277 ap_req.ticket.enc_part.etype, &tkey);
1278 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1279 kvno_search_tries--;
1280 krbtgt_kvno_try--;
1281 goto next_kvno;
1282 } else if (ret) {
1283 char *str = NULL, *p = NULL;
1285 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1286 krb5_unparse_name(context, princ, &p);
1287 kdc_log(context, config, 0,
1288 "No server key with enctype %s found for %s",
1289 str ? str : "<unknown enctype>",
1290 p ? p : "<unparse_name failed>");
1291 free(str);
1292 free(p);
1293 ret = KRB5KRB_AP_ERR_BADKEYVER;
1294 goto out;
1297 if (b->kdc_options.validate)
1298 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1299 else
1300 verify_ap_req_flags = 0;
1302 ret = krb5_verify_ap_req2(context,
1303 &ac,
1304 &ap_req,
1305 princ,
1306 &tkey->key,
1307 verify_ap_req_flags,
1308 &ap_req_options,
1309 ticket,
1310 KRB5_KU_TGS_REQ_AUTH);
1311 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1312 kvno_search_tries--;
1313 krbtgt_kvno_try--;
1314 goto next_kvno;
1317 krb5_free_principal(context, princ);
1318 if(ret) {
1319 const char *msg = krb5_get_error_message(context, ret);
1320 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1321 krb5_free_error_message(context, msg);
1322 goto out;
1326 krb5_authenticator auth;
1328 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1329 if (ret == 0) {
1330 *csec = malloc(sizeof(**csec));
1331 if (*csec == NULL) {
1332 krb5_free_authenticator(context, &auth);
1333 kdc_log(context, config, 0, "malloc failed");
1334 goto out;
1336 **csec = auth->ctime;
1337 *cusec = malloc(sizeof(**cusec));
1338 if (*cusec == NULL) {
1339 krb5_free_authenticator(context, &auth);
1340 kdc_log(context, config, 0, "malloc failed");
1341 goto out;
1343 **cusec = auth->cusec;
1344 krb5_free_authenticator(context, &auth);
1348 ret = tgs_check_authenticator(context, config,
1349 ac, b, e_text, &(*ticket)->ticket.key);
1350 if (ret) {
1351 krb5_auth_con_free(context, ac);
1352 goto out;
1355 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1356 *rk_is_subkey = 1;
1358 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1359 if(ret){
1360 const char *msg = krb5_get_error_message(context, ret);
1361 krb5_auth_con_free(context, ac);
1362 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1363 krb5_free_error_message(context, msg);
1364 goto out;
1366 if(subkey == NULL){
1367 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1368 *rk_is_subkey = 0;
1370 ret = krb5_auth_con_getkey(context, ac, &subkey);
1371 if(ret) {
1372 const char *msg = krb5_get_error_message(context, ret);
1373 krb5_auth_con_free(context, ac);
1374 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1375 krb5_free_error_message(context, msg);
1376 goto out;
1379 if(subkey == NULL){
1380 krb5_auth_con_free(context, ac);
1381 kdc_log(context, config, 0,
1382 "Failed to get key for enc-authorization-data");
1383 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1384 goto out;
1387 *replykey = subkey;
1389 if (b->enc_authorization_data) {
1390 krb5_data ad;
1392 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1393 if (ret) {
1394 const char *msg = krb5_get_error_message(context, ret);
1395 krb5_auth_con_free(context, ac);
1396 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1397 krb5_free_error_message(context, msg);
1398 goto out;
1400 ret = krb5_decrypt_EncryptedData (context,
1401 crypto,
1402 usage,
1403 b->enc_authorization_data,
1404 &ad);
1405 krb5_crypto_destroy(context, crypto);
1406 if(ret){
1407 krb5_auth_con_free(context, ac);
1408 kdc_log(context, config, 0,
1409 "Failed to decrypt enc-authorization-data");
1410 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1411 goto out;
1413 ALLOC(*auth_data);
1414 if (*auth_data == NULL) {
1415 krb5_auth_con_free(context, ac);
1416 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1417 goto out;
1419 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1420 if(ret){
1421 krb5_auth_con_free(context, ac);
1422 free(*auth_data);
1423 *auth_data = NULL;
1424 kdc_log(context, config, 0, "Failed to decode authorization data");
1425 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1426 goto out;
1430 krb5_auth_con_free(context, ac);
1432 out:
1433 free_AP_REQ(&ap_req);
1435 return ret;
1438 static krb5_error_code
1439 build_server_referral(krb5_context context,
1440 krb5_kdc_configuration *config,
1441 krb5_crypto session,
1442 krb5_const_realm referred_realm,
1443 const PrincipalName *true_principal_name,
1444 const PrincipalName *requested_principal,
1445 krb5_data *outdata)
1447 PA_ServerReferralData ref;
1448 krb5_error_code ret;
1449 EncryptedData ed;
1450 krb5_data data;
1451 size_t size = 0;
1453 memset(&ref, 0, sizeof(ref));
1455 if (referred_realm) {
1456 ALLOC(ref.referred_realm);
1457 if (ref.referred_realm == NULL)
1458 goto eout;
1459 *ref.referred_realm = strdup(referred_realm);
1460 if (*ref.referred_realm == NULL)
1461 goto eout;
1463 if (true_principal_name) {
1464 ALLOC(ref.true_principal_name);
1465 if (ref.true_principal_name == NULL)
1466 goto eout;
1467 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1468 if (ret)
1469 goto eout;
1471 if (requested_principal) {
1472 ALLOC(ref.requested_principal_name);
1473 if (ref.requested_principal_name == NULL)
1474 goto eout;
1475 ret = copy_PrincipalName(requested_principal,
1476 ref.requested_principal_name);
1477 if (ret)
1478 goto eout;
1481 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1482 data.data, data.length,
1483 &ref, &size, ret);
1484 free_PA_ServerReferralData(&ref);
1485 if (ret)
1486 return ret;
1487 if (data.length != size)
1488 krb5_abortx(context, "internal asn.1 encoder error");
1490 ret = krb5_encrypt_EncryptedData(context, session,
1491 KRB5_KU_PA_SERVER_REFERRAL,
1492 data.data, data.length,
1493 0 /* kvno */, &ed);
1494 free(data.data);
1495 if (ret)
1496 return ret;
1498 ASN1_MALLOC_ENCODE(EncryptedData,
1499 outdata->data, outdata->length,
1500 &ed, &size, ret);
1501 free_EncryptedData(&ed);
1502 if (ret)
1503 return ret;
1504 if (outdata->length != size)
1505 krb5_abortx(context, "internal asn.1 encoder error");
1507 return 0;
1508 eout:
1509 free_PA_ServerReferralData(&ref);
1510 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1511 return ENOMEM;
1514 static krb5_error_code
1515 tgs_build_reply(krb5_context context,
1516 krb5_kdc_configuration *config,
1517 KDC_REQ *req,
1518 KDC_REQ_BODY *b,
1519 hdb_entry_ex *krbtgt,
1520 krb5_enctype krbtgt_etype,
1521 const krb5_keyblock *replykey,
1522 int rk_is_subkey,
1523 krb5_ticket *ticket,
1524 krb5_data *reply,
1525 const char *from,
1526 const char **e_text,
1527 AuthorizationData **auth_data,
1528 const struct sockaddr *from_addr)
1530 krb5_error_code ret;
1531 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1532 krb5_principal krbtgt_out_principal = NULL;
1533 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1534 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1535 HDB *clientdb, *s4u2self_impersonated_clientdb;
1536 krb5_realm ref_realm = NULL;
1537 EncTicketPart *tgt = &ticket->ticket;
1538 krb5_principals spp = NULL;
1539 const EncryptionKey *ekey;
1540 krb5_keyblock sessionkey;
1541 krb5_kvno kvno;
1542 krb5_data rspac;
1544 hdb_entry_ex *krbtgt_out = NULL;
1546 METHOD_DATA enc_pa_data;
1548 PrincipalName *s;
1549 Realm r;
1550 int nloop = 0;
1551 EncTicketPart adtkt;
1552 char opt_str[128];
1553 int signedpath = 0;
1555 Key *tkey_check;
1556 Key *tkey_sign;
1557 Key *tkey_krbtgt_check = NULL;
1558 int flags = HDB_F_FOR_TGS_REQ;
1560 memset(&sessionkey, 0, sizeof(sessionkey));
1561 memset(&adtkt, 0, sizeof(adtkt));
1562 krb5_data_zero(&rspac);
1563 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1565 s = b->sname;
1566 r = b->realm;
1569 * Always to do CANON, see comment below about returned server principal (rsp).
1571 flags |= HDB_F_CANON;
1573 if(b->kdc_options.enc_tkt_in_skey){
1574 Ticket *t;
1575 hdb_entry_ex *uu;
1576 krb5_principal p;
1577 Key *uukey;
1579 if(b->additional_tickets == NULL ||
1580 b->additional_tickets->len == 0){
1581 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1582 kdc_log(context, config, 0,
1583 "No second ticket present in request");
1584 goto out;
1586 t = &b->additional_tickets->val[0];
1587 if(!get_krbtgt_realm(&t->sname)){
1588 kdc_log(context, config, 0,
1589 "Additional ticket is not a ticket-granting ticket");
1590 ret = KRB5KDC_ERR_POLICY;
1591 goto out;
1593 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1594 ret = _kdc_db_fetch(context, config, p,
1595 HDB_F_GET_KRBTGT, t->enc_part.kvno,
1596 NULL, &uu);
1597 krb5_free_principal(context, p);
1598 if(ret){
1599 if (ret == HDB_ERR_NOENTRY)
1600 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1601 goto out;
1603 ret = hdb_enctype2key(context, &uu->entry, NULL,
1604 t->enc_part.etype, &uukey);
1605 if(ret){
1606 _kdc_free_ent(context, uu);
1607 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1608 goto out;
1610 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1611 _kdc_free_ent(context, uu);
1612 if(ret)
1613 goto out;
1615 ret = verify_flags(context, config, &adtkt, spn);
1616 if (ret)
1617 goto out;
1619 s = &adtkt.cname;
1620 r = adtkt.crealm;
1623 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1624 ret = krb5_unparse_name(context, sp, &spn);
1625 if (ret)
1626 goto out;
1627 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1628 ret = krb5_unparse_name(context, cp, &cpn);
1629 if (ret)
1630 goto out;
1631 unparse_flags (KDCOptions2int(b->kdc_options),
1632 asn1_KDCOptions_units(),
1633 opt_str, sizeof(opt_str));
1634 if(*opt_str)
1635 kdc_log(context, config, 0,
1636 "TGS-REQ %s from %s for %s [%s]",
1637 cpn, from, spn, opt_str);
1638 else
1639 kdc_log(context, config, 0,
1640 "TGS-REQ %s from %s for %s", cpn, from, spn);
1643 * Fetch server
1646 server_lookup:
1647 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1648 NULL, NULL, &server);
1650 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1651 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1652 goto out;
1653 } else if(ret){
1654 const char *new_rlm, *msg;
1655 Realm req_rlm;
1656 krb5_realm *realms;
1658 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1659 if(nloop++ < 2) {
1660 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1661 if(new_rlm) {
1662 kdc_log(context, config, 5, "krbtgt for realm %s "
1663 "not found, trying %s",
1664 req_rlm, new_rlm);
1665 krb5_free_principal(context, sp);
1666 free(spn);
1667 krb5_make_principal(context, &sp, r,
1668 KRB5_TGS_NAME, new_rlm, NULL);
1669 ret = krb5_unparse_name(context, sp, &spn);
1670 if (ret)
1671 goto out;
1673 if (ref_realm)
1674 free(ref_realm);
1675 ref_realm = strdup(new_rlm);
1676 goto server_lookup;
1679 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1680 if (strcmp(realms[0], sp->realm) != 0) {
1681 kdc_log(context, config, 5,
1682 "Returning a referral to realm %s for "
1683 "server %s that was not found",
1684 realms[0], spn);
1685 krb5_free_principal(context, sp);
1686 free(spn);
1687 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1688 realms[0], NULL);
1689 ret = krb5_unparse_name(context, sp, &spn);
1690 if (ret)
1691 goto out;
1693 if (ref_realm)
1694 free(ref_realm);
1695 ref_realm = strdup(realms[0]);
1697 krb5_free_host_realm(context, realms);
1698 goto server_lookup;
1700 krb5_free_host_realm(context, realms);
1702 msg = krb5_get_error_message(context, ret);
1703 kdc_log(context, config, 0,
1704 "Server not found in database: %s: %s", spn, msg);
1705 krb5_free_error_message(context, msg);
1706 if (ret == HDB_ERR_NOENTRY)
1707 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1708 goto out;
1711 /* the name returned to the client depend on what was asked for,
1712 * return canonical name if kdc_options.canonicalize was set, the
1713 * client wants the true name of the principal, if not it just
1714 * wants the name its asked for.
1717 if (b->kdc_options.canonicalize)
1718 rsp = server->entry.principal;
1719 else
1720 rsp = sp;
1724 * Select enctype, return key and kvno.
1728 krb5_enctype etype;
1730 if(b->kdc_options.enc_tkt_in_skey) {
1731 size_t i;
1732 ekey = &adtkt.key;
1733 for(i = 0; i < b->etype.len; i++)
1734 if (b->etype.val[i] == adtkt.key.keytype)
1735 break;
1736 if(i == b->etype.len) {
1737 kdc_log(context, config, 0,
1738 "Addition ticket have not matching etypes");
1739 krb5_clear_error_message(context);
1740 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1741 goto out;
1743 etype = b->etype.val[i];
1744 kvno = 0;
1745 } else {
1746 Key *skey;
1748 ret = _kdc_find_etype(context,
1749 krb5_principal_is_krbtgt(context, sp) ?
1750 config->tgt_use_strongest_session_key :
1751 config->svc_use_strongest_session_key, FALSE,
1752 server, b->etype.val, b->etype.len, &etype,
1753 NULL);
1754 if(ret) {
1755 kdc_log(context, config, 0,
1756 "Server (%s) has no support for etypes", spn);
1757 goto out;
1759 ret = _kdc_get_preferred_key(context, config, server, spn,
1760 NULL, &skey);
1761 if(ret) {
1762 kdc_log(context, config, 0,
1763 "Server (%s) has no supported etypes", spn);
1764 goto out;
1766 ekey = &skey->key;
1767 kvno = server->entry.kvno;
1770 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1771 if (ret)
1772 goto out;
1776 * Check that service is in the same realm as the krbtgt. If it's
1777 * not the same, it's someone that is using a uni-directional trust
1778 * backward.
1782 * Validate authoriation data
1785 ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1786 krbtgt_etype, &tkey_check);
1787 if(ret) {
1788 kdc_log(context, config, 0,
1789 "Failed to find key for krbtgt PAC check");
1790 goto out;
1794 * Now refetch the primary krbtgt, and get the current kvno (the
1795 * sign check may have been on an old kvno, and the server may
1796 * have been an incoming trust)
1800 const char *remote_realm =
1801 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1803 ret = krb5_make_principal(context,
1804 &krbtgt_out_principal,
1805 remote_realm,
1806 KRB5_TGS_NAME,
1807 remote_realm,
1808 NULL);
1809 if(ret) {
1810 kdc_log(context, config, 0,
1811 "Failed to make krbtgt principal name object for "
1812 "authz-data signatures");
1813 goto out;
1815 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1816 if (ret) {
1817 kdc_log(context, config, 0,
1818 "Failed to make krbtgt principal name object for "
1819 "authz-data signatures");
1820 goto out;
1824 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1825 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1826 if (ret) {
1827 char *ktpn = NULL;
1828 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1829 kdc_log(context, config, 0,
1830 "No such principal %s (needed for authz-data signature keys) "
1831 "while processing TGS-REQ for service %s with krbtg %s",
1832 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1833 free(ktpn);
1834 ret = KRB5KRB_AP_ERR_NOT_US;
1835 goto out;
1839 * The first realm is the realm of the service, the second is
1840 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1841 * encrypted to. The redirection via the krbtgt_out entry allows
1842 * the DB to possibly correct the case of the realm (Samba4 does
1843 * this) before the strcmp()
1845 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1846 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1847 char *ktpn;
1848 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1849 kdc_log(context, config, 0,
1850 "Request with wrong krbtgt: %s",
1851 (ret == 0) ? ktpn : "<unknown>");
1852 if(ret == 0)
1853 free(ktpn);
1854 ret = KRB5KRB_AP_ERR_NOT_US;
1855 goto out;
1858 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1859 NULL, &tkey_sign);
1860 if (ret) {
1861 kdc_log(context, config, 0,
1862 "Failed to find key for krbtgt PAC signature");
1863 goto out;
1865 ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1866 tkey_sign->key.keytype, &tkey_sign);
1867 if(ret) {
1868 kdc_log(context, config, 0,
1869 "Failed to find key for krbtgt PAC signature");
1870 goto out;
1874 * Check if we would know the krbtgt key for the PAC. We would
1875 * only know this if the krbtgt principal was the same (ie, in our
1876 * realm, regardless of KVNO)
1879 if (krb5_principal_compare(context, krbtgt_out->entry.principal, krbtgt->entry.principal))
1880 tkey_krbtgt_check = tkey_check;
1883 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1884 NULL, &clientdb, &client);
1885 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1886 /* This is OK, we are just trying to find out if they have
1887 * been disabled or deleted in the meantime, missing secrets
1888 * is OK */
1889 } else if(ret){
1890 const char *krbtgt_realm, *msg;
1893 * If the client belongs to the same realm as our krbtgt, it
1894 * should exist in the local database.
1898 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1900 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1901 if (ret == HDB_ERR_NOENTRY)
1902 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1903 kdc_log(context, config, 1, "Client no longer in database: %s",
1904 cpn);
1905 goto out;
1908 msg = krb5_get_error_message(context, ret);
1909 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1910 krb5_free_error_message(context, msg);
1913 ret = check_PAC(context, config, cp, NULL,
1914 client, server, krbtgt,
1915 &tkey_check->key,
1916 tkey_krbtgt_check ? &tkey_krbtgt_check->key : NULL,
1917 ekey, &tkey_sign->key,
1918 tgt, &rspac, &signedpath);
1919 if (ret) {
1920 const char *msg = krb5_get_error_message(context, ret);
1921 kdc_log(context, config, 0,
1922 "Verify PAC failed for %s (%s) from %s with %s",
1923 spn, cpn, from, msg);
1924 krb5_free_error_message(context, msg);
1925 goto out;
1928 /* also check the krbtgt for signature */
1929 ret = check_KRB5SignedPath(context,
1930 config,
1931 krbtgt,
1933 tgt,
1934 &spp,
1935 &signedpath);
1936 if (ret) {
1937 const char *msg = krb5_get_error_message(context, ret);
1938 kdc_log(context, config, 0,
1939 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1940 spn, cpn, from, msg);
1941 krb5_free_error_message(context, msg);
1942 goto out;
1946 * Process request
1949 /* by default the tgt principal matches the client principal */
1950 tp = cp;
1951 tpn = cpn;
1953 if (client) {
1954 const PA_DATA *sdata;
1955 int i = 0;
1957 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1958 if (sdata) {
1959 krb5_crypto crypto;
1960 krb5_data datack;
1961 PA_S4U2Self self;
1962 const char *str;
1964 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1965 sdata->padata_value.length,
1966 &self, NULL);
1967 if (ret) {
1968 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1969 goto out;
1972 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1973 if (ret)
1974 goto out;
1976 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1977 if (ret) {
1978 const char *msg = krb5_get_error_message(context, ret);
1979 free_PA_S4U2Self(&self);
1980 krb5_data_free(&datack);
1981 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1982 krb5_free_error_message(context, msg);
1983 goto out;
1986 ret = krb5_verify_checksum(context,
1987 crypto,
1988 KRB5_KU_OTHER_CKSUM,
1989 datack.data,
1990 datack.length,
1991 &self.cksum);
1992 krb5_data_free(&datack);
1993 krb5_crypto_destroy(context, crypto);
1994 if (ret) {
1995 const char *msg = krb5_get_error_message(context, ret);
1996 free_PA_S4U2Self(&self);
1997 kdc_log(context, config, 0,
1998 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1999 krb5_free_error_message(context, msg);
2000 goto out;
2003 ret = _krb5_principalname2krb5_principal(context,
2004 &tp,
2005 self.name,
2006 self.realm);
2007 free_PA_S4U2Self(&self);
2008 if (ret)
2009 goto out;
2011 ret = krb5_unparse_name(context, tp, &tpn);
2012 if (ret)
2013 goto out;
2015 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2016 if(rspac.data) {
2017 krb5_pac p = NULL;
2018 krb5_data_free(&rspac);
2019 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2020 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
2021 if (ret) {
2022 const char *msg;
2025 * If the client belongs to the same realm as our krbtgt, it
2026 * should exist in the local database.
2030 if (ret == HDB_ERR_NOENTRY)
2031 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2032 msg = krb5_get_error_message(context, ret);
2033 kdc_log(context, config, 1,
2034 "S2U4Self principal to impersonate %s not found in database: %s",
2035 tpn, msg);
2036 krb5_free_error_message(context, msg);
2037 goto out;
2039 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2040 if (ret) {
2041 kdc_log(context, config, 0, "PAC generation failed for -- %s",
2042 tpn);
2043 goto out;
2045 if (p != NULL) {
2046 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2047 s4u2self_impersonated_client->entry.principal,
2048 ekey, &tkey_sign->key,
2049 &rspac);
2050 krb5_pac_free(context, p);
2051 if (ret) {
2052 kdc_log(context, config, 0, "PAC signing failed for -- %s",
2053 tpn);
2054 goto out;
2060 * Check that service doing the impersonating is
2061 * requesting a ticket to it-self.
2063 ret = check_s4u2self(context, config, clientdb, client, sp);
2064 if (ret) {
2065 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2066 "to impersonate to service "
2067 "(tried for user %s to service %s)",
2068 cpn, tpn, spn);
2069 goto out;
2073 * If the service isn't trusted for authentication to
2074 * delegation, remove the forward flag.
2077 if (client->entry.flags.trusted_for_delegation) {
2078 str = "[forwardable]";
2079 } else {
2080 b->kdc_options.forwardable = 0;
2081 str = "";
2083 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2084 "service %s %s", cpn, tpn, spn, str);
2089 * Constrained delegation
2092 if (client != NULL
2093 && b->additional_tickets != NULL
2094 && b->additional_tickets->len != 0
2095 && b->kdc_options.enc_tkt_in_skey == 0)
2097 int ad_signedpath = 0;
2098 Key *clientkey;
2099 Ticket *t;
2102 * Require that the KDC have issued the service's krbtgt (not
2103 * self-issued ticket with kimpersonate(1).
2105 if (!signedpath) {
2106 ret = KRB5KDC_ERR_BADOPTION;
2107 kdc_log(context, config, 0,
2108 "Constrained delegation done on service ticket %s/%s",
2109 cpn, spn);
2110 goto out;
2113 t = &b->additional_tickets->val[0];
2115 ret = hdb_enctype2key(context, &client->entry,
2116 hdb_kvno2keys(context, &client->entry,
2117 t->enc_part.kvno ? * t->enc_part.kvno : 0),
2118 t->enc_part.etype, &clientkey);
2119 if(ret){
2120 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2121 goto out;
2124 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2125 if (ret) {
2126 kdc_log(context, config, 0,
2127 "failed to decrypt ticket for "
2128 "constrained delegation from %s to %s ", cpn, spn);
2129 goto out;
2132 ret = _krb5_principalname2krb5_principal(context,
2133 &tp,
2134 adtkt.cname,
2135 adtkt.crealm);
2136 if (ret)
2137 goto out;
2139 ret = krb5_unparse_name(context, tp, &tpn);
2140 if (ret)
2141 goto out;
2143 ret = _krb5_principalname2krb5_principal(context,
2144 &dp,
2145 t->sname,
2146 t->realm);
2147 if (ret)
2148 goto out;
2150 ret = krb5_unparse_name(context, dp, &dpn);
2151 if (ret)
2152 goto out;
2154 /* check that ticket is valid */
2155 if (adtkt.flags.forwardable == 0) {
2156 kdc_log(context, config, 0,
2157 "Missing forwardable flag on ticket for "
2158 "constrained delegation from %s (%s) as %s to %s ",
2159 cpn, dpn, tpn, spn);
2160 ret = KRB5KDC_ERR_BADOPTION;
2161 goto out;
2164 ret = check_constrained_delegation(context, config, clientdb,
2165 client, server, sp);
2166 if (ret) {
2167 kdc_log(context, config, 0,
2168 "constrained delegation from %s (%s) as %s to %s not allowed",
2169 cpn, dpn, tpn, spn);
2170 goto out;
2173 ret = verify_flags(context, config, &adtkt, tpn);
2174 if (ret) {
2175 goto out;
2178 krb5_data_free(&rspac);
2181 * generate the PAC for the user.
2183 * TODO: pass in t->sname and t->realm and build
2184 * a S4U_DELEGATION_INFO blob to the PAC.
2186 ret = check_PAC(context, config, tp, dp,
2187 client, server, krbtgt,
2188 &clientkey->key, &tkey_check->key,
2189 ekey, &tkey_sign->key,
2190 &adtkt, &rspac, &ad_signedpath);
2191 if (ret) {
2192 const char *msg = krb5_get_error_message(context, ret);
2193 kdc_log(context, config, 0,
2194 "Verify delegated PAC failed to %s for client"
2195 "%s (%s) as %s from %s with %s",
2196 spn, cpn, dpn, tpn, from, msg);
2197 krb5_free_error_message(context, msg);
2198 goto out;
2202 * Check that the KDC issued the user's ticket.
2204 ret = check_KRB5SignedPath(context,
2205 config,
2206 krbtgt,
2208 &adtkt,
2209 NULL,
2210 &ad_signedpath);
2211 if (ret) {
2212 const char *msg = krb5_get_error_message(context, ret);
2213 kdc_log(context, config, 0,
2214 "KRB5SignedPath check from service %s failed "
2215 "for delegation to %s for client %s (%s)"
2216 "from %s failed with %s",
2217 spn, tpn, dpn, cpn, from, msg);
2218 krb5_free_error_message(context, msg);
2219 goto out;
2222 if (!ad_signedpath) {
2223 ret = KRB5KDC_ERR_BADOPTION;
2224 kdc_log(context, config, 0,
2225 "Ticket not signed with PAC nor SignedPath service %s failed "
2226 "for delegation to %s for client %s (%s)"
2227 "from %s",
2228 spn, tpn, dpn, cpn, from);
2229 goto out;
2232 kdc_log(context, config, 0, "constrained delegation for %s "
2233 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2237 * Check flags
2240 ret = kdc_check_flags(context, config,
2241 client, cpn,
2242 server, spn,
2243 FALSE);
2244 if(ret)
2245 goto out;
2247 if((b->kdc_options.validate || b->kdc_options.renew) &&
2248 !krb5_principal_compare(context,
2249 krbtgt->entry.principal,
2250 server->entry.principal)){
2251 kdc_log(context, config, 0, "Inconsistent request.");
2252 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2253 goto out;
2256 /* check for valid set of addresses */
2257 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2258 ret = KRB5KRB_AP_ERR_BADADDR;
2259 kdc_log(context, config, 0, "Request from wrong address");
2260 goto out;
2264 * If this is an referral, add server referral data to the
2265 * auth_data reply .
2267 if (ref_realm) {
2268 PA_DATA pa;
2269 krb5_crypto crypto;
2271 kdc_log(context, config, 0,
2272 "Adding server referral to %s", ref_realm);
2274 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2275 if (ret)
2276 goto out;
2278 ret = build_server_referral(context, config, crypto, ref_realm,
2279 NULL, s, &pa.padata_value);
2280 krb5_crypto_destroy(context, crypto);
2281 if (ret) {
2282 kdc_log(context, config, 0,
2283 "Failed building server referral");
2284 goto out;
2286 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2288 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2289 krb5_data_free(&pa.padata_value);
2290 if (ret) {
2291 kdc_log(context, config, 0,
2292 "Add server referral METHOD-DATA failed");
2293 goto out;
2301 ret = tgs_make_reply(context,
2302 config,
2305 tgt,
2306 replykey,
2307 rk_is_subkey,
2308 ekey,
2309 &sessionkey,
2310 kvno,
2311 *auth_data,
2312 server,
2313 rsp,
2314 spn,
2315 client,
2317 krbtgt_out,
2318 tkey_sign->key.keytype,
2319 spp,
2320 &rspac,
2321 &enc_pa_data,
2322 e_text,
2323 reply);
2325 out:
2326 if (tpn != cpn)
2327 free(tpn);
2328 free(spn);
2329 free(cpn);
2330 free(dpn);
2331 free(krbtgt_out_n);
2333 krb5_data_free(&rspac);
2334 krb5_free_keyblock_contents(context, &sessionkey);
2335 if(krbtgt_out)
2336 _kdc_free_ent(context, krbtgt_out);
2337 if(server)
2338 _kdc_free_ent(context, server);
2339 if(client)
2340 _kdc_free_ent(context, client);
2341 if(s4u2self_impersonated_client)
2342 _kdc_free_ent(context, s4u2self_impersonated_client);
2344 if (tp && tp != cp)
2345 krb5_free_principal(context, tp);
2346 krb5_free_principal(context, cp);
2347 krb5_free_principal(context, dp);
2348 krb5_free_principal(context, sp);
2349 krb5_free_principal(context, krbtgt_out_principal);
2350 if (ref_realm)
2351 free(ref_realm);
2352 free_METHOD_DATA(&enc_pa_data);
2354 free_EncTicketPart(&adtkt);
2356 return ret;
2363 krb5_error_code
2364 _kdc_tgs_rep(krb5_context context,
2365 krb5_kdc_configuration *config,
2366 KDC_REQ *req,
2367 krb5_data *data,
2368 const char *from,
2369 struct sockaddr *from_addr,
2370 int datagram_reply)
2372 AuthorizationData *auth_data = NULL;
2373 krb5_error_code ret;
2374 int i = 0;
2375 const PA_DATA *tgs_req;
2377 hdb_entry_ex *krbtgt = NULL;
2378 krb5_ticket *ticket = NULL;
2379 const char *e_text = NULL;
2380 krb5_enctype krbtgt_etype = ETYPE_NULL;
2382 krb5_keyblock *replykey = NULL;
2383 int rk_is_subkey = 0;
2384 time_t *csec = NULL;
2385 int *cusec = NULL;
2387 if(req->padata == NULL){
2388 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2389 kdc_log(context, config, 0,
2390 "TGS-REQ from %s without PA-DATA", from);
2391 goto out;
2394 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2396 if(tgs_req == NULL){
2397 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2399 kdc_log(context, config, 0,
2400 "TGS-REQ from %s without PA-TGS-REQ", from);
2401 goto out;
2403 ret = tgs_parse_request(context, config,
2404 &req->req_body, tgs_req,
2405 &krbtgt,
2406 &krbtgt_etype,
2407 &ticket,
2408 &e_text,
2409 from, from_addr,
2410 &csec, &cusec,
2411 &auth_data,
2412 &replykey,
2413 &rk_is_subkey);
2414 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2415 /* kdc_log() is called in tgs_parse_request() */
2416 goto out;
2418 if (ret) {
2419 kdc_log(context, config, 0,
2420 "Failed parsing TGS-REQ from %s", from);
2421 goto out;
2425 const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2426 if (pa)
2427 kdc_log(context, config, 10, "Got TGS FAST request");
2431 ret = tgs_build_reply(context,
2432 config,
2433 req,
2434 &req->req_body,
2435 krbtgt,
2436 krbtgt_etype,
2437 replykey,
2438 rk_is_subkey,
2439 ticket,
2440 data,
2441 from,
2442 &e_text,
2443 &auth_data,
2444 from_addr);
2445 if (ret) {
2446 kdc_log(context, config, 0,
2447 "Failed building TGS-REP to %s", from);
2448 goto out;
2451 /* */
2452 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2453 krb5_data_free(data);
2454 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2455 e_text = "Reply packet too large";
2458 out:
2459 if (replykey)
2460 krb5_free_keyblock(context, replykey);
2462 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2463 /* XXX add fast wrapping on the error */
2464 METHOD_DATA error_method = { 0, NULL };
2467 kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2468 ret = _kdc_fast_mk_error(context, NULL,
2469 &error_method,
2470 NULL,
2471 NULL,
2472 ret, NULL,
2473 NULL, NULL,
2474 csec, cusec,
2475 data);
2476 free_METHOD_DATA(&error_method);
2478 free(csec);
2479 free(cusec);
2480 if (ticket)
2481 krb5_free_ticket(context, ticket);
2482 if(krbtgt)
2483 _kdc_free_ent(context, krbtgt);
2485 if (auth_data) {
2486 free_AuthorizationData(auth_data);
2487 free(auth_data);
2490 return ret;