use right directory
[heimdal.git] / kdc / krb5tgs.c
blobbe42b1ab2545d2df55b00fa0a15f5d9e81dda05b
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.authtime;
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.authtime + 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, et.key.keytype) != 0
974 && _kdc_is_weak_exception(server->entry.principal, et.key.keytype))
976 krb5_enctype_enable(context, et.key.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, et.key.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 > 1)
1126 name = server->name.name_string.val[1];
1127 else
1128 return FALSE;
1130 kdc_log(context, config, 0, "Searching referral for %s", name);
1132 return _krb5_get_host_realm_int(context, name, FALSE, realms) == 0;
1135 static krb5_error_code
1136 tgs_parse_request(krb5_context context,
1137 krb5_kdc_configuration *config,
1138 KDC_REQ_BODY *b,
1139 const PA_DATA *tgs_req,
1140 hdb_entry_ex **krbtgt,
1141 krb5_enctype *krbtgt_etype,
1142 krb5_ticket **ticket,
1143 const char **e_text,
1144 const char *from,
1145 const struct sockaddr *from_addr,
1146 time_t **csec,
1147 int **cusec,
1148 AuthorizationData **auth_data,
1149 krb5_keyblock **replykey,
1150 int *rk_is_subkey)
1152 static char failed[] = "<unparse_name failed>";
1153 krb5_ap_req ap_req;
1154 krb5_error_code ret;
1155 krb5_principal princ;
1156 krb5_auth_context ac = NULL;
1157 krb5_flags ap_req_options;
1158 krb5_flags verify_ap_req_flags;
1159 krb5_crypto crypto;
1160 krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1161 krb5uint32 krbtgt_kvno_try;
1162 int kvno_search_tries = 4; /* number of kvnos to try when tkt_vno == 0 */
1163 const Keys *krbtgt_keys;/* keyset for TGT tkt_vno */
1164 Key *tkey;
1165 krb5_keyblock *subkey = NULL;
1166 unsigned usage;
1168 *auth_data = NULL;
1169 *csec = NULL;
1170 *cusec = NULL;
1171 *replykey = NULL;
1173 memset(&ap_req, 0, sizeof(ap_req));
1174 ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
1175 if(ret){
1176 const char *msg = krb5_get_error_message(context, ret);
1177 kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", msg);
1178 krb5_free_error_message(context, msg);
1179 goto out;
1182 if(!get_krbtgt_realm(&ap_req.ticket.sname)){
1183 /* XXX check for ticket.sname == req.sname */
1184 kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
1185 ret = KRB5KDC_ERR_POLICY; /* ? */
1186 goto out;
1189 _krb5_principalname2krb5_principal(context,
1190 &princ,
1191 ap_req.ticket.sname,
1192 ap_req.ticket.realm);
1194 krbtgt_kvno = ap_req.ticket.enc_part.kvno ? *ap_req.ticket.enc_part.kvno : 0;
1195 ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT,
1196 &krbtgt_kvno, NULL, krbtgt);
1197 krbtgt_kvno_try = krbtgt_kvno ? krbtgt_kvno : (*krbtgt)->entry.kvno;
1199 if (ret == HDB_ERR_NOT_FOUND_HERE) {
1200 /* XXX Factor out this unparsing of the same princ all over */
1201 char *p;
1202 ret = krb5_unparse_name(context, princ, &p);
1203 if (ret != 0)
1204 p = failed;
1205 krb5_free_principal(context, princ);
1206 kdc_log(context, config, 5,
1207 "Ticket-granting ticket account %s does not have secrets at "
1208 "this KDC, need to proxy", p);
1209 if (ret == 0)
1210 free(p);
1211 ret = HDB_ERR_NOT_FOUND_HERE;
1212 goto out;
1213 } else if (ret == HDB_ERR_KVNO_NOT_FOUND) {
1214 char *p;
1215 ret = krb5_unparse_name(context, princ, &p);
1216 if (ret != 0)
1217 p = failed;
1218 krb5_free_principal(context, princ);
1219 kdc_log(context, config, 5,
1220 "Ticket-granting ticket account %s does not have keys for "
1221 "kvno %d at this KDC", p, krbtgt_kvno);
1222 if (ret == 0)
1223 free(p);
1224 ret = HDB_ERR_KVNO_NOT_FOUND;
1225 goto out;
1226 } else if (ret == HDB_ERR_NO_MKEY) {
1227 char *p;
1228 ret = krb5_unparse_name(context, princ, &p);
1229 if (ret != 0)
1230 p = failed;
1231 krb5_free_principal(context, princ);
1232 kdc_log(context, config, 5,
1233 "Missing master key for decrypting keys for ticket-granting "
1234 "ticket account %s with kvno %d at this KDC", p, krbtgt_kvno);
1235 if (ret == 0)
1236 free(p);
1237 ret = HDB_ERR_KVNO_NOT_FOUND;
1238 goto out;
1239 } else if (ret) {
1240 const char *msg = krb5_get_error_message(context, ret);
1241 char *p;
1242 ret = krb5_unparse_name(context, princ, &p);
1243 if (ret != 0)
1244 p = failed;
1245 krb5_free_principal(context, princ);
1246 kdc_log(context, config, 0,
1247 "Ticket-granting ticket not found in database: %s", msg);
1248 krb5_free_error_message(context, msg);
1249 if (ret == 0)
1250 free(p);
1251 ret = KRB5KRB_AP_ERR_NOT_US;
1252 goto out;
1255 *krbtgt_etype = ap_req.ticket.enc_part.etype;
1257 next_kvno:
1258 krbtgt_keys = hdb_kvno2keys(context, &(*krbtgt)->entry, krbtgt_kvno_try);
1259 ret = hdb_enctype2key(context, &(*krbtgt)->entry, krbtgt_keys,
1260 ap_req.ticket.enc_part.etype, &tkey);
1261 if (ret && krbtgt_kvno == 0 && kvno_search_tries > 0) {
1262 kvno_search_tries--;
1263 krbtgt_kvno_try--;
1264 goto next_kvno;
1265 } else if (ret) {
1266 char *str = NULL, *p = NULL;
1268 krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
1269 krb5_unparse_name(context, princ, &p);
1270 kdc_log(context, config, 0,
1271 "No server key with enctype %s found for %s",
1272 str ? str : "<unknown enctype>",
1273 p ? p : "<unparse_name failed>");
1274 free(str);
1275 free(p);
1276 ret = KRB5KRB_AP_ERR_BADKEYVER;
1277 goto out;
1280 if (b->kdc_options.validate)
1281 verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
1282 else
1283 verify_ap_req_flags = 0;
1285 ret = krb5_verify_ap_req2(context,
1286 &ac,
1287 &ap_req,
1288 princ,
1289 &tkey->key,
1290 verify_ap_req_flags,
1291 &ap_req_options,
1292 ticket,
1293 KRB5_KU_TGS_REQ_AUTH);
1294 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) {
1295 kvno_search_tries--;
1296 krbtgt_kvno_try--;
1297 goto next_kvno;
1300 krb5_free_principal(context, princ);
1301 if(ret) {
1302 const char *msg = krb5_get_error_message(context, ret);
1303 kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", msg);
1304 krb5_free_error_message(context, msg);
1305 goto out;
1309 krb5_authenticator auth;
1311 ret = krb5_auth_con_getauthenticator(context, ac, &auth);
1312 if (ret == 0) {
1313 *csec = malloc(sizeof(**csec));
1314 if (*csec == NULL) {
1315 krb5_free_authenticator(context, &auth);
1316 kdc_log(context, config, 0, "malloc failed");
1317 goto out;
1319 **csec = auth->ctime;
1320 *cusec = malloc(sizeof(**cusec));
1321 if (*cusec == NULL) {
1322 krb5_free_authenticator(context, &auth);
1323 kdc_log(context, config, 0, "malloc failed");
1324 goto out;
1326 **cusec = auth->cusec;
1327 krb5_free_authenticator(context, &auth);
1331 ret = tgs_check_authenticator(context, config,
1332 ac, b, e_text, &(*ticket)->ticket.key);
1333 if (ret) {
1334 krb5_auth_con_free(context, ac);
1335 goto out;
1338 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY;
1339 *rk_is_subkey = 1;
1341 ret = krb5_auth_con_getremotesubkey(context, ac, &subkey);
1342 if(ret){
1343 const char *msg = krb5_get_error_message(context, ret);
1344 krb5_auth_con_free(context, ac);
1345 kdc_log(context, config, 0, "Failed to get remote subkey: %s", msg);
1346 krb5_free_error_message(context, msg);
1347 goto out;
1349 if(subkey == NULL){
1350 usage = KRB5_KU_TGS_REQ_AUTH_DAT_SESSION;
1351 *rk_is_subkey = 0;
1353 ret = krb5_auth_con_getkey(context, ac, &subkey);
1354 if(ret) {
1355 const char *msg = krb5_get_error_message(context, ret);
1356 krb5_auth_con_free(context, ac);
1357 kdc_log(context, config, 0, "Failed to get session key: %s", msg);
1358 krb5_free_error_message(context, msg);
1359 goto out;
1362 if(subkey == NULL){
1363 krb5_auth_con_free(context, ac);
1364 kdc_log(context, config, 0,
1365 "Failed to get key for enc-authorization-data");
1366 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1367 goto out;
1370 *replykey = subkey;
1372 if (b->enc_authorization_data) {
1373 krb5_data ad;
1375 ret = krb5_crypto_init(context, subkey, 0, &crypto);
1376 if (ret) {
1377 const char *msg = krb5_get_error_message(context, ret);
1378 krb5_auth_con_free(context, ac);
1379 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1380 krb5_free_error_message(context, msg);
1381 goto out;
1383 ret = krb5_decrypt_EncryptedData (context,
1384 crypto,
1385 usage,
1386 b->enc_authorization_data,
1387 &ad);
1388 krb5_crypto_destroy(context, crypto);
1389 if(ret){
1390 krb5_auth_con_free(context, ac);
1391 kdc_log(context, config, 0,
1392 "Failed to decrypt enc-authorization-data");
1393 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1394 goto out;
1396 ALLOC(*auth_data);
1397 if (*auth_data == NULL) {
1398 krb5_auth_con_free(context, ac);
1399 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1400 goto out;
1402 ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
1403 if(ret){
1404 krb5_auth_con_free(context, ac);
1405 free(*auth_data);
1406 *auth_data = NULL;
1407 kdc_log(context, config, 0, "Failed to decode authorization data");
1408 ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
1409 goto out;
1413 krb5_auth_con_free(context, ac);
1415 out:
1416 free_AP_REQ(&ap_req);
1418 return ret;
1421 static krb5_error_code
1422 build_server_referral(krb5_context context,
1423 krb5_kdc_configuration *config,
1424 krb5_crypto session,
1425 krb5_const_realm referred_realm,
1426 const PrincipalName *true_principal_name,
1427 const PrincipalName *requested_principal,
1428 krb5_data *outdata)
1430 PA_ServerReferralData ref;
1431 krb5_error_code ret;
1432 EncryptedData ed;
1433 krb5_data data;
1434 size_t size = 0;
1436 memset(&ref, 0, sizeof(ref));
1438 if (referred_realm) {
1439 ALLOC(ref.referred_realm);
1440 if (ref.referred_realm == NULL)
1441 goto eout;
1442 *ref.referred_realm = strdup(referred_realm);
1443 if (*ref.referred_realm == NULL)
1444 goto eout;
1446 if (true_principal_name) {
1447 ALLOC(ref.true_principal_name);
1448 if (ref.true_principal_name == NULL)
1449 goto eout;
1450 ret = copy_PrincipalName(true_principal_name, ref.true_principal_name);
1451 if (ret)
1452 goto eout;
1454 if (requested_principal) {
1455 ALLOC(ref.requested_principal_name);
1456 if (ref.requested_principal_name == NULL)
1457 goto eout;
1458 ret = copy_PrincipalName(requested_principal,
1459 ref.requested_principal_name);
1460 if (ret)
1461 goto eout;
1464 ASN1_MALLOC_ENCODE(PA_ServerReferralData,
1465 data.data, data.length,
1466 &ref, &size, ret);
1467 free_PA_ServerReferralData(&ref);
1468 if (ret)
1469 return ret;
1470 if (data.length != size)
1471 krb5_abortx(context, "internal asn.1 encoder error");
1473 ret = krb5_encrypt_EncryptedData(context, session,
1474 KRB5_KU_PA_SERVER_REFERRAL,
1475 data.data, data.length,
1476 0 /* kvno */, &ed);
1477 free(data.data);
1478 if (ret)
1479 return ret;
1481 ASN1_MALLOC_ENCODE(EncryptedData,
1482 outdata->data, outdata->length,
1483 &ed, &size, ret);
1484 free_EncryptedData(&ed);
1485 if (ret)
1486 return ret;
1487 if (outdata->length != size)
1488 krb5_abortx(context, "internal asn.1 encoder error");
1490 return 0;
1491 eout:
1492 free_PA_ServerReferralData(&ref);
1493 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1494 return ENOMEM;
1497 static krb5_error_code
1498 tgs_build_reply(krb5_context context,
1499 krb5_kdc_configuration *config,
1500 KDC_REQ *req,
1501 KDC_REQ_BODY *b,
1502 hdb_entry_ex *krbtgt,
1503 krb5_enctype krbtgt_etype,
1504 const krb5_keyblock *replykey,
1505 int rk_is_subkey,
1506 krb5_ticket *ticket,
1507 krb5_data *reply,
1508 const char *from,
1509 const char **e_text,
1510 AuthorizationData **auth_data,
1511 const struct sockaddr *from_addr)
1513 krb5_error_code ret;
1514 krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL;
1515 krb5_principal krbtgt_out_principal = NULL;
1516 char *spn = NULL, *cpn = NULL, *tpn = NULL, *dpn = NULL, *krbtgt_out_n = NULL;
1517 hdb_entry_ex *server = NULL, *client = NULL, *s4u2self_impersonated_client = NULL;
1518 HDB *clientdb, *s4u2self_impersonated_clientdb;
1519 krb5_realm ref_realm = NULL;
1520 EncTicketPart *tgt = &ticket->ticket;
1521 krb5_principals spp = NULL;
1522 const EncryptionKey *ekey;
1523 krb5_keyblock sessionkey;
1524 krb5_kvno kvno;
1525 krb5_data rspac;
1527 hdb_entry_ex *krbtgt_out = NULL;
1529 METHOD_DATA enc_pa_data;
1531 PrincipalName *s;
1532 Realm r;
1533 int nloop = 0;
1534 EncTicketPart adtkt;
1535 char opt_str[128];
1536 int signedpath = 0;
1538 Key *tkey_check;
1539 Key *tkey_sign;
1540 Key *tkey_krbtgt_check = NULL;
1541 int flags = HDB_F_FOR_TGS_REQ;
1543 memset(&sessionkey, 0, sizeof(sessionkey));
1544 memset(&adtkt, 0, sizeof(adtkt));
1545 krb5_data_zero(&rspac);
1546 memset(&enc_pa_data, 0, sizeof(enc_pa_data));
1548 s = b->sname;
1549 r = b->realm;
1552 * Always to do CANON, see comment below about returned server principal (rsp).
1554 flags |= HDB_F_CANON;
1556 if(b->kdc_options.enc_tkt_in_skey){
1557 Ticket *t;
1558 hdb_entry_ex *uu;
1559 krb5_principal p;
1560 Key *uukey;
1562 if(b->additional_tickets == NULL ||
1563 b->additional_tickets->len == 0){
1564 ret = KRB5KDC_ERR_BADOPTION; /* ? */
1565 kdc_log(context, config, 0,
1566 "No second ticket present in request");
1567 goto out;
1569 t = &b->additional_tickets->val[0];
1570 if(!get_krbtgt_realm(&t->sname)){
1571 kdc_log(context, config, 0,
1572 "Additional ticket is not a ticket-granting ticket");
1573 ret = KRB5KDC_ERR_POLICY;
1574 goto out;
1576 _krb5_principalname2krb5_principal(context, &p, t->sname, t->realm);
1577 ret = _kdc_db_fetch(context, config, p,
1578 HDB_F_GET_KRBTGT, t->enc_part.kvno,
1579 NULL, &uu);
1580 krb5_free_principal(context, p);
1581 if(ret){
1582 if (ret == HDB_ERR_NOENTRY)
1583 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1584 goto out;
1586 ret = hdb_enctype2key(context, &uu->entry, NULL,
1587 t->enc_part.etype, &uukey);
1588 if(ret){
1589 _kdc_free_ent(context, uu);
1590 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
1591 goto out;
1593 ret = krb5_decrypt_ticket(context, t, &uukey->key, &adtkt, 0);
1594 _kdc_free_ent(context, uu);
1595 if(ret)
1596 goto out;
1598 ret = verify_flags(context, config, &adtkt, spn);
1599 if (ret)
1600 goto out;
1602 s = &adtkt.cname;
1603 r = adtkt.crealm;
1606 _krb5_principalname2krb5_principal(context, &sp, *s, r);
1607 ret = krb5_unparse_name(context, sp, &spn);
1608 if (ret)
1609 goto out;
1610 _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm);
1611 ret = krb5_unparse_name(context, cp, &cpn);
1612 if (ret)
1613 goto out;
1614 unparse_flags (KDCOptions2int(b->kdc_options),
1615 asn1_KDCOptions_units(),
1616 opt_str, sizeof(opt_str));
1617 if(*opt_str)
1618 kdc_log(context, config, 0,
1619 "TGS-REQ %s from %s for %s [%s]",
1620 cpn, from, spn, opt_str);
1621 else
1622 kdc_log(context, config, 0,
1623 "TGS-REQ %s from %s for %s", cpn, from, spn);
1626 * Fetch server
1629 server_lookup:
1630 ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags,
1631 NULL, NULL, &server);
1633 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1634 kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", sp);
1635 goto out;
1636 } else if(ret){
1637 const char *new_rlm, *msg;
1638 Realm req_rlm;
1639 krb5_realm *realms;
1641 if ((req_rlm = get_krbtgt_realm(&sp->name)) != NULL) {
1642 if(nloop++ < 2) {
1643 new_rlm = find_rpath(context, tgt->crealm, req_rlm);
1644 if(new_rlm) {
1645 kdc_log(context, config, 5, "krbtgt for realm %s "
1646 "not found, trying %s",
1647 req_rlm, new_rlm);
1648 krb5_free_principal(context, sp);
1649 free(spn);
1650 krb5_make_principal(context, &sp, r,
1651 KRB5_TGS_NAME, new_rlm, NULL);
1652 ret = krb5_unparse_name(context, sp, &spn);
1653 if (ret)
1654 goto out;
1656 if (ref_realm)
1657 free(ref_realm);
1658 ref_realm = strdup(new_rlm);
1659 goto server_lookup;
1662 } else if(need_referral(context, config, &b->kdc_options, sp, &realms)) {
1663 if (strcmp(realms[0], sp->realm) != 0) {
1664 kdc_log(context, config, 5,
1665 "Returning a referral to realm %s for "
1666 "server %s that was not found",
1667 realms[0], spn);
1668 krb5_free_principal(context, sp);
1669 free(spn);
1670 krb5_make_principal(context, &sp, r, KRB5_TGS_NAME,
1671 realms[0], NULL);
1672 ret = krb5_unparse_name(context, sp, &spn);
1673 if (ret)
1674 goto out;
1676 if (ref_realm)
1677 free(ref_realm);
1678 ref_realm = strdup(realms[0]);
1680 krb5_free_host_realm(context, realms);
1681 goto server_lookup;
1683 krb5_free_host_realm(context, realms);
1685 msg = krb5_get_error_message(context, ret);
1686 kdc_log(context, config, 0,
1687 "Server not found in database: %s: %s", spn, msg);
1688 krb5_free_error_message(context, msg);
1689 if (ret == HDB_ERR_NOENTRY)
1690 ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
1691 goto out;
1694 /* the name returned to the client depend on what was asked for,
1695 * return canonical name if kdc_options.canonicalize was set, the
1696 * client wants the true name of the principal, if not it just
1697 * wants the name its asked for.
1700 if (b->kdc_options.canonicalize)
1701 rsp = server->entry.principal;
1702 else
1703 rsp = sp;
1707 * Select enctype, return key and kvno.
1711 krb5_enctype etype;
1713 if(b->kdc_options.enc_tkt_in_skey) {
1714 size_t i;
1715 ekey = &adtkt.key;
1716 for(i = 0; i < b->etype.len; i++)
1717 if (b->etype.val[i] == adtkt.key.keytype)
1718 break;
1719 if(i == b->etype.len) {
1720 kdc_log(context, config, 0,
1721 "Addition ticket have not matching etypes");
1722 krb5_clear_error_message(context);
1723 ret = KRB5KDC_ERR_ETYPE_NOSUPP;
1724 goto out;
1726 etype = b->etype.val[i];
1727 kvno = 0;
1728 } else {
1729 Key *skey;
1731 ret = _kdc_find_etype(context,
1732 krb5_principal_is_krbtgt(context, sp) ?
1733 config->tgt_use_strongest_session_key :
1734 config->svc_use_strongest_session_key, FALSE,
1735 server, b->etype.val, b->etype.len, &etype,
1736 NULL);
1737 if(ret) {
1738 kdc_log(context, config, 0,
1739 "Server (%s) has no support for etypes", spn);
1740 goto out;
1742 ret = _kdc_get_preferred_key(context, config, server, spn,
1743 NULL, &skey);
1744 if(ret) {
1745 kdc_log(context, config, 0,
1746 "Server (%s) has no supported etypes", spn);
1747 goto out;
1749 ekey = &skey->key;
1750 kvno = server->entry.kvno;
1753 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1754 if (ret)
1755 goto out;
1759 * Check that service is in the same realm as the krbtgt. If it's
1760 * not the same, it's someone that is using a uni-directional trust
1761 * backward.
1765 * Validate authoriation data
1768 ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1769 krbtgt_etype, &tkey_check);
1770 if(ret) {
1771 kdc_log(context, config, 0,
1772 "Failed to find key for krbtgt PAC check");
1773 goto out;
1777 * Now refetch the primary krbtgt, and get the current kvno (the
1778 * sign check may have been on an old kvno, and the server may
1779 * have been an incoming trust)
1783 const char *remote_realm =
1784 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1786 ret = krb5_make_principal(context,
1787 &krbtgt_out_principal,
1788 remote_realm,
1789 KRB5_TGS_NAME,
1790 remote_realm,
1791 NULL);
1792 if(ret) {
1793 kdc_log(context, config, 0,
1794 "Failed to make krbtgt principal name object for "
1795 "authz-data signatures");
1796 goto out;
1798 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1799 if (ret) {
1800 kdc_log(context, config, 0,
1801 "Failed to make krbtgt principal name object for "
1802 "authz-data signatures");
1803 goto out;
1807 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1808 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1809 if (ret) {
1810 char *ktpn = NULL;
1811 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1812 kdc_log(context, config, 0,
1813 "No such principal %s (needed for authz-data signature keys) "
1814 "while processing TGS-REQ for service %s with krbtg %s",
1815 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1816 free(ktpn);
1817 ret = KRB5KRB_AP_ERR_NOT_US;
1818 goto out;
1822 * The first realm is the realm of the service, the second is
1823 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1824 * encrypted to. The redirection via the krbtgt_out entry allows
1825 * the DB to possibly correct the case of the realm (Samba4 does
1826 * this) before the strcmp()
1828 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1829 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1830 char *ktpn;
1831 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1832 kdc_log(context, config, 0,
1833 "Request with wrong krbtgt: %s",
1834 (ret == 0) ? ktpn : "<unknown>");
1835 if(ret == 0)
1836 free(ktpn);
1837 ret = KRB5KRB_AP_ERR_NOT_US;
1838 goto out;
1841 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1842 NULL, &tkey_sign);
1843 if (ret) {
1844 kdc_log(context, config, 0,
1845 "Failed to find key for krbtgt PAC signature");
1846 goto out;
1848 ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1849 tkey_sign->key.keytype, &tkey_sign);
1850 if(ret) {
1851 kdc_log(context, config, 0,
1852 "Failed to find key for krbtgt PAC signature");
1853 goto out;
1857 * Check if we would know the krbtgt key for the PAC. We would
1858 * only know this if the krbtgt principal was the same (ie, in our
1859 * realm, regardless of KVNO)
1862 if (krb5_principal_compare(context, krbtgt_out->entry.principal, krbtgt->entry.principal))
1863 tkey_krbtgt_check = tkey_check;
1866 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1867 NULL, &clientdb, &client);
1868 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1869 /* This is OK, we are just trying to find out if they have
1870 * been disabled or deleted in the meantime, missing secrets
1871 * is OK */
1872 } else if(ret){
1873 const char *krbtgt_realm, *msg;
1876 * If the client belongs to the same realm as our krbtgt, it
1877 * should exist in the local database.
1881 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1883 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1884 if (ret == HDB_ERR_NOENTRY)
1885 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1886 kdc_log(context, config, 1, "Client no longer in database: %s",
1887 cpn);
1888 goto out;
1891 msg = krb5_get_error_message(context, ret);
1892 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1893 krb5_free_error_message(context, msg);
1896 ret = check_PAC(context, config, cp, NULL,
1897 client, server, krbtgt,
1898 &tkey_check->key,
1899 tkey_krbtgt_check ? &tkey_krbtgt_check->key : NULL,
1900 ekey, &tkey_sign->key,
1901 tgt, &rspac, &signedpath);
1902 if (ret) {
1903 const char *msg = krb5_get_error_message(context, ret);
1904 kdc_log(context, config, 0,
1905 "Verify PAC failed for %s (%s) from %s with %s",
1906 spn, cpn, from, msg);
1907 krb5_free_error_message(context, msg);
1908 goto out;
1911 /* also check the krbtgt for signature */
1912 ret = check_KRB5SignedPath(context,
1913 config,
1914 krbtgt,
1916 tgt,
1917 &spp,
1918 &signedpath);
1919 if (ret) {
1920 const char *msg = krb5_get_error_message(context, ret);
1921 kdc_log(context, config, 0,
1922 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1923 spn, cpn, from, msg);
1924 krb5_free_error_message(context, msg);
1925 goto out;
1929 * Process request
1932 /* by default the tgt principal matches the client principal */
1933 tp = cp;
1934 tpn = cpn;
1936 if (client) {
1937 const PA_DATA *sdata;
1938 int i = 0;
1940 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1941 if (sdata) {
1942 krb5_crypto crypto;
1943 krb5_data datack;
1944 PA_S4U2Self self;
1945 const char *str;
1947 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1948 sdata->padata_value.length,
1949 &self, NULL);
1950 if (ret) {
1951 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1952 goto out;
1955 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1956 if (ret)
1957 goto out;
1959 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1960 if (ret) {
1961 const char *msg = krb5_get_error_message(context, ret);
1962 free_PA_S4U2Self(&self);
1963 krb5_data_free(&datack);
1964 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1965 krb5_free_error_message(context, msg);
1966 goto out;
1969 ret = krb5_verify_checksum(context,
1970 crypto,
1971 KRB5_KU_OTHER_CKSUM,
1972 datack.data,
1973 datack.length,
1974 &self.cksum);
1975 krb5_data_free(&datack);
1976 krb5_crypto_destroy(context, crypto);
1977 if (ret) {
1978 const char *msg = krb5_get_error_message(context, ret);
1979 free_PA_S4U2Self(&self);
1980 kdc_log(context, config, 0,
1981 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1982 krb5_free_error_message(context, msg);
1983 goto out;
1986 ret = _krb5_principalname2krb5_principal(context,
1987 &tp,
1988 self.name,
1989 self.realm);
1990 free_PA_S4U2Self(&self);
1991 if (ret)
1992 goto out;
1994 ret = krb5_unparse_name(context, tp, &tpn);
1995 if (ret)
1996 goto out;
1998 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1999 if(rspac.data) {
2000 krb5_pac p = NULL;
2001 krb5_data_free(&rspac);
2002 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2003 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
2004 if (ret) {
2005 const char *msg;
2008 * If the client belongs to the same realm as our krbtgt, it
2009 * should exist in the local database.
2013 if (ret == HDB_ERR_NOENTRY)
2014 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2015 msg = krb5_get_error_message(context, ret);
2016 kdc_log(context, config, 1,
2017 "S2U4Self principal to impersonate %s not found in database: %s",
2018 tpn, msg);
2019 krb5_free_error_message(context, msg);
2020 goto out;
2022 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2023 if (ret) {
2024 kdc_log(context, config, 0, "PAC generation failed for -- %s",
2025 tpn);
2026 goto out;
2028 if (p != NULL) {
2029 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2030 s4u2self_impersonated_client->entry.principal,
2031 ekey, &tkey_sign->key,
2032 &rspac);
2033 krb5_pac_free(context, p);
2034 if (ret) {
2035 kdc_log(context, config, 0, "PAC signing failed for -- %s",
2036 tpn);
2037 goto out;
2043 * Check that service doing the impersonating is
2044 * requesting a ticket to it-self.
2046 ret = check_s4u2self(context, config, clientdb, client, sp);
2047 if (ret) {
2048 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2049 "to impersonate to service "
2050 "(tried for user %s to service %s)",
2051 cpn, tpn, spn);
2052 goto out;
2056 * If the service isn't trusted for authentication to
2057 * delegation, remove the forward flag.
2060 if (client->entry.flags.trusted_for_delegation) {
2061 str = "[forwardable]";
2062 } else {
2063 b->kdc_options.forwardable = 0;
2064 str = "";
2066 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2067 "service %s %s", cpn, tpn, spn, str);
2072 * Constrained delegation
2075 if (client != NULL
2076 && b->additional_tickets != NULL
2077 && b->additional_tickets->len != 0
2078 && b->kdc_options.enc_tkt_in_skey == 0)
2080 int ad_signedpath = 0;
2081 Key *clientkey;
2082 Ticket *t;
2085 * Require that the KDC have issued the service's krbtgt (not
2086 * self-issued ticket with kimpersonate(1).
2088 if (!signedpath) {
2089 ret = KRB5KDC_ERR_BADOPTION;
2090 kdc_log(context, config, 0,
2091 "Constrained delegation done on service ticket %s/%s",
2092 cpn, spn);
2093 goto out;
2096 t = &b->additional_tickets->val[0];
2098 ret = hdb_enctype2key(context, &client->entry,
2099 hdb_kvno2keys(context, &client->entry,
2100 t->enc_part.kvno ? * t->enc_part.kvno : 0),
2101 t->enc_part.etype, &clientkey);
2102 if(ret){
2103 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2104 goto out;
2107 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2108 if (ret) {
2109 kdc_log(context, config, 0,
2110 "failed to decrypt ticket for "
2111 "constrained delegation from %s to %s ", cpn, spn);
2112 goto out;
2115 ret = _krb5_principalname2krb5_principal(context,
2116 &tp,
2117 adtkt.cname,
2118 adtkt.crealm);
2119 if (ret)
2120 goto out;
2122 ret = krb5_unparse_name(context, tp, &tpn);
2123 if (ret)
2124 goto out;
2126 ret = _krb5_principalname2krb5_principal(context,
2127 &dp,
2128 t->sname,
2129 t->realm);
2130 if (ret)
2131 goto out;
2133 ret = krb5_unparse_name(context, dp, &dpn);
2134 if (ret)
2135 goto out;
2137 /* check that ticket is valid */
2138 if (adtkt.flags.forwardable == 0) {
2139 kdc_log(context, config, 0,
2140 "Missing forwardable flag on ticket for "
2141 "constrained delegation from %s (%s) as %s to %s ",
2142 cpn, dpn, tpn, spn);
2143 ret = KRB5KDC_ERR_BADOPTION;
2144 goto out;
2147 ret = check_constrained_delegation(context, config, clientdb,
2148 client, server, sp);
2149 if (ret) {
2150 kdc_log(context, config, 0,
2151 "constrained delegation from %s (%s) as %s to %s not allowed",
2152 cpn, dpn, tpn, spn);
2153 goto out;
2156 ret = verify_flags(context, config, &adtkt, tpn);
2157 if (ret) {
2158 goto out;
2161 krb5_data_free(&rspac);
2164 * generate the PAC for the user.
2166 * TODO: pass in t->sname and t->realm and build
2167 * a S4U_DELEGATION_INFO blob to the PAC.
2169 ret = check_PAC(context, config, tp, dp,
2170 client, server, krbtgt,
2171 &clientkey->key, &tkey_check->key,
2172 ekey, &tkey_sign->key,
2173 &adtkt, &rspac, &ad_signedpath);
2174 if (ret) {
2175 const char *msg = krb5_get_error_message(context, ret);
2176 kdc_log(context, config, 0,
2177 "Verify delegated PAC failed to %s for client"
2178 "%s (%s) as %s from %s with %s",
2179 spn, cpn, dpn, tpn, from, msg);
2180 krb5_free_error_message(context, msg);
2181 goto out;
2185 * Check that the KDC issued the user's ticket.
2187 ret = check_KRB5SignedPath(context,
2188 config,
2189 krbtgt,
2191 &adtkt,
2192 NULL,
2193 &ad_signedpath);
2194 if (ret) {
2195 const char *msg = krb5_get_error_message(context, ret);
2196 kdc_log(context, config, 0,
2197 "KRB5SignedPath check from service %s failed "
2198 "for delegation to %s for client %s (%s)"
2199 "from %s failed with %s",
2200 spn, tpn, dpn, cpn, from, msg);
2201 krb5_free_error_message(context, msg);
2202 goto out;
2205 if (!ad_signedpath) {
2206 ret = KRB5KDC_ERR_BADOPTION;
2207 kdc_log(context, config, 0,
2208 "Ticket not signed with PAC nor SignedPath service %s failed "
2209 "for delegation to %s for client %s (%s)"
2210 "from %s",
2211 spn, tpn, dpn, cpn, from);
2212 goto out;
2215 kdc_log(context, config, 0, "constrained delegation for %s "
2216 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2220 * Check flags
2223 ret = kdc_check_flags(context, config,
2224 client, cpn,
2225 server, spn,
2226 FALSE);
2227 if(ret)
2228 goto out;
2230 if((b->kdc_options.validate || b->kdc_options.renew) &&
2231 !krb5_principal_compare(context,
2232 krbtgt->entry.principal,
2233 server->entry.principal)){
2234 kdc_log(context, config, 0, "Inconsistent request.");
2235 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2236 goto out;
2239 /* check for valid set of addresses */
2240 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2241 ret = KRB5KRB_AP_ERR_BADADDR;
2242 kdc_log(context, config, 0, "Request from wrong address");
2243 goto out;
2247 * If this is an referral, add server referral data to the
2248 * auth_data reply .
2250 if (ref_realm) {
2251 PA_DATA pa;
2252 krb5_crypto crypto;
2254 kdc_log(context, config, 0,
2255 "Adding server referral to %s", ref_realm);
2257 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2258 if (ret)
2259 goto out;
2261 ret = build_server_referral(context, config, crypto, ref_realm,
2262 NULL, s, &pa.padata_value);
2263 krb5_crypto_destroy(context, crypto);
2264 if (ret) {
2265 kdc_log(context, config, 0,
2266 "Failed building server referral");
2267 goto out;
2269 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2271 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2272 krb5_data_free(&pa.padata_value);
2273 if (ret) {
2274 kdc_log(context, config, 0,
2275 "Add server referral METHOD-DATA failed");
2276 goto out;
2284 ret = tgs_make_reply(context,
2285 config,
2288 tgt,
2289 replykey,
2290 rk_is_subkey,
2291 ekey,
2292 &sessionkey,
2293 kvno,
2294 *auth_data,
2295 server,
2296 rsp,
2297 spn,
2298 client,
2300 krbtgt_out,
2301 tkey_sign->key.keytype,
2302 spp,
2303 &rspac,
2304 &enc_pa_data,
2305 e_text,
2306 reply);
2308 out:
2309 if (tpn != cpn)
2310 free(tpn);
2311 free(spn);
2312 free(cpn);
2313 free(dpn);
2314 free(krbtgt_out_n);
2316 krb5_data_free(&rspac);
2317 krb5_free_keyblock_contents(context, &sessionkey);
2318 if(krbtgt_out)
2319 _kdc_free_ent(context, krbtgt_out);
2320 if(server)
2321 _kdc_free_ent(context, server);
2322 if(client)
2323 _kdc_free_ent(context, client);
2324 if(s4u2self_impersonated_client)
2325 _kdc_free_ent(context, s4u2self_impersonated_client);
2327 if (tp && tp != cp)
2328 krb5_free_principal(context, tp);
2329 krb5_free_principal(context, cp);
2330 krb5_free_principal(context, dp);
2331 krb5_free_principal(context, sp);
2332 krb5_free_principal(context, krbtgt_out_principal);
2333 if (ref_realm)
2334 free(ref_realm);
2335 free_METHOD_DATA(&enc_pa_data);
2337 free_EncTicketPart(&adtkt);
2339 return ret;
2346 krb5_error_code
2347 _kdc_tgs_rep(krb5_context context,
2348 krb5_kdc_configuration *config,
2349 KDC_REQ *req,
2350 krb5_data *data,
2351 const char *from,
2352 struct sockaddr *from_addr,
2353 int datagram_reply)
2355 AuthorizationData *auth_data = NULL;
2356 krb5_error_code ret;
2357 int i = 0;
2358 const PA_DATA *tgs_req;
2360 hdb_entry_ex *krbtgt = NULL;
2361 krb5_ticket *ticket = NULL;
2362 const char *e_text = NULL;
2363 krb5_enctype krbtgt_etype = ETYPE_NULL;
2365 krb5_keyblock *replykey = NULL;
2366 int rk_is_subkey = 0;
2367 time_t *csec = NULL;
2368 int *cusec = NULL;
2370 if(req->padata == NULL){
2371 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2372 kdc_log(context, config, 0,
2373 "TGS-REQ from %s without PA-DATA", from);
2374 goto out;
2377 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2379 if(tgs_req == NULL){
2380 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2382 kdc_log(context, config, 0,
2383 "TGS-REQ from %s without PA-TGS-REQ", from);
2384 goto out;
2386 ret = tgs_parse_request(context, config,
2387 &req->req_body, tgs_req,
2388 &krbtgt,
2389 &krbtgt_etype,
2390 &ticket,
2391 &e_text,
2392 from, from_addr,
2393 &csec, &cusec,
2394 &auth_data,
2395 &replykey,
2396 &rk_is_subkey);
2397 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2398 /* kdc_log() is called in tgs_parse_request() */
2399 goto out;
2401 if (ret) {
2402 kdc_log(context, config, 0,
2403 "Failed parsing TGS-REQ from %s", from);
2404 goto out;
2408 int i = 0;
2409 const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2410 if (pa)
2411 kdc_log(context, config, 10, "Got TGS FAST request");
2415 ret = tgs_build_reply(context,
2416 config,
2417 req,
2418 &req->req_body,
2419 krbtgt,
2420 krbtgt_etype,
2421 replykey,
2422 rk_is_subkey,
2423 ticket,
2424 data,
2425 from,
2426 &e_text,
2427 &auth_data,
2428 from_addr);
2429 if (ret) {
2430 kdc_log(context, config, 0,
2431 "Failed building TGS-REP to %s", from);
2432 goto out;
2435 /* */
2436 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2437 krb5_data_free(data);
2438 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2439 e_text = "Reply packet too large";
2442 out:
2443 if (replykey)
2444 krb5_free_keyblock(context, replykey);
2446 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2447 /* XXX add fast wrapping on the error */
2448 METHOD_DATA error_method = { 0, NULL };
2451 kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2452 ret = _kdc_fast_mk_error(context, NULL,
2453 &error_method,
2454 NULL,
2455 NULL,
2456 ret, NULL,
2457 NULL, NULL,
2458 csec, cusec,
2459 data);
2460 free_METHOD_DATA(&error_method);
2462 free(csec);
2463 free(cusec);
2464 if (ticket)
2465 krb5_free_ticket(context, ticket);
2466 if(krbtgt)
2467 _kdc_free_ent(context, krbtgt);
2469 if (auth_data) {
2470 free_AuthorizationData(auth_data);
2471 free(auth_data);
2474 return ret;