2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
37 * return the realm of a krbtgt-ticket or NULL
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];
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
,
64 AuthorizationData child
;
68 if (ad
== NULL
|| ad
->len
== 0)
69 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
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
,
81 krb5_set_error_message(context
, ret
, "Failed to decode "
82 "IF_RELEVANT with %d", ret
);
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
;
97 ret
= der_copy_octet_string(&child
.val
[0].ad_data
, data
);
98 free_AuthorizationData(&child
);
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
,
115 krb5_crypto crypto
= NULL
;
118 if (server
&& principals
) {
119 ret
= add_Principals(principals
, server
);
125 KRB5SignedPathData spd
;
128 spd
.authtime
= tkt
->authtime
;
129 spd
.delegated
= principals
;
130 spd
.method_data
= NULL
;
132 ASN1_MALLOC_ENCODE(KRB5SignedPathData
, data
.data
, data
.length
,
136 if (data
.length
!= size
)
137 krb5_abortx(context
, "internal asn.1 encoder error");
142 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, enctype
, &key
);
144 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
152 * Fill in KRB5SignedPath
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
);
166 ASN1_MALLOC_ENCODE(KRB5SignedPath
, data
.data
, data
.length
, &sp
, &size
, ret
);
167 free_Checksum(&sp
.cksum
);
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
);
186 static krb5_error_code
187 check_KRB5SignedPath(krb5_context context
,
188 krb5_kdc_configuration
*config
,
189 hdb_entry_ex
*krbtgt
,
192 krb5_principals
*delegated
,
197 krb5_crypto crypto
= NULL
;
202 ret
= find_KRB5SignedPath(context
, tkt
->authorization_data
, &data
);
204 KRB5SignedPathData spd
;
208 ret
= decode_KRB5SignedPath(data
.data
, data
.length
, &sp
, NULL
);
209 krb5_data_free(&data
);
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
,
221 free_KRB5SignedPath(&sp
);
224 if (data
.length
!= size
)
225 krb5_abortx(context
, "internal asn.1 encoder error");
229 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, sp
.etype
, &key
);
231 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
234 free_KRB5SignedPath(&sp
);
238 ret
= krb5_verify_checksum(context
, crypto
, KRB5_KU_KRB5SIGNEDPATH
,
239 data
.data
, data
.length
,
241 krb5_crypto_destroy(context
, crypto
);
244 free_KRB5SignedPath(&sp
);
245 kdc_log(context
, config
, 5,
246 "KRB5SignedPath not signed correctly, not marking as signed");
250 if (delegated
&& sp
.delegated
) {
252 *delegated
= malloc(sizeof(*sp
.delegated
));
253 if (*delegated
== NULL
) {
254 free_KRB5SignedPath(&sp
);
258 ret
= copy_Principals(*delegated
, sp
.delegated
);
260 free_KRB5SignedPath(&sp
);
266 free_KRB5SignedPath(&sp
);
278 static krb5_error_code
279 check_PAC(krb5_context context
,
280 krb5_kdc_configuration
*config
,
281 const krb5_principal client_principal
,
282 hdb_entry_ex
*client
,
283 hdb_entry_ex
*server
,
284 const EncryptionKey
*server_key
,
285 const EncryptionKey
*krbtgt_key
,
290 AuthorizationData
*ad
= tkt
->authorization_data
;
294 if (ad
== NULL
|| ad
->len
== 0)
297 for (i
= 0; i
< ad
->len
; i
++) {
298 AuthorizationData child
;
300 if (ad
->val
[i
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
303 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
304 ad
->val
[i
].ad_data
.length
,
308 krb5_set_error_message(context
, ret
, "Failed to decode "
309 "IF_RELEVANT with %d", ret
);
312 for (j
= 0; j
< child
.len
; j
++) {
314 if (child
.val
[j
].ad_type
== KRB5_AUTHDATA_WIN2K_PAC
) {
318 ret
= krb5_pac_parse(context
,
319 child
.val
[j
].ad_data
.data
,
320 child
.val
[j
].ad_data
.length
,
322 free_AuthorizationData(&child
);
326 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
,
330 krb5_pac_free(context
, pac
);
334 ret
= _kdc_pac_verify(context
, client_principal
,
335 client
, server
, &pac
);
337 krb5_pac_free(context
, pac
);
342 ret
= _krb5_pac_sign(context
, pac
, tkt
->authtime
,
344 server_key
, krbtgt_key
, rspac
);
346 krb5_pac_free(context
, pac
);
351 free_AuthorizationData(&child
);
360 static krb5_error_code
361 check_tgs_flags(krb5_context context
,
362 krb5_kdc_configuration
*config
,
363 KDC_REQ_BODY
*b
, const EncTicketPart
*tgt
, EncTicketPart
*et
)
365 KDCOptions f
= b
->kdc_options
;
368 if(!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
){
369 kdc_log(context
, config
, 0,
370 "Bad request to validate ticket");
371 return KRB5KDC_ERR_BADOPTION
;
373 if(*tgt
->starttime
> kdc_time
){
374 kdc_log(context
, config
, 0,
375 "Early request to validate ticket");
376 return KRB5KRB_AP_ERR_TKT_NYV
;
379 et
->flags
.invalid
= 0;
380 }else if(tgt
->flags
.invalid
){
381 kdc_log(context
, config
, 0,
382 "Ticket-granting ticket has INVALID flag set");
383 return KRB5KRB_AP_ERR_TKT_INVALID
;
387 if(!tgt
->flags
.forwardable
){
388 kdc_log(context
, config
, 0,
389 "Bad request for forwardable ticket");
390 return KRB5KDC_ERR_BADOPTION
;
392 et
->flags
.forwardable
= 1;
395 if(!tgt
->flags
.forwardable
){
396 kdc_log(context
, config
, 0,
397 "Request to forward non-forwardable ticket");
398 return KRB5KDC_ERR_BADOPTION
;
400 et
->flags
.forwarded
= 1;
401 et
->caddr
= b
->addresses
;
403 if(tgt
->flags
.forwarded
)
404 et
->flags
.forwarded
= 1;
407 if(!tgt
->flags
.proxiable
){
408 kdc_log(context
, config
, 0,
409 "Bad request for proxiable ticket");
410 return KRB5KDC_ERR_BADOPTION
;
412 et
->flags
.proxiable
= 1;
415 if(!tgt
->flags
.proxiable
){
416 kdc_log(context
, config
, 0,
417 "Request to proxy non-proxiable ticket");
418 return KRB5KDC_ERR_BADOPTION
;
421 et
->caddr
= b
->addresses
;
426 if(f
.allow_postdate
){
427 if(!tgt
->flags
.may_postdate
){
428 kdc_log(context
, config
, 0,
429 "Bad request for post-datable ticket");
430 return KRB5KDC_ERR_BADOPTION
;
432 et
->flags
.may_postdate
= 1;
435 if(!tgt
->flags
.may_postdate
){
436 kdc_log(context
, config
, 0,
437 "Bad request for postdated ticket");
438 return KRB5KDC_ERR_BADOPTION
;
441 *et
->starttime
= *b
->from
;
442 et
->flags
.postdated
= 1;
443 et
->flags
.invalid
= 1;
444 }else if(b
->from
&& *b
->from
> kdc_time
+ context
->max_skew
){
445 kdc_log(context
, config
, 0, "Ticket cannot be postdated");
446 return KRB5KDC_ERR_CANNOT_POSTDATE
;
450 if(!tgt
->flags
.renewable
){
451 kdc_log(context
, config
, 0,
452 "Bad request for renewable ticket");
453 return KRB5KDC_ERR_BADOPTION
;
455 et
->flags
.renewable
= 1;
456 ALLOC(et
->renew_till
);
457 _kdc_fix_time(&b
->rtime
);
458 *et
->renew_till
= *b
->rtime
;
462 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
463 kdc_log(context
, config
, 0,
464 "Request to renew non-renewable ticket");
465 return KRB5KDC_ERR_BADOPTION
;
467 old_life
= tgt
->endtime
;
469 old_life
-= *tgt
->starttime
;
471 old_life
-= tgt
->authtime
;
472 et
->endtime
= *et
->starttime
+ old_life
;
473 if (et
->renew_till
!= NULL
)
474 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
478 /* checks for excess flags */
479 if(f
.request_anonymous
&& !config
->allow_anonymous
){
480 kdc_log(context
, config
, 0,
481 "Request for anonymous ticket");
482 return KRB5KDC_ERR_BADOPTION
;
489 * Determine if constrained delegation is allowed from this client to this server
492 static krb5_error_code
493 check_constrained_delegation(krb5_context context
,
494 krb5_kdc_configuration
*config
,
496 hdb_entry_ex
*client
,
497 krb5_const_principal server
)
499 const HDB_Ext_Constrained_delegation_acl
*acl
;
503 /* if client delegates to itself, that ok */
504 if (krb5_principal_compare(context
, client
->entry
.principal
, server
) == TRUE
)
507 if (clientdb
->hdb_check_constrained_delegation
) {
508 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, server
);
512 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
514 krb5_clear_error_message(context
);
519 for (i
= 0; i
< acl
->len
; i
++) {
520 if (krb5_principal_compare(context
, server
, &acl
->val
[i
]) == TRUE
)
524 ret
= KRB5KDC_ERR_BADOPTION
;
526 kdc_log(context
, config
, 0,
527 "Bad request for constrained delegation");
532 * Determine if s4u2self is allowed from this client to this server
534 * For example, regardless of the principal being impersonated, if the
535 * 'client' and 'server' are the same, then it's safe.
538 static krb5_error_code
539 check_s4u2self(krb5_context context
,
540 krb5_kdc_configuration
*config
,
542 hdb_entry_ex
*client
,
543 krb5_const_principal server
)
547 /* if client does a s4u2self to itself, that ok */
548 if (krb5_principal_compare(context
, client
->entry
.principal
, server
) == TRUE
)
551 if (clientdb
->hdb_check_s4u2self
) {
552 ret
= clientdb
->hdb_check_s4u2self(context
, clientdb
, client
, server
);
556 ret
= KRB5KDC_ERR_BADOPTION
;
565 static krb5_error_code
566 verify_flags (krb5_context context
,
567 krb5_kdc_configuration
*config
,
568 const EncTicketPart
*et
,
571 if(et
->endtime
< kdc_time
){
572 kdc_log(context
, config
, 0, "Ticket expired (%s)", pstr
);
573 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
575 if(et
->flags
.invalid
){
576 kdc_log(context
, config
, 0, "Ticket not valid (%s)", pstr
);
577 return KRB5KRB_AP_ERR_TKT_NYV
;
586 static krb5_error_code
587 fix_transited_encoding(krb5_context context
,
588 krb5_kdc_configuration
*config
,
589 krb5_boolean check_policy
,
590 const TransitedEncoding
*tr
,
592 const char *client_realm
,
593 const char *server_realm
,
594 const char *tgt_realm
)
596 krb5_error_code ret
= 0;
597 char **realms
, **tmp
;
598 unsigned int num_realms
;
601 switch (tr
->tr_type
) {
602 case DOMAIN_X500_COMPRESS
:
606 * Allow empty content of type 0 because that is was Microsoft
607 * generates in their TGT.
609 if (tr
->contents
.length
== 0)
611 kdc_log(context
, config
, 0,
612 "Transited type 0 with non empty content");
613 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
615 kdc_log(context
, config
, 0,
616 "Unknown transited type: %u", tr
->tr_type
);
617 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
620 ret
= krb5_domain_x500_decode(context
,
627 krb5_warn(context
, ret
,
628 "Decoding transited encoding");
631 if(strcmp(client_realm
, tgt_realm
) && strcmp(server_realm
, tgt_realm
)) {
632 /* not us, so add the previous realm to transited set */
633 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
637 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
643 realms
[num_realms
] = strdup(tgt_realm
);
644 if(realms
[num_realms
] == NULL
){
650 if(num_realms
== 0) {
651 if(strcmp(client_realm
, server_realm
))
652 kdc_log(context
, config
, 0,
653 "cross-realm %s -> %s", client_realm
, server_realm
);
657 for(i
= 0; i
< num_realms
; i
++)
658 l
+= strlen(realms
[i
]) + 2;
662 for(i
= 0; i
< num_realms
; i
++) {
664 strlcat(rs
, ", ", l
);
665 strlcat(rs
, realms
[i
], l
);
667 kdc_log(context
, config
, 0,
668 "cross-realm %s -> %s via [%s]",
669 client_realm
, server_realm
, rs
);
674 ret
= krb5_check_transited(context
, client_realm
,
676 realms
, num_realms
, NULL
);
678 krb5_warn(context
, ret
, "cross-realm %s -> %s",
679 client_realm
, server_realm
);
682 et
->flags
.transited_policy_checked
= 1;
684 et
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
685 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
687 krb5_warn(context
, ret
, "Encoding transited encoding");
689 for(i
= 0; i
< num_realms
; i
++)
696 static krb5_error_code
697 tgs_make_reply(krb5_context context
,
698 krb5_kdc_configuration
*config
,
700 krb5_const_principal tgt_name
,
701 const EncTicketPart
*tgt
,
702 const krb5_keyblock
*replykey
,
704 const EncryptionKey
*serverkey
,
705 const krb5_keyblock
*sessionkey
,
707 AuthorizationData
*auth_data
,
708 hdb_entry_ex
*server
,
709 krb5_principal server_principal
,
710 const char *server_name
,
711 hdb_entry_ex
*client
,
712 krb5_principal client_principal
,
713 hdb_entry_ex
*krbtgt
,
714 krb5_enctype krbtgt_etype
,
716 const krb5_data
*rspac
,
717 const METHOD_DATA
*enc_pa_data
,
724 KDCOptions f
= b
->kdc_options
;
728 memset(&rep
, 0, sizeof(rep
));
729 memset(&et
, 0, sizeof(et
));
730 memset(&ek
, 0, sizeof(ek
));
733 rep
.msg_type
= krb_tgs_rep
;
735 et
.authtime
= tgt
->authtime
;
736 _kdc_fix_time(&b
->till
);
737 et
.endtime
= min(tgt
->endtime
, *b
->till
);
739 *et
.starttime
= kdc_time
;
741 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
745 /* We should check the transited encoding if:
746 1) the request doesn't ask not to be checked
747 2) globally enforcing a check
748 3) principal requires checking
749 4) we allow non-check per-principal, but principal isn't marked as allowing this
750 5) we don't globally allow this
753 #define GLOBAL_FORCE_TRANSITED_CHECK \
754 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
755 #define GLOBAL_ALLOW_PER_PRINCIPAL \
756 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
757 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
758 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
760 /* these will consult the database in future release */
761 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
762 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
764 ret
= fix_transited_encoding(context
, config
,
765 !f
.disable_transited_check
||
766 GLOBAL_FORCE_TRANSITED_CHECK
||
767 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
768 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
769 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
770 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
771 &tgt
->transited
, &et
,
772 krb5_principal_get_realm(context
, client_principal
),
773 krb5_principal_get_realm(context
, server
->entry
.principal
),
774 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
));
778 copy_Realm(&server_principal
->realm
, &rep
.ticket
.realm
);
779 _krb5_principal2principalname(&rep
.ticket
.sname
, server_principal
);
780 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
782 if (f.request_anonymous)
783 _kdc_make_anonymous_principalname (&rep.cname);
786 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
787 rep
.ticket
.tkt_vno
= 5;
791 et
.caddr
= tgt
->caddr
;
795 life
= et
.endtime
- *et
.starttime
;
796 if(client
&& client
->entry
.max_life
)
797 life
= min(life
, *client
->entry
.max_life
);
798 if(server
->entry
.max_life
)
799 life
= min(life
, *server
->entry
.max_life
);
800 et
.endtime
= *et
.starttime
+ life
;
802 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
803 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
){
804 et
.flags
.renewable
= 1;
805 ALLOC(et
.renew_till
);
806 *et
.renew_till
= *b
->till
;
810 renew
= *et
.renew_till
- et
.authtime
;
811 if(client
&& client
->entry
.max_renew
)
812 renew
= min(renew
, *client
->entry
.max_renew
);
813 if(server
->entry
.max_renew
)
814 renew
= min(renew
, *server
->entry
.max_renew
);
815 *et
.renew_till
= et
.authtime
+ renew
;
819 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
820 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
821 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
824 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
826 if(*et
.starttime
== et
.endtime
){
827 ret
= KRB5KDC_ERR_NEVER_VALID
;
830 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
832 et
.renew_till
= NULL
;
833 et
.flags
.renewable
= 0;
836 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
837 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
838 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
839 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
843 * No not need to filter out the any PAC from the
844 * auth_data since it's signed by the KDC.
846 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
847 KRB5_AUTHDATA_WIN2K_PAC
, rspac
);
855 /* XXX check authdata */
857 if (et
.authorization_data
== NULL
) {
858 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
859 if (et
.authorization_data
== NULL
) {
861 krb5_set_error_message(context
, ret
, "malloc: out of memory");
865 for(i
= 0; i
< auth_data
->len
; i
++) {
866 ret
= add_AuthorizationData(et
.authorization_data
, &auth_data
->val
[i
]);
868 krb5_set_error_message(context
, ret
, "malloc: out of memory");
873 /* Filter out type KRB5SignedPath */
874 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
876 if (et
.authorization_data
->len
== 1) {
877 free_AuthorizationData(et
.authorization_data
);
878 free(et
.authorization_data
);
879 et
.authorization_data
= NULL
;
881 AuthorizationData
*ad
= et
.authorization_data
;
882 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
888 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
891 et
.crealm
= tgt
->crealm
;
892 et
.cname
= tgt_name
->name
;
895 /* MIT must have at least one last_req */
897 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
898 if (ek
.last_req
.val
== NULL
) {
904 ek
.authtime
= et
.authtime
;
905 ek
.starttime
= et
.starttime
;
906 ek
.endtime
= et
.endtime
;
907 ek
.renew_till
= et
.renew_till
;
908 ek
.srealm
= rep
.ticket
.realm
;
909 ek
.sname
= rep
.ticket
.sname
;
911 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
912 et
.endtime
, et
.renew_till
);
914 /* Don't sign cross realm tickets, they can't be checked anyway */
916 char *r
= get_krbtgt_realm(&ek
.sname
);
918 if (r
== NULL
|| strcmp(r
, ek
.srealm
) == 0) {
919 ret
= _kdc_add_KRB5SignedPath(context
,
932 if (enc_pa_data
->len
) {
933 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
934 if (rep
.padata
== NULL
) {
938 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
943 if (krb5_enctype_valid(context
, et
.key
.keytype
) != 0
944 && _kdc_is_weak_exception(server
->entry
.principal
, et
.key
.keytype
))
946 krb5_enctype_enable(context
, et
.key
.keytype
);
951 /* It is somewhat unclear where the etype in the following
952 encryption should come from. What we have is a session
953 key in the passed tgt, and a list of preferred etypes
954 *for the new ticket*. Should we pick the best possible
955 etype, given the keytype in the tgt, or should we look
956 at the etype list here as well? What if the tgt
957 session key is DES3 and we want a ticket with a (say)
958 CAST session key. Should the DES3 etype be added to the
959 etype list, even if we don't want a session key with
961 ret
= _kdc_encode_reply(context
, config
,
962 &rep
, &et
, &ek
, et
.key
.keytype
,
964 serverkey
, 0, replykey
, rk_is_subkey
,
967 krb5_enctype_disable(context
, et
.key
.keytype
);
971 free_TransitedEncoding(&et
.transited
);
976 if(et
.authorization_data
) {
977 free_AuthorizationData(et
.authorization_data
);
978 free(et
.authorization_data
);
980 free_LastReq(&ek
.last_req
);
981 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
982 free_EncryptionKey(&et
.key
);
986 static krb5_error_code
987 tgs_check_authenticator(krb5_context context
,
988 krb5_kdc_configuration
*config
,
989 krb5_auth_context ac
,
994 krb5_authenticator auth
;
1001 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1002 if(auth
->cksum
== NULL
){
1003 kdc_log(context
, config
, 0, "No authenticator in request");
1004 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
1008 * according to RFC1510 it doesn't need to be keyed,
1009 * but according to the latest draft it needs to.
1013 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
1016 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
1017 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
1018 auth
->cksum
->cksumtype
);
1019 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
1023 /* XXX should not re-encode this */
1024 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
1026 const char *msg
= krb5_get_error_message(context
, ret
);
1027 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s", msg
);
1028 krb5_free_error_message(context
, msg
);
1031 if(buf_size
!= len
) {
1033 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
1034 *e_text
= "KDC internal error";
1035 ret
= KRB5KRB_ERR_GENERIC
;
1038 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
1040 const char *msg
= krb5_get_error_message(context
, ret
);
1042 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1043 krb5_free_error_message(context
, msg
);
1046 ret
= krb5_verify_checksum(context
,
1048 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
1053 krb5_crypto_destroy(context
, crypto
);
1055 const char *msg
= krb5_get_error_message(context
, ret
);
1056 kdc_log(context
, config
, 0,
1057 "Failed to verify authenticator checksum: %s", msg
);
1058 krb5_free_error_message(context
, msg
);
1061 free_Authenticator(auth
);
1071 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1073 const char *new_realm
= krb5_config_get_string(context
,
1084 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1085 const KDCOptions
* const options
, krb5_principal server
,
1086 krb5_realm
**realms
)
1090 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
1093 if (server
->name
.name_string
.len
== 1)
1094 name
= server
->name
.name_string
.val
[0];
1095 else if (server
->name
.name_string
.len
> 1)
1096 name
= server
->name
.name_string
.val
[1];
1100 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
1102 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
1105 static krb5_error_code
1106 tgs_parse_request(krb5_context context
,
1107 krb5_kdc_configuration
*config
,
1109 const PA_DATA
*tgs_req
,
1110 hdb_entry_ex
**krbtgt
,
1111 krb5_enctype
*krbtgt_etype
,
1112 krb5_ticket
**ticket
,
1113 const char **e_text
,
1115 const struct sockaddr
*from_addr
,
1118 AuthorizationData
**auth_data
,
1119 krb5_keyblock
**replykey
,
1123 krb5_error_code ret
;
1124 krb5_principal princ
;
1125 krb5_auth_context ac
= NULL
;
1126 krb5_flags ap_req_options
;
1127 krb5_flags verify_ap_req_flags
;
1130 krb5_keyblock
*subkey
= NULL
;
1138 memset(&ap_req
, 0, sizeof(ap_req
));
1139 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
1141 const char *msg
= krb5_get_error_message(context
, ret
);
1142 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s", msg
);
1143 krb5_free_error_message(context
, msg
);
1147 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1148 /* XXX check for ticket.sname == req.sname */
1149 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
1150 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1154 _krb5_principalname2krb5_principal(context
,
1156 ap_req
.ticket
.sname
,
1157 ap_req
.ticket
.realm
);
1159 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, NULL
, krbtgt
);
1162 const char *msg
= krb5_get_error_message(context
, ret
);
1164 ret
= krb5_unparse_name(context
, princ
, &p
);
1166 p
= "<unparse_name failed>";
1167 krb5_free_principal(context
, princ
);
1168 kdc_log(context
, config
, 0,
1169 "Ticket-granting ticket not found in database: %s", msg
);
1170 krb5_free_error_message(context
, msg
);
1173 ret
= KRB5KRB_AP_ERR_NOT_US
;
1177 if(ap_req
.ticket
.enc_part
.kvno
&&
1178 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
1181 ret
= krb5_unparse_name (context
, princ
, &p
);
1182 krb5_free_principal(context
, princ
);
1184 p
= "<unparse_name failed>";
1185 kdc_log(context
, config
, 0,
1186 "Ticket kvno = %d, DB kvno = %d (%s)",
1187 *ap_req
.ticket
.enc_part
.kvno
,
1188 (*krbtgt
)->entry
.kvno
,
1192 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1196 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1198 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1199 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1201 char *str
= NULL
, *p
= NULL
;
1203 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1204 krb5_unparse_name(context
, princ
, &p
);
1205 kdc_log(context
, config
, 0,
1206 "No server key with enctype %s found for %s",
1207 str
? str
: "<unknown enctype>",
1208 p
? p
: "<unparse_name failed>");
1211 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1215 if (b
->kdc_options
.validate
)
1216 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1218 verify_ap_req_flags
= 0;
1220 ret
= krb5_verify_ap_req2(context
,
1225 verify_ap_req_flags
,
1228 KRB5_KU_TGS_REQ_AUTH
);
1230 krb5_free_principal(context
, princ
);
1232 const char *msg
= krb5_get_error_message(context
, ret
);
1233 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s", msg
);
1234 krb5_free_error_message(context
, msg
);
1239 krb5_authenticator auth
;
1241 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1243 *csec
= malloc(sizeof(**csec
));
1244 if (*csec
== NULL
) {
1245 krb5_free_authenticator(context
, &auth
);
1246 kdc_log(context
, config
, 0, "malloc failed");
1249 **csec
= auth
->ctime
;
1250 *cusec
= malloc(sizeof(**cusec
));
1251 if (*cusec
== NULL
) {
1252 krb5_free_authenticator(context
, &auth
);
1253 kdc_log(context
, config
, 0, "malloc failed");
1256 **cusec
= auth
->cusec
;
1257 krb5_free_authenticator(context
, &auth
);
1261 ret
= tgs_check_authenticator(context
, config
,
1262 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1264 krb5_auth_con_free(context
, ac
);
1268 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1271 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
1273 const char *msg
= krb5_get_error_message(context
, ret
);
1274 krb5_auth_con_free(context
, ac
);
1275 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s", msg
);
1276 krb5_free_error_message(context
, msg
);
1280 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1283 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1285 const char *msg
= krb5_get_error_message(context
, ret
);
1286 krb5_auth_con_free(context
, ac
);
1287 kdc_log(context
, config
, 0, "Failed to get session key: %s", msg
);
1288 krb5_free_error_message(context
, msg
);
1293 krb5_auth_con_free(context
, ac
);
1294 kdc_log(context
, config
, 0,
1295 "Failed to get key for enc-authorization-data");
1296 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1302 if (b
->enc_authorization_data
) {
1305 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1307 const char *msg
= krb5_get_error_message(context
, ret
);
1308 krb5_auth_con_free(context
, ac
);
1309 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1310 krb5_free_error_message(context
, msg
);
1313 ret
= krb5_decrypt_EncryptedData (context
,
1316 b
->enc_authorization_data
,
1318 krb5_crypto_destroy(context
, crypto
);
1320 krb5_auth_con_free(context
, ac
);
1321 kdc_log(context
, config
, 0,
1322 "Failed to decrypt enc-authorization-data");
1323 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1327 if (*auth_data
== NULL
) {
1328 krb5_auth_con_free(context
, ac
);
1329 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1332 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1334 krb5_auth_con_free(context
, ac
);
1337 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1338 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1343 krb5_auth_con_free(context
, ac
);
1346 free_AP_REQ(&ap_req
);
1351 static krb5_error_code
1352 build_server_referral(krb5_context context
,
1353 krb5_kdc_configuration
*config
,
1354 krb5_crypto session
,
1355 krb5_const_realm referred_realm
,
1356 const PrincipalName
*true_principal_name
,
1357 const PrincipalName
*requested_principal
,
1360 PA_ServerReferralData ref
;
1361 krb5_error_code ret
;
1366 memset(&ref
, 0, sizeof(ref
));
1368 if (referred_realm
) {
1369 ALLOC(ref
.referred_realm
);
1370 if (ref
.referred_realm
== NULL
)
1372 *ref
.referred_realm
= strdup(referred_realm
);
1373 if (*ref
.referred_realm
== NULL
)
1376 if (true_principal_name
) {
1377 ALLOC(ref
.true_principal_name
);
1378 if (ref
.true_principal_name
== NULL
)
1380 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1384 if (requested_principal
) {
1385 ALLOC(ref
.requested_principal_name
);
1386 if (ref
.requested_principal_name
== NULL
)
1388 ret
= copy_PrincipalName(requested_principal
,
1389 ref
.requested_principal_name
);
1394 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1395 data
.data
, data
.length
,
1397 free_PA_ServerReferralData(&ref
);
1400 if (data
.length
!= size
)
1401 krb5_abortx(context
, "internal asn.1 encoder error");
1403 ret
= krb5_encrypt_EncryptedData(context
, session
,
1404 KRB5_KU_PA_SERVER_REFERRAL
,
1405 data
.data
, data
.length
,
1411 ASN1_MALLOC_ENCODE(EncryptedData
,
1412 outdata
->data
, outdata
->length
,
1414 free_EncryptedData(&ed
);
1417 if (outdata
->length
!= size
)
1418 krb5_abortx(context
, "internal asn.1 encoder error");
1422 free_PA_ServerReferralData(&ref
);
1423 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1427 static krb5_error_code
1428 tgs_build_reply(krb5_context context
,
1429 krb5_kdc_configuration
*config
,
1432 hdb_entry_ex
*krbtgt
,
1433 krb5_enctype krbtgt_etype
,
1434 const krb5_keyblock
*replykey
,
1436 krb5_ticket
*ticket
,
1439 const char **e_text
,
1440 AuthorizationData
**auth_data
,
1441 const struct sockaddr
*from_addr
)
1443 krb5_error_code ret
;
1444 krb5_principal cp
= NULL
, sp
= NULL
;
1445 krb5_principal client_principal
= NULL
;
1446 char *spn
= NULL
, *cpn
= NULL
;
1447 hdb_entry_ex
*server
= NULL
, *client
= NULL
, *s4u2self_impersonated_client
= NULL
;
1448 HDB
*clientdb
, *s4u2self_impersonated_clientdb
;
1449 krb5_realm ref_realm
= NULL
;
1450 EncTicketPart
*tgt
= &ticket
->ticket
;
1451 krb5_principals spp
= NULL
;
1452 const EncryptionKey
*ekey
;
1453 krb5_keyblock sessionkey
;
1457 METHOD_DATA enc_pa_data
;
1462 EncTicketPart adtkt
;
1468 memset(&sessionkey
, 0, sizeof(sessionkey
));
1469 memset(&adtkt
, 0, sizeof(adtkt
));
1470 krb5_data_zero(&rspac
);
1471 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1476 if(b
->kdc_options
.enc_tkt_in_skey
){
1482 if(b
->additional_tickets
== NULL
||
1483 b
->additional_tickets
->len
== 0){
1484 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1485 kdc_log(context
, config
, 0,
1486 "No second ticket present in request");
1489 t
= &b
->additional_tickets
->val
[0];
1490 if(!get_krbtgt_realm(&t
->sname
)){
1491 kdc_log(context
, config
, 0,
1492 "Additional ticket is not a ticket-granting ticket");
1493 ret
= KRB5KDC_ERR_POLICY
;
1496 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1497 ret
= _kdc_db_fetch(context
, config
, p
,
1498 HDB_F_GET_CLIENT
|HDB_F_GET_SERVER
,
1500 krb5_free_principal(context
, p
);
1502 if (ret
== HDB_ERR_NOENTRY
)
1503 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1506 ret
= hdb_enctype2key(context
, &uu
->entry
,
1507 t
->enc_part
.etype
, &uukey
);
1509 _kdc_free_ent(context
, uu
);
1510 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1513 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1514 _kdc_free_ent(context
, uu
);
1518 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1526 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1527 ret
= krb5_unparse_name(context
, sp
, &spn
);
1530 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1531 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1534 unparse_flags (KDCOptions2int(b
->kdc_options
),
1535 asn1_KDCOptions_units(),
1536 opt_str
, sizeof(opt_str
));
1538 kdc_log(context
, config
, 0,
1539 "TGS-REQ %s from %s for %s [%s]",
1540 cpn
, from
, spn
, opt_str
);
1542 kdc_log(context
, config
, 0,
1543 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1550 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
| HDB_F_CANON
,
1554 const char *new_rlm
, *msg
;
1558 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1560 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1562 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1563 "not found, trying %s",
1565 krb5_free_principal(context
, sp
);
1567 krb5_make_principal(context
, &sp
, r
,
1568 KRB5_TGS_NAME
, new_rlm
, NULL
);
1569 ret
= krb5_unparse_name(context
, sp
, &spn
);
1575 ref_realm
= strdup(new_rlm
);
1579 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1580 if (strcmp(realms
[0], sp
->realm
) != 0) {
1581 kdc_log(context
, config
, 5,
1582 "Returning a referral to realm %s for "
1583 "server %s that was not found",
1585 krb5_free_principal(context
, sp
);
1587 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1589 ret
= krb5_unparse_name(context
, sp
, &spn
);
1595 ref_realm
= strdup(realms
[0]);
1597 krb5_free_host_realm(context
, realms
);
1600 krb5_free_host_realm(context
, realms
);
1602 msg
= krb5_get_error_message(context
, ret
);
1603 kdc_log(context
, config
, 0,
1604 "Server not found in database: %s: %s", spn
, msg
);
1605 krb5_free_error_message(context
, msg
);
1606 if (ret
== HDB_ERR_NOENTRY
)
1607 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1611 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| HDB_F_CANON
,
1612 &clientdb
, &client
);
1614 const char *krbtgt_realm
, *msg
;
1617 * If the client belongs to the same realm as our krbtgt, it
1618 * should exist in the local database.
1623 krb5_principal_get_comp_string(context
,
1624 krbtgt
->entry
.principal
, 1);
1626 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1627 if (ret
== HDB_ERR_NOENTRY
)
1628 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1629 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1634 msg
= krb5_get_error_message(context
, ret
);
1635 kdc_log(context
, config
, 1, "Client not found in database: %s", msg
);
1636 krb5_free_error_message(context
, msg
);
1640 * Select enctype, return key and kvno.
1646 if(b
->kdc_options
.enc_tkt_in_skey
) {
1649 for(i
= 0; i
< b
->etype
.len
; i
++)
1650 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1652 if(i
== b
->etype
.len
) {
1653 kdc_log(context
, config
, 0,
1654 "Addition ticket have not matching etypes");
1655 krb5_clear_error_message(context
);
1656 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1659 etype
= b
->etype
.val
[i
];
1664 ret
= _kdc_find_etype(context
, server
,
1665 b
->etype
.val
, b
->etype
.len
, &skey
);
1667 kdc_log(context
, config
, 0,
1668 "Server (%s) has no support for etypes", spn
);
1672 etype
= skey
->key
.keytype
;
1673 kvno
= server
->entry
.kvno
;
1676 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1682 * Check that service is in the same realm as the krbtgt. If it's
1683 * not the same, it's someone that is using a uni-directional trust
1687 if (strcmp(krb5_principal_get_realm(context
, sp
),
1688 krb5_principal_get_comp_string(context
,
1689 krbtgt
->entry
.principal
,
1692 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &tpn
);
1693 kdc_log(context
, config
, 0,
1694 "Request with wrong krbtgt: %s",
1695 (ret
== 0) ? tpn
: "<unknown>");
1698 ret
= KRB5KRB_AP_ERR_NOT_US
;
1703 * Validate authoriation data
1706 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1707 krbtgt_etype
, &tkey
);
1709 kdc_log(context
, config
, 0,
1710 "Failed to find key for krbtgt PAC check");
1714 ret
= check_PAC(context
, config
, cp
,
1715 client
, server
, ekey
, &tkey
->key
,
1716 tgt
, &rspac
, &signedpath
);
1718 const char *msg
= krb5_get_error_message(context
, ret
);
1719 kdc_log(context
, config
, 0,
1720 "Verify PAC failed for %s (%s) from %s with %s",
1721 spn
, cpn
, from
, msg
);
1722 krb5_free_error_message(context
, msg
);
1726 /* also check the krbtgt for signature */
1727 ret
= check_KRB5SignedPath(context
,
1735 const char *msg
= krb5_get_error_message(context
, ret
);
1736 kdc_log(context
, config
, 0,
1737 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1738 spn
, cpn
, from
, msg
);
1739 krb5_free_error_message(context
, msg
);
1747 client_principal
= cp
;
1750 const PA_DATA
*sdata
;
1753 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1758 char *selfcpn
= NULL
;
1761 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1762 sdata
->padata_value
.length
,
1765 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1769 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1773 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1775 const char *msg
= krb5_get_error_message(context
, ret
);
1776 free_PA_S4U2Self(&self
);
1777 krb5_data_free(&datack
);
1778 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1779 krb5_free_error_message(context
, msg
);
1783 ret
= krb5_verify_checksum(context
,
1785 KRB5_KU_OTHER_CKSUM
,
1789 krb5_data_free(&datack
);
1790 krb5_crypto_destroy(context
, crypto
);
1792 const char *msg
= krb5_get_error_message(context
, ret
);
1793 free_PA_S4U2Self(&self
);
1794 kdc_log(context
, config
, 0,
1795 "krb5_verify_checksum failed for S4U2Self: %s", msg
);
1796 krb5_free_error_message(context
, msg
);
1800 ret
= _krb5_principalname2krb5_principal(context
,
1804 free_PA_S4U2Self(&self
);
1808 ret
= krb5_unparse_name(context
, client_principal
, &selfcpn
);
1812 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1815 krb5_data_free(&rspac
);
1816 ret
= _kdc_db_fetch(context
, config
, client_principal
, HDB_F_GET_CLIENT
| HDB_F_CANON
,
1817 &s4u2self_impersonated_clientdb
, &s4u2self_impersonated_client
);
1822 * If the client belongs to the same realm as our krbtgt, it
1823 * should exist in the local database.
1827 if (ret
== HDB_ERR_NOENTRY
)
1828 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1829 msg
= krb5_get_error_message(context
, ret
);
1830 kdc_log(context
, config
, 1, "S2U4Self principal to impersonate %s not found in database: %s", cpn
, msg
);
1831 krb5_free_error_message(context
, msg
);
1834 ret
= _kdc_pac_generate(context
, s4u2self_impersonated_client
, &p
);
1836 kdc_log(context
, config
, 0, "PAC generation failed for -- %s",
1841 ret
= _krb5_pac_sign(context
, p
, ticket
->ticket
.authtime
,
1842 s4u2self_impersonated_client
->entry
.principal
,
1845 krb5_pac_free(context
, p
);
1847 kdc_log(context
, config
, 0, "PAC signing failed for -- %s",
1855 * Check that service doing the impersonating is
1856 * requesting a ticket to it-self.
1858 ret
= check_s4u2self(context
, config
, clientdb
, client
, sp
);
1860 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1861 "to impersonate to service "
1862 "(tried for user %s to service %s)",
1869 * If the service isn't trusted for authentication to
1870 * delegation, remove the forward flag.
1873 if (client
->entry
.flags
.trusted_for_delegation
) {
1874 str
= "[forwardable]";
1876 b
->kdc_options
.forwardable
= 0;
1879 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
1880 "service %s %s", cpn
, selfcpn
, spn
, str
);
1886 * Constrained delegation
1890 && b
->additional_tickets
!= NULL
1891 && b
->additional_tickets
->len
!= 0
1892 && b
->kdc_options
.enc_tkt_in_skey
== 0)
1894 int ad_signedpath
= 0;
1900 * Require that the KDC have issued the service's krbtgt (not
1901 * self-issued ticket with kimpersonate(1).
1904 ret
= KRB5KDC_ERR_BADOPTION
;
1905 kdc_log(context
, config
, 0,
1906 "Constrained delegation done on service ticket %s/%s",
1911 t
= &b
->additional_tickets
->val
[0];
1913 ret
= hdb_enctype2key(context
, &client
->entry
,
1914 t
->enc_part
.etype
, &clientkey
);
1916 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1920 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
1922 kdc_log(context
, config
, 0,
1923 "failed to decrypt ticket for "
1924 "constrained delegation from %s to %s ", cpn
, spn
);
1928 /* check that ticket is valid */
1929 if (adtkt
.flags
.forwardable
== 0) {
1930 kdc_log(context
, config
, 0,
1931 "Missing forwardable flag on ticket for "
1932 "constrained delegation from %s to %s ", cpn
, spn
);
1933 ret
= KRB5KDC_ERR_BADOPTION
;
1937 ret
= check_constrained_delegation(context
, config
, clientdb
,
1940 kdc_log(context
, config
, 0,
1941 "constrained delegation from %s to %s not allowed",
1946 ret
= _krb5_principalname2krb5_principal(context
,
1953 ret
= krb5_unparse_name(context
, client_principal
, &str
);
1957 ret
= verify_flags(context
, config
, &adtkt
, str
);
1964 * Check that the KDC issued the user's ticket.
1966 ret
= check_KRB5SignedPath(context
,
1973 if (ret
== 0 && !ad_signedpath
)
1974 ret
= KRB5KDC_ERR_BADOPTION
;
1976 const char *msg
= krb5_get_error_message(context
, ret
);
1977 kdc_log(context
, config
, 0,
1978 "KRB5SignedPath check from service %s failed "
1979 "for delegation to %s for client %s "
1980 "from %s failed with %s",
1981 spn
, str
, cpn
, from
, msg
);
1982 krb5_free_error_message(context
, msg
);
1987 kdc_log(context
, config
, 0, "constrained delegation for %s "
1988 "from %s to %s", str
, cpn
, spn
);
1996 ret
= kdc_check_flags(context
, config
,
2003 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
2004 !krb5_principal_compare(context
,
2005 krbtgt
->entry
.principal
,
2006 server
->entry
.principal
)){
2007 kdc_log(context
, config
, 0, "Inconsistent request.");
2008 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
2012 /* check for valid set of addresses */
2013 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
2014 ret
= KRB5KRB_AP_ERR_BADADDR
;
2015 kdc_log(context
, config
, 0, "Request from wrong address");
2020 * If this is an referral, add server referral data to the
2027 kdc_log(context
, config
, 0,
2028 "Adding server referral to %s", ref_realm
);
2030 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
2034 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
2035 NULL
, s
, &pa
.padata_value
);
2036 krb5_crypto_destroy(context
, crypto
);
2038 kdc_log(context
, config
, 0,
2039 "Failed building server referral");
2042 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
2044 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
2045 krb5_data_free(&pa
.padata_value
);
2047 kdc_log(context
, config
, 0,
2048 "Add server referral METHOD-DATA failed");
2057 ret
= tgs_make_reply(context
,
2085 krb5_data_free(&rspac
);
2086 krb5_free_keyblock_contents(context
, &sessionkey
);
2088 _kdc_free_ent(context
, server
);
2090 _kdc_free_ent(context
, client
);
2091 if(s4u2self_impersonated_client
)
2092 _kdc_free_ent(context
, s4u2self_impersonated_client
);
2094 if (client_principal
&& client_principal
!= cp
)
2095 krb5_free_principal(context
, client_principal
);
2097 krb5_free_principal(context
, cp
);
2099 krb5_free_principal(context
, sp
);
2102 free_METHOD_DATA(&enc_pa_data
);
2104 free_EncTicketPart(&adtkt
);
2114 _kdc_tgs_rep(krb5_context context
,
2115 krb5_kdc_configuration
*config
,
2119 struct sockaddr
*from_addr
,
2122 AuthorizationData
*auth_data
= NULL
;
2123 krb5_error_code ret
;
2125 const PA_DATA
*tgs_req
;
2127 hdb_entry_ex
*krbtgt
= NULL
;
2128 krb5_ticket
*ticket
= NULL
;
2129 const char *e_text
= NULL
;
2130 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2132 krb5_keyblock
*replykey
= NULL
;
2133 int rk_is_subkey
= 0;
2134 time_t *csec
= NULL
;
2137 if(req
->padata
== NULL
){
2138 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2139 kdc_log(context
, config
, 0,
2140 "TGS-REQ from %s without PA-DATA", from
);
2144 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2146 if(tgs_req
== NULL
){
2147 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2149 kdc_log(context
, config
, 0,
2150 "TGS-REQ from %s without PA-TGS-REQ", from
);
2153 ret
= tgs_parse_request(context
, config
,
2154 &req
->req_body
, tgs_req
,
2165 kdc_log(context
, config
, 0,
2166 "Failed parsing TGS-REQ from %s", from
);
2170 ret
= tgs_build_reply(context
,
2185 kdc_log(context
, config
, 0,
2186 "Failed building TGS-REP to %s", from
);
2191 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2192 krb5_data_free(data
);
2193 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2194 e_text
= "Reply packet too large";
2199 krb5_free_keyblock(context
, replykey
);
2200 if(ret
&& data
->data
== NULL
){
2201 krb5_mk_error(context
,
2214 krb5_free_ticket(context
, ticket
);
2216 _kdc_free_ent(context
, krbtgt
);
2219 free_AuthorizationData(auth_data
);