kdc-tester4.json is in objdir
[heimdal.git] / kdc / krb5tgs.c
blob8952dd2a3dd79df785bb09a66ecb547a66da78bf
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 config->tgs_use_strongest_session_key, FALSE,
1733 server, b->etype.val, b->etype.len, &etype,
1734 NULL);
1735 if(ret) {
1736 kdc_log(context, config, 0,
1737 "Server (%s) has no support for etypes", spn);
1738 goto out;
1740 ret = _kdc_get_preferred_key(context, config, server, spn,
1741 NULL, &skey);
1742 if(ret) {
1743 kdc_log(context, config, 0,
1744 "Server (%s) has no supported etypes", spn);
1745 goto out;
1747 ekey = &skey->key;
1748 kvno = server->entry.kvno;
1751 ret = krb5_generate_random_keyblock(context, etype, &sessionkey);
1752 if (ret)
1753 goto out;
1757 * Check that service is in the same realm as the krbtgt. If it's
1758 * not the same, it's someone that is using a uni-directional trust
1759 * backward.
1763 * Validate authoriation data
1766 ret = hdb_enctype2key(context, &krbtgt->entry, NULL, /* XXX use the right kvno! */
1767 krbtgt_etype, &tkey_check);
1768 if(ret) {
1769 kdc_log(context, config, 0,
1770 "Failed to find key for krbtgt PAC check");
1771 goto out;
1775 * Now refetch the primary krbtgt, and get the current kvno (the
1776 * sign check may have been on an old kvno, and the server may
1777 * have been an incoming trust)
1781 const char *remote_realm =
1782 krb5_principal_get_comp_string(context, krbtgt->entry.principal, 1);
1784 ret = krb5_make_principal(context,
1785 &krbtgt_out_principal,
1786 remote_realm,
1787 KRB5_TGS_NAME,
1788 remote_realm,
1789 NULL);
1790 if(ret) {
1791 kdc_log(context, config, 0,
1792 "Failed to make krbtgt principal name object for "
1793 "authz-data signatures");
1794 goto out;
1796 ret = krb5_unparse_name(context, krbtgt_out_principal, &krbtgt_out_n);
1797 if (ret) {
1798 kdc_log(context, config, 0,
1799 "Failed to make krbtgt principal name object for "
1800 "authz-data signatures");
1801 goto out;
1805 ret = _kdc_db_fetch(context, config, krbtgt_out_principal,
1806 HDB_F_GET_KRBTGT, NULL, NULL, &krbtgt_out);
1807 if (ret) {
1808 char *ktpn = NULL;
1809 ret = krb5_unparse_name(context, krbtgt->entry.principal, &ktpn);
1810 kdc_log(context, config, 0,
1811 "No such principal %s (needed for authz-data signature keys) "
1812 "while processing TGS-REQ for service %s with krbtg %s",
1813 krbtgt_out_n, spn, (ret == 0) ? ktpn : "<unknown>");
1814 free(ktpn);
1815 ret = KRB5KRB_AP_ERR_NOT_US;
1816 goto out;
1820 * The first realm is the realm of the service, the second is
1821 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1822 * encrypted to. The redirection via the krbtgt_out entry allows
1823 * the DB to possibly correct the case of the realm (Samba4 does
1824 * this) before the strcmp()
1826 if (strcmp(krb5_principal_get_realm(context, server->entry.principal),
1827 krb5_principal_get_realm(context, krbtgt_out->entry.principal)) != 0) {
1828 char *ktpn;
1829 ret = krb5_unparse_name(context, krbtgt_out->entry.principal, &ktpn);
1830 kdc_log(context, config, 0,
1831 "Request with wrong krbtgt: %s",
1832 (ret == 0) ? ktpn : "<unknown>");
1833 if(ret == 0)
1834 free(ktpn);
1835 ret = KRB5KRB_AP_ERR_NOT_US;
1836 goto out;
1839 ret = _kdc_get_preferred_key(context, config, krbtgt_out, krbtgt_out_n,
1840 NULL, &tkey_sign);
1841 if (ret) {
1842 kdc_log(context, config, 0,
1843 "Failed to find key for krbtgt PAC signature");
1844 goto out;
1846 ret = hdb_enctype2key(context, &krbtgt_out->entry, NULL,
1847 tkey_sign->key.keytype, &tkey_sign);
1848 if(ret) {
1849 kdc_log(context, config, 0,
1850 "Failed to find key for krbtgt PAC signature");
1851 goto out;
1855 * Check if we would know the krbtgt key for the PAC. We would
1856 * only know this if the krbtgt principal was the same (ie, in our
1857 * realm, regardless of KVNO)
1860 if (krb5_principal_compare(context, krbtgt_out->entry.principal, krbtgt->entry.principal))
1861 tkey_krbtgt_check = tkey_check;
1864 ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags,
1865 NULL, &clientdb, &client);
1866 if(ret == HDB_ERR_NOT_FOUND_HERE) {
1867 /* This is OK, we are just trying to find out if they have
1868 * been disabled or deleted in the meantime, missing secrets
1869 * is OK */
1870 } else if(ret){
1871 const char *krbtgt_realm, *msg;
1874 * If the client belongs to the same realm as our krbtgt, it
1875 * should exist in the local database.
1879 krbtgt_realm = krb5_principal_get_realm(context, krbtgt_out->entry.principal);
1881 if(strcmp(krb5_principal_get_realm(context, cp), krbtgt_realm) == 0) {
1882 if (ret == HDB_ERR_NOENTRY)
1883 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1884 kdc_log(context, config, 1, "Client no longer in database: %s",
1885 cpn);
1886 goto out;
1889 msg = krb5_get_error_message(context, ret);
1890 kdc_log(context, config, 1, "Client not found in database: %s", msg);
1891 krb5_free_error_message(context, msg);
1894 ret = check_PAC(context, config, cp, NULL,
1895 client, server, krbtgt,
1896 &tkey_check->key,
1897 tkey_krbtgt_check ? &tkey_krbtgt_check->key : NULL,
1898 ekey, &tkey_sign->key,
1899 tgt, &rspac, &signedpath);
1900 if (ret) {
1901 const char *msg = krb5_get_error_message(context, ret);
1902 kdc_log(context, config, 0,
1903 "Verify PAC failed for %s (%s) from %s with %s",
1904 spn, cpn, from, msg);
1905 krb5_free_error_message(context, msg);
1906 goto out;
1909 /* also check the krbtgt for signature */
1910 ret = check_KRB5SignedPath(context,
1911 config,
1912 krbtgt,
1914 tgt,
1915 &spp,
1916 &signedpath);
1917 if (ret) {
1918 const char *msg = krb5_get_error_message(context, ret);
1919 kdc_log(context, config, 0,
1920 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1921 spn, cpn, from, msg);
1922 krb5_free_error_message(context, msg);
1923 goto out;
1927 * Process request
1930 /* by default the tgt principal matches the client principal */
1931 tp = cp;
1932 tpn = cpn;
1934 if (client) {
1935 const PA_DATA *sdata;
1936 int i = 0;
1938 sdata = _kdc_find_padata(req, &i, KRB5_PADATA_FOR_USER);
1939 if (sdata) {
1940 krb5_crypto crypto;
1941 krb5_data datack;
1942 PA_S4U2Self self;
1943 const char *str;
1945 ret = decode_PA_S4U2Self(sdata->padata_value.data,
1946 sdata->padata_value.length,
1947 &self, NULL);
1948 if (ret) {
1949 kdc_log(context, config, 0, "Failed to decode PA-S4U2Self");
1950 goto out;
1953 ret = _krb5_s4u2self_to_checksumdata(context, &self, &datack);
1954 if (ret)
1955 goto out;
1957 ret = krb5_crypto_init(context, &tgt->key, 0, &crypto);
1958 if (ret) {
1959 const char *msg = krb5_get_error_message(context, ret);
1960 free_PA_S4U2Self(&self);
1961 krb5_data_free(&datack);
1962 kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg);
1963 krb5_free_error_message(context, msg);
1964 goto out;
1967 ret = krb5_verify_checksum(context,
1968 crypto,
1969 KRB5_KU_OTHER_CKSUM,
1970 datack.data,
1971 datack.length,
1972 &self.cksum);
1973 krb5_data_free(&datack);
1974 krb5_crypto_destroy(context, crypto);
1975 if (ret) {
1976 const char *msg = krb5_get_error_message(context, ret);
1977 free_PA_S4U2Self(&self);
1978 kdc_log(context, config, 0,
1979 "krb5_verify_checksum failed for S4U2Self: %s", msg);
1980 krb5_free_error_message(context, msg);
1981 goto out;
1984 ret = _krb5_principalname2krb5_principal(context,
1985 &tp,
1986 self.name,
1987 self.realm);
1988 free_PA_S4U2Self(&self);
1989 if (ret)
1990 goto out;
1992 ret = krb5_unparse_name(context, tp, &tpn);
1993 if (ret)
1994 goto out;
1996 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1997 if(rspac.data) {
1998 krb5_pac p = NULL;
1999 krb5_data_free(&rspac);
2000 ret = _kdc_db_fetch(context, config, tp, HDB_F_GET_CLIENT | flags,
2001 NULL, &s4u2self_impersonated_clientdb, &s4u2self_impersonated_client);
2002 if (ret) {
2003 const char *msg;
2006 * If the client belongs to the same realm as our krbtgt, it
2007 * should exist in the local database.
2011 if (ret == HDB_ERR_NOENTRY)
2012 ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2013 msg = krb5_get_error_message(context, ret);
2014 kdc_log(context, config, 1,
2015 "S2U4Self principal to impersonate %s not found in database: %s",
2016 tpn, msg);
2017 krb5_free_error_message(context, msg);
2018 goto out;
2020 ret = _kdc_pac_generate(context, s4u2self_impersonated_client, &p);
2021 if (ret) {
2022 kdc_log(context, config, 0, "PAC generation failed for -- %s",
2023 tpn);
2024 goto out;
2026 if (p != NULL) {
2027 ret = _krb5_pac_sign(context, p, ticket->ticket.authtime,
2028 s4u2self_impersonated_client->entry.principal,
2029 ekey, &tkey_sign->key,
2030 &rspac);
2031 krb5_pac_free(context, p);
2032 if (ret) {
2033 kdc_log(context, config, 0, "PAC signing failed for -- %s",
2034 tpn);
2035 goto out;
2041 * Check that service doing the impersonating is
2042 * requesting a ticket to it-self.
2044 ret = check_s4u2self(context, config, clientdb, client, sp);
2045 if (ret) {
2046 kdc_log(context, config, 0, "S4U2Self: %s is not allowed "
2047 "to impersonate to service "
2048 "(tried for user %s to service %s)",
2049 cpn, tpn, spn);
2050 goto out;
2054 * If the service isn't trusted for authentication to
2055 * delegation, remove the forward flag.
2058 if (client->entry.flags.trusted_for_delegation) {
2059 str = "[forwardable]";
2060 } else {
2061 b->kdc_options.forwardable = 0;
2062 str = "";
2064 kdc_log(context, config, 0, "s4u2self %s impersonating %s to "
2065 "service %s %s", cpn, tpn, spn, str);
2070 * Constrained delegation
2073 if (client != NULL
2074 && b->additional_tickets != NULL
2075 && b->additional_tickets->len != 0
2076 && b->kdc_options.enc_tkt_in_skey == 0)
2078 int ad_signedpath = 0;
2079 Key *clientkey;
2080 Ticket *t;
2083 * Require that the KDC have issued the service's krbtgt (not
2084 * self-issued ticket with kimpersonate(1).
2086 if (!signedpath) {
2087 ret = KRB5KDC_ERR_BADOPTION;
2088 kdc_log(context, config, 0,
2089 "Constrained delegation done on service ticket %s/%s",
2090 cpn, spn);
2091 goto out;
2094 t = &b->additional_tickets->val[0];
2096 ret = hdb_enctype2key(context, &client->entry,
2097 hdb_kvno2keys(context, &client->entry,
2098 t->enc_part.kvno ? * t->enc_part.kvno : 0),
2099 t->enc_part.etype, &clientkey);
2100 if(ret){
2101 ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */
2102 goto out;
2105 ret = krb5_decrypt_ticket(context, t, &clientkey->key, &adtkt, 0);
2106 if (ret) {
2107 kdc_log(context, config, 0,
2108 "failed to decrypt ticket for "
2109 "constrained delegation from %s to %s ", cpn, spn);
2110 goto out;
2113 ret = _krb5_principalname2krb5_principal(context,
2114 &tp,
2115 adtkt.cname,
2116 adtkt.crealm);
2117 if (ret)
2118 goto out;
2120 ret = krb5_unparse_name(context, tp, &tpn);
2121 if (ret)
2122 goto out;
2124 ret = _krb5_principalname2krb5_principal(context,
2125 &dp,
2126 t->sname,
2127 t->realm);
2128 if (ret)
2129 goto out;
2131 ret = krb5_unparse_name(context, dp, &dpn);
2132 if (ret)
2133 goto out;
2135 /* check that ticket is valid */
2136 if (adtkt.flags.forwardable == 0) {
2137 kdc_log(context, config, 0,
2138 "Missing forwardable flag on ticket for "
2139 "constrained delegation from %s (%s) as %s to %s ",
2140 cpn, dpn, tpn, spn);
2141 ret = KRB5KDC_ERR_BADOPTION;
2142 goto out;
2145 ret = check_constrained_delegation(context, config, clientdb,
2146 client, server, sp);
2147 if (ret) {
2148 kdc_log(context, config, 0,
2149 "constrained delegation from %s (%s) as %s to %s not allowed",
2150 cpn, dpn, tpn, spn);
2151 goto out;
2154 ret = verify_flags(context, config, &adtkt, tpn);
2155 if (ret) {
2156 goto out;
2159 krb5_data_free(&rspac);
2162 * generate the PAC for the user.
2164 * TODO: pass in t->sname and t->realm and build
2165 * a S4U_DELEGATION_INFO blob to the PAC.
2167 ret = check_PAC(context, config, tp, dp,
2168 client, server, krbtgt,
2169 &clientkey->key, &tkey_check->key,
2170 ekey, &tkey_sign->key,
2171 &adtkt, &rspac, &ad_signedpath);
2172 if (ret) {
2173 const char *msg = krb5_get_error_message(context, ret);
2174 kdc_log(context, config, 0,
2175 "Verify delegated PAC failed to %s for client"
2176 "%s (%s) as %s from %s with %s",
2177 spn, cpn, dpn, tpn, from, msg);
2178 krb5_free_error_message(context, msg);
2179 goto out;
2183 * Check that the KDC issued the user's ticket.
2185 ret = check_KRB5SignedPath(context,
2186 config,
2187 krbtgt,
2189 &adtkt,
2190 NULL,
2191 &ad_signedpath);
2192 if (ret) {
2193 const char *msg = krb5_get_error_message(context, ret);
2194 kdc_log(context, config, 0,
2195 "KRB5SignedPath check from service %s failed "
2196 "for delegation to %s for client %s (%s)"
2197 "from %s failed with %s",
2198 spn, tpn, dpn, cpn, from, msg);
2199 krb5_free_error_message(context, msg);
2200 goto out;
2203 if (!ad_signedpath) {
2204 ret = KRB5KDC_ERR_BADOPTION;
2205 kdc_log(context, config, 0,
2206 "Ticket not signed with PAC nor SignedPath service %s failed "
2207 "for delegation to %s for client %s (%s)"
2208 "from %s",
2209 spn, tpn, dpn, cpn, from);
2210 goto out;
2213 kdc_log(context, config, 0, "constrained delegation for %s "
2214 "from %s (%s) to %s", tpn, cpn, dpn, spn);
2218 * Check flags
2221 ret = kdc_check_flags(context, config,
2222 client, cpn,
2223 server, spn,
2224 FALSE);
2225 if(ret)
2226 goto out;
2228 if((b->kdc_options.validate || b->kdc_options.renew) &&
2229 !krb5_principal_compare(context,
2230 krbtgt->entry.principal,
2231 server->entry.principal)){
2232 kdc_log(context, config, 0, "Inconsistent request.");
2233 ret = KRB5KDC_ERR_SERVER_NOMATCH;
2234 goto out;
2237 /* check for valid set of addresses */
2238 if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) {
2239 ret = KRB5KRB_AP_ERR_BADADDR;
2240 kdc_log(context, config, 0, "Request from wrong address");
2241 goto out;
2245 * If this is an referral, add server referral data to the
2246 * auth_data reply .
2248 if (ref_realm) {
2249 PA_DATA pa;
2250 krb5_crypto crypto;
2252 kdc_log(context, config, 0,
2253 "Adding server referral to %s", ref_realm);
2255 ret = krb5_crypto_init(context, &sessionkey, 0, &crypto);
2256 if (ret)
2257 goto out;
2259 ret = build_server_referral(context, config, crypto, ref_realm,
2260 NULL, s, &pa.padata_value);
2261 krb5_crypto_destroy(context, crypto);
2262 if (ret) {
2263 kdc_log(context, config, 0,
2264 "Failed building server referral");
2265 goto out;
2267 pa.padata_type = KRB5_PADATA_SERVER_REFERRAL;
2269 ret = add_METHOD_DATA(&enc_pa_data, &pa);
2270 krb5_data_free(&pa.padata_value);
2271 if (ret) {
2272 kdc_log(context, config, 0,
2273 "Add server referral METHOD-DATA failed");
2274 goto out;
2282 ret = tgs_make_reply(context,
2283 config,
2286 tgt,
2287 replykey,
2288 rk_is_subkey,
2289 ekey,
2290 &sessionkey,
2291 kvno,
2292 *auth_data,
2293 server,
2294 rsp,
2295 spn,
2296 client,
2298 krbtgt_out,
2299 tkey_sign->key.keytype,
2300 spp,
2301 &rspac,
2302 &enc_pa_data,
2303 e_text,
2304 reply);
2306 out:
2307 if (tpn != cpn)
2308 free(tpn);
2309 free(spn);
2310 free(cpn);
2311 free(dpn);
2312 free(krbtgt_out_n);
2314 krb5_data_free(&rspac);
2315 krb5_free_keyblock_contents(context, &sessionkey);
2316 if(krbtgt_out)
2317 _kdc_free_ent(context, krbtgt_out);
2318 if(server)
2319 _kdc_free_ent(context, server);
2320 if(client)
2321 _kdc_free_ent(context, client);
2322 if(s4u2self_impersonated_client)
2323 _kdc_free_ent(context, s4u2self_impersonated_client);
2325 if (tp && tp != cp)
2326 krb5_free_principal(context, tp);
2327 krb5_free_principal(context, cp);
2328 krb5_free_principal(context, dp);
2329 krb5_free_principal(context, sp);
2330 krb5_free_principal(context, krbtgt_out_principal);
2331 if (ref_realm)
2332 free(ref_realm);
2333 free_METHOD_DATA(&enc_pa_data);
2335 free_EncTicketPart(&adtkt);
2337 return ret;
2344 krb5_error_code
2345 _kdc_tgs_rep(krb5_context context,
2346 krb5_kdc_configuration *config,
2347 KDC_REQ *req,
2348 krb5_data *data,
2349 const char *from,
2350 struct sockaddr *from_addr,
2351 int datagram_reply)
2353 AuthorizationData *auth_data = NULL;
2354 krb5_error_code ret;
2355 int i = 0;
2356 const PA_DATA *tgs_req;
2358 hdb_entry_ex *krbtgt = NULL;
2359 krb5_ticket *ticket = NULL;
2360 const char *e_text = NULL;
2361 krb5_enctype krbtgt_etype = ETYPE_NULL;
2363 krb5_keyblock *replykey = NULL;
2364 int rk_is_subkey = 0;
2365 time_t *csec = NULL;
2366 int *cusec = NULL;
2368 if(req->padata == NULL){
2369 ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */
2370 kdc_log(context, config, 0,
2371 "TGS-REQ from %s without PA-DATA", from);
2372 goto out;
2375 tgs_req = _kdc_find_padata(req, &i, KRB5_PADATA_TGS_REQ);
2377 if(tgs_req == NULL){
2378 ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP;
2380 kdc_log(context, config, 0,
2381 "TGS-REQ from %s without PA-TGS-REQ", from);
2382 goto out;
2384 ret = tgs_parse_request(context, config,
2385 &req->req_body, tgs_req,
2386 &krbtgt,
2387 &krbtgt_etype,
2388 &ticket,
2389 &e_text,
2390 from, from_addr,
2391 &csec, &cusec,
2392 &auth_data,
2393 &replykey,
2394 &rk_is_subkey);
2395 if (ret == HDB_ERR_NOT_FOUND_HERE) {
2396 /* kdc_log() is called in tgs_parse_request() */
2397 goto out;
2399 if (ret) {
2400 kdc_log(context, config, 0,
2401 "Failed parsing TGS-REQ from %s", from);
2402 goto out;
2406 int i = 0;
2407 const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST);
2408 if (pa)
2409 kdc_log(context, config, 10, "Got TGS FAST request");
2413 ret = tgs_build_reply(context,
2414 config,
2415 req,
2416 &req->req_body,
2417 krbtgt,
2418 krbtgt_etype,
2419 replykey,
2420 rk_is_subkey,
2421 ticket,
2422 data,
2423 from,
2424 &e_text,
2425 &auth_data,
2426 from_addr);
2427 if (ret) {
2428 kdc_log(context, config, 0,
2429 "Failed building TGS-REP to %s", from);
2430 goto out;
2433 /* */
2434 if (datagram_reply && data->length > config->max_datagram_reply_length) {
2435 krb5_data_free(data);
2436 ret = KRB5KRB_ERR_RESPONSE_TOO_BIG;
2437 e_text = "Reply packet too large";
2440 out:
2441 if (replykey)
2442 krb5_free_keyblock(context, replykey);
2444 if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){
2445 /* XXX add fast wrapping on the error */
2446 METHOD_DATA error_method = { 0, NULL };
2449 kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret);
2450 ret = _kdc_fast_mk_error(context, NULL,
2451 &error_method,
2452 NULL,
2453 NULL,
2454 ret, NULL,
2455 NULL, NULL,
2456 csec, cusec,
2457 data);
2458 free_METHOD_DATA(&error_method);
2460 free(csec);
2461 free(cusec);
2462 if (ticket)
2463 krb5_free_ticket(context, ticket);
2464 if(krbtgt)
2465 _kdc_free_ent(context, krbtgt);
2467 if (auth_data) {
2468 free_AuthorizationData(auth_data);
2469 free(auth_data);
2472 return ret;