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
, NULL
, 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
, NULL
, /* XXX use correct kvno! */
232 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
235 free_KRB5SignedPath(&sp
);
239 ret
= krb5_verify_checksum(context
, crypto
, KRB5_KU_KRB5SIGNEDPATH
,
240 data
.data
, data
.length
,
242 krb5_crypto_destroy(context
, crypto
);
245 free_KRB5SignedPath(&sp
);
246 kdc_log(context
, config
, 5,
247 "KRB5SignedPath not signed correctly, not marking as signed");
251 if (delegated
&& sp
.delegated
) {
253 *delegated
= malloc(sizeof(*sp
.delegated
));
254 if (*delegated
== NULL
) {
255 free_KRB5SignedPath(&sp
);
259 ret
= copy_Principals(*delegated
, sp
.delegated
);
261 free_KRB5SignedPath(&sp
);
267 free_KRB5SignedPath(&sp
);
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
,
295 AuthorizationData
*ad
= tkt
->authorization_data
;
299 if (ad
== NULL
|| ad
->len
== 0)
302 for (i
= 0; i
< ad
->len
; i
++) {
303 AuthorizationData child
;
305 if (ad
->val
[i
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
308 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
309 ad
->val
[i
].ad_data
.length
,
313 krb5_set_error_message(context
, ret
, "Failed to decode "
314 "IF_RELEVANT with %d", ret
);
317 for (j
= 0; j
< child
.len
; j
++) {
319 if (child
.val
[j
].ad_type
== KRB5_AUTHDATA_WIN2K_PAC
) {
324 ret
= krb5_pac_parse(context
,
325 child
.val
[j
].ad_data
.data
,
326 child
.val
[j
].ad_data
.length
,
328 free_AuthorizationData(&child
);
332 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
,
334 server_check_key
, krbtgt_check_key
);
336 krb5_pac_free(context
, pac
);
340 ret
= _kdc_pac_verify(context
, client_principal
,
341 delegated_proxy_principal
,
342 client
, server
, krbtgt
, &pac
, &signed_pac
);
344 krb5_pac_free(context
, pac
);
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.
356 ret
= _krb5_pac_sign(context
, pac
, tkt
->authtime
,
358 server_sign_key
, krbtgt_sign_key
, rspac
);
360 krb5_pac_free(context
, pac
);
365 free_AuthorizationData(&child
);
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
;
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
;
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
;
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;
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;
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;
429 if(!tgt
->flags
.proxiable
){
430 kdc_log(context
, config
, 0,
431 "Request to proxy non-proxiable ticket");
432 return KRB5KDC_ERR_BADOPTION
;
435 et
->caddr
= b
->addresses
;
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;
449 if(!tgt
->flags
.may_postdate
){
450 kdc_log(context
, config
, 0,
451 "Bad request for postdated ticket");
452 return KRB5KDC_ERR_BADOPTION
;
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
;
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
;
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
;
483 old_life
-= *tgt
->starttime
;
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
);
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
;
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
,
510 hdb_entry_ex
*client
,
511 hdb_entry_ex
*server
,
512 krb5_const_principal target
)
514 const HDB_Ext_Constrained_delegation_acl
*acl
;
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");
531 if (clientdb
->hdb_check_constrained_delegation
) {
532 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, target
);
536 /* if client delegates to itself, that ok */
537 if (krb5_principal_compare(context
, client
->entry
.principal
, server
->entry
.principal
) == TRUE
)
540 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
542 krb5_clear_error_message(context
);
547 for (i
= 0; i
< acl
->len
; i
++) {
548 if (krb5_principal_compare(context
, target
, &acl
->val
[i
]) == TRUE
)
552 ret
= KRB5KDC_ERR_BADOPTION
;
554 kdc_log(context
, config
, 0,
555 "Bad request for constrained delegation");
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
,
570 hdb_entry_ex
*client
,
571 krb5_const_principal server
)
575 /* if client does a s4u2self to itself, that ok */
576 if (krb5_principal_compare(context
, client
->entry
.principal
, server
) == TRUE
)
579 if (clientdb
->hdb_check_s4u2self
) {
580 ret
= clientdb
->hdb_check_s4u2self(context
, clientdb
, client
, server
);
584 ret
= KRB5KDC_ERR_BADOPTION
;
593 static krb5_error_code
594 verify_flags (krb5_context context
,
595 krb5_kdc_configuration
*config
,
596 const EncTicketPart
*et
,
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
;
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
,
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
;
629 switch (tr
->tr_type
) {
630 case DOMAIN_X500_COMPRESS
:
634 * Allow empty content of type 0 because that is was Microsoft
635 * generates in their TGT.
637 if (tr
->contents
.length
== 0)
639 kdc_log(context
, config
, 0,
640 "Transited type 0 with non empty content");
641 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
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
,
655 krb5_warn(context
, ret
,
656 "Decoding transited encoding");
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
)) {
665 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
671 realms
[num_realms
] = strdup(tgt_realm
);
672 if(realms
[num_realms
] == NULL
){
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
);
685 for(i
= 0; i
< num_realms
; i
++)
686 l
+= strlen(realms
[i
]) + 2;
690 for(i
= 0; i
< num_realms
; i
++) {
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
);
702 ret
= krb5_check_transited(context
, client_realm
,
704 realms
, num_realms
, NULL
);
706 krb5_warn(context
, ret
, "cross-realm %s -> %s",
707 client_realm
, server_realm
);
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
);
715 krb5_warn(context
, ret
, "Encoding transited encoding");
717 for(i
= 0; i
< num_realms
; i
++)
724 static krb5_error_code
725 tgs_make_reply(krb5_context context
,
726 krb5_kdc_configuration
*config
,
728 krb5_const_principal tgt_name
,
729 const EncTicketPart
*tgt
,
730 const krb5_keyblock
*replykey
,
732 const EncryptionKey
*serverkey
,
733 const krb5_keyblock
*sessionkey
,
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
,
744 const krb5_data
*rspac
,
745 const METHOD_DATA
*enc_pa_data
,
752 KDCOptions f
= b
->kdc_options
;
756 memset(&rep
, 0, sizeof(rep
));
757 memset(&et
, 0, sizeof(et
));
758 memset(&ek
, 0, sizeof(ek
));
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
);
767 *et
.starttime
= kdc_time
;
769 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
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
));
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);
814 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
815 rep
.ticket
.tkt_vno
= 5;
819 et
.caddr
= tgt
->caddr
;
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
;
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
;
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
;
860 if(et
.renew_till
&& et
.endtime
== *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
;
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
);
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
) {
891 krb5_set_error_message(context
, ret
, "malloc: out of memory");
895 for(i
= 0; i
< auth_data
->len
; i
++) {
896 ret
= add_AuthorizationData(et
.authorization_data
, &auth_data
->val
[i
]);
898 krb5_set_error_message(context
, ret
, "malloc: out of memory");
903 /* Filter out type KRB5SignedPath */
904 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
906 if (et
.authorization_data
->len
== 1) {
907 free_AuthorizationData(et
.authorization_data
);
908 free(et
.authorization_data
);
909 et
.authorization_data
= NULL
;
911 AuthorizationData
*ad
= et
.authorization_data
;
912 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
918 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
921 et
.crealm
= tgt_name
->realm
;
922 et
.cname
= tgt_name
->name
;
925 /* MIT must have at least one last_req */
927 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
928 if (ek
.last_req
.val
== NULL
) {
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
,
962 if (enc_pa_data
->len
) {
963 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
964 if (rep
.padata
== NULL
) {
968 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
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
);
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
991 ret
= _kdc_encode_reply(context
, config
, NULL
, 0,
992 &rep
, &et
, &ek
, serverkey
->keytype
,
994 serverkey
, 0, replykey
, rk_is_subkey
,
997 krb5_enctype_disable(context
, et
.key
.keytype
);
1001 free_TransitedEncoding(&et
.transited
);
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
);
1016 static krb5_error_code
1017 tgs_check_authenticator(krb5_context context
,
1018 krb5_kdc_configuration
*config
,
1019 krb5_auth_context ac
,
1021 const char **e_text
,
1024 krb5_authenticator auth
;
1028 krb5_error_code ret
;
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
;
1038 * according to RFC1510 it doesn't need to be keyed,
1039 * but according to the latest draft it needs to.
1043 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
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
;
1053 /* XXX should not re-encode this */
1054 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, 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
);
1061 if(buf_size
!= len
) {
1063 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
1064 *e_text
= "KDC internal error";
1065 ret
= KRB5KRB_ERR_GENERIC
;
1068 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
1070 const char *msg
= krb5_get_error_message(context
, ret
);
1072 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1073 krb5_free_error_message(context
, msg
);
1076 ret
= krb5_verify_checksum(context
,
1078 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
1083 krb5_crypto_destroy(context
, crypto
);
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
);
1091 free_Authenticator(auth
);
1101 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1103 const char *new_realm
= krb5_config_get_string(context
,
1114 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1115 const KDCOptions
* const options
, krb5_principal server
,
1116 krb5_realm
**realms
)
1120 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
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];
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
,
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
,
1145 const struct sockaddr
*from_addr
,
1148 AuthorizationData
**auth_data
,
1149 krb5_keyblock
**replykey
,
1152 static char failed
[] = "<unparse_name failed>";
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
;
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 */
1165 krb5_keyblock
*subkey
= NULL
;
1173 memset(&ap_req
, 0, sizeof(ap_req
));
1174 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
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
);
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
; /* ? */
1189 _krb5_principalname2krb5_principal(context
,
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 */
1202 ret
= krb5_unparse_name(context
, princ
, &p
);
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
);
1211 ret
= HDB_ERR_NOT_FOUND_HERE
;
1213 } else if (ret
== HDB_ERR_KVNO_NOT_FOUND
) {
1215 ret
= krb5_unparse_name(context
, princ
, &p
);
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
);
1224 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1226 } else if (ret
== HDB_ERR_NO_MKEY
) {
1228 ret
= krb5_unparse_name(context
, princ
, &p
);
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
);
1237 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1240 const char *msg
= krb5_get_error_message(context
, ret
);
1242 ret
= krb5_unparse_name(context
, princ
, &p
);
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
);
1251 ret
= KRB5KRB_AP_ERR_NOT_US
;
1255 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
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
--;
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>");
1276 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1280 if (b
->kdc_options
.validate
)
1281 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1283 verify_ap_req_flags
= 0;
1285 ret
= krb5_verify_ap_req2(context
,
1290 verify_ap_req_flags
,
1293 KRB5_KU_TGS_REQ_AUTH
);
1294 if (ret
== KRB5KRB_AP_ERR_BAD_INTEGRITY
&& kvno_search_tries
> 0) {
1295 kvno_search_tries
--;
1300 krb5_free_principal(context
, princ
);
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
);
1309 krb5_authenticator auth
;
1311 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1313 *csec
= malloc(sizeof(**csec
));
1314 if (*csec
== NULL
) {
1315 krb5_free_authenticator(context
, &auth
);
1316 kdc_log(context
, config
, 0, "malloc failed");
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");
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
);
1334 krb5_auth_con_free(context
, ac
);
1338 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1341 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
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
);
1350 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1353 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
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
);
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
; /* ? */
1372 if (b
->enc_authorization_data
) {
1375 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
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
);
1383 ret
= krb5_decrypt_EncryptedData (context
,
1386 b
->enc_authorization_data
,
1388 krb5_crypto_destroy(context
, crypto
);
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
; /* ? */
1397 if (*auth_data
== NULL
) {
1398 krb5_auth_con_free(context
, ac
);
1399 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1402 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1404 krb5_auth_con_free(context
, ac
);
1407 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1408 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1413 krb5_auth_con_free(context
, ac
);
1416 free_AP_REQ(&ap_req
);
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
,
1430 PA_ServerReferralData ref
;
1431 krb5_error_code ret
;
1436 memset(&ref
, 0, sizeof(ref
));
1438 if (referred_realm
) {
1439 ALLOC(ref
.referred_realm
);
1440 if (ref
.referred_realm
== NULL
)
1442 *ref
.referred_realm
= strdup(referred_realm
);
1443 if (*ref
.referred_realm
== NULL
)
1446 if (true_principal_name
) {
1447 ALLOC(ref
.true_principal_name
);
1448 if (ref
.true_principal_name
== NULL
)
1450 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1454 if (requested_principal
) {
1455 ALLOC(ref
.requested_principal_name
);
1456 if (ref
.requested_principal_name
== NULL
)
1458 ret
= copy_PrincipalName(requested_principal
,
1459 ref
.requested_principal_name
);
1464 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1465 data
.data
, data
.length
,
1467 free_PA_ServerReferralData(&ref
);
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
,
1481 ASN1_MALLOC_ENCODE(EncryptedData
,
1482 outdata
->data
, outdata
->length
,
1484 free_EncryptedData(&ed
);
1487 if (outdata
->length
!= size
)
1488 krb5_abortx(context
, "internal asn.1 encoder error");
1492 free_PA_ServerReferralData(&ref
);
1493 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1497 static krb5_error_code
1498 tgs_build_reply(krb5_context context
,
1499 krb5_kdc_configuration
*config
,
1502 hdb_entry_ex
*krbtgt
,
1503 krb5_enctype krbtgt_etype
,
1504 const krb5_keyblock
*replykey
,
1506 krb5_ticket
*ticket
,
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
;
1527 hdb_entry_ex
*krbtgt_out
= NULL
;
1529 METHOD_DATA enc_pa_data
;
1534 EncTicketPart adtkt
;
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
));
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
){
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");
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
;
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
,
1580 krb5_free_principal(context
, p
);
1582 if (ret
== HDB_ERR_NOENTRY
)
1583 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1586 ret
= hdb_enctype2key(context
, &uu
->entry
, NULL
,
1587 t
->enc_part
.etype
, &uukey
);
1589 _kdc_free_ent(context
, uu
);
1590 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1593 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1594 _kdc_free_ent(context
, uu
);
1598 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1606 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1607 ret
= krb5_unparse_name(context
, sp
, &spn
);
1610 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1611 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1614 unparse_flags (KDCOptions2int(b
->kdc_options
),
1615 asn1_KDCOptions_units(),
1616 opt_str
, sizeof(opt_str
));
1618 kdc_log(context
, config
, 0,
1619 "TGS-REQ %s from %s for %s [%s]",
1620 cpn
, from
, spn
, opt_str
);
1622 kdc_log(context
, config
, 0,
1623 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
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
);
1637 const char *new_rlm
, *msg
;
1641 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1643 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1645 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1646 "not found, trying %s",
1648 krb5_free_principal(context
, sp
);
1650 krb5_make_principal(context
, &sp
, r
,
1651 KRB5_TGS_NAME
, new_rlm
, NULL
);
1652 ret
= krb5_unparse_name(context
, sp
, &spn
);
1658 ref_realm
= strdup(new_rlm
);
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",
1668 krb5_free_principal(context
, sp
);
1670 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1672 ret
= krb5_unparse_name(context
, sp
, &spn
);
1678 ref_realm
= strdup(realms
[0]);
1680 krb5_free_host_realm(context
, realms
);
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
;
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
;
1707 * Select enctype, return key and kvno.
1713 if(b
->kdc_options
.enc_tkt_in_skey
) {
1716 for(i
= 0; i
< b
->etype
.len
; i
++)
1717 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
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
;
1726 etype
= b
->etype
.val
[i
];
1731 ret
= _kdc_find_etype(context
,
1732 config
->tgs_use_strongest_session_key
, FALSE
,
1733 server
, b
->etype
.val
, b
->etype
.len
, &etype
,
1736 kdc_log(context
, config
, 0,
1737 "Server (%s) has no support for etypes", spn
);
1740 ret
= _kdc_get_preferred_key(context
, config
, server
, spn
,
1743 kdc_log(context
, config
, 0,
1744 "Server (%s) has no supported etypes", spn
);
1748 kvno
= server
->entry
.kvno
;
1751 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
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
1763 * Validate authoriation data
1766 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, NULL
, /* XXX use the right kvno! */
1767 krbtgt_etype
, &tkey_check
);
1769 kdc_log(context
, config
, 0,
1770 "Failed to find key for krbtgt PAC check");
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
,
1791 kdc_log(context
, config
, 0,
1792 "Failed to make krbtgt principal name object for "
1793 "authz-data signatures");
1796 ret
= krb5_unparse_name(context
, krbtgt_out_principal
, &krbtgt_out_n
);
1798 kdc_log(context
, config
, 0,
1799 "Failed to make krbtgt principal name object for "
1800 "authz-data signatures");
1805 ret
= _kdc_db_fetch(context
, config
, krbtgt_out_principal
,
1806 HDB_F_GET_KRBTGT
, NULL
, NULL
, &krbtgt_out
);
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>");
1815 ret
= KRB5KRB_AP_ERR_NOT_US
;
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) {
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>");
1835 ret
= KRB5KRB_AP_ERR_NOT_US
;
1839 ret
= _kdc_get_preferred_key(context
, config
, krbtgt_out
, krbtgt_out_n
,
1842 kdc_log(context
, config
, 0,
1843 "Failed to find key for krbtgt PAC signature");
1846 ret
= hdb_enctype2key(context
, &krbtgt_out
->entry
, NULL
,
1847 tkey_sign
->key
.keytype
, &tkey_sign
);
1849 kdc_log(context
, config
, 0,
1850 "Failed to find key for krbtgt PAC signature");
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
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",
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
,
1897 tkey_krbtgt_check
? &tkey_krbtgt_check
->key
: NULL
,
1898 ekey
, &tkey_sign
->key
,
1899 tgt
, &rspac
, &signedpath
);
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
);
1909 /* also check the krbtgt for signature */
1910 ret
= check_KRB5SignedPath(context
,
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
);
1930 /* by default the tgt principal matches the client principal */
1935 const PA_DATA
*sdata
;
1938 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1945 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1946 sdata
->padata_value
.length
,
1949 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1953 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1957 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
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
);
1967 ret
= krb5_verify_checksum(context
,
1969 KRB5_KU_OTHER_CKSUM
,
1973 krb5_data_free(&datack
);
1974 krb5_crypto_destroy(context
, crypto
);
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
);
1984 ret
= _krb5_principalname2krb5_principal(context
,
1988 free_PA_S4U2Self(&self
);
1992 ret
= krb5_unparse_name(context
, tp
, &tpn
);
1996 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
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
);
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",
2017 krb5_free_error_message(context
, msg
);
2020 ret
= _kdc_pac_generate(context
, s4u2self_impersonated_client
, &p
);
2022 kdc_log(context
, config
, 0, "PAC generation failed for -- %s",
2027 ret
= _krb5_pac_sign(context
, p
, ticket
->ticket
.authtime
,
2028 s4u2self_impersonated_client
->entry
.principal
,
2029 ekey
, &tkey_sign
->key
,
2031 krb5_pac_free(context
, p
);
2033 kdc_log(context
, config
, 0, "PAC signing failed for -- %s",
2041 * Check that service doing the impersonating is
2042 * requesting a ticket to it-self.
2044 ret
= check_s4u2self(context
, config
, clientdb
, client
, sp
);
2046 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
2047 "to impersonate to service "
2048 "(tried for user %s to service %s)",
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]";
2061 b
->kdc_options
.forwardable
= 0;
2064 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
2065 "service %s %s", cpn
, tpn
, spn
, str
);
2070 * Constrained delegation
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;
2083 * Require that the KDC have issued the service's krbtgt (not
2084 * self-issued ticket with kimpersonate(1).
2087 ret
= KRB5KDC_ERR_BADOPTION
;
2088 kdc_log(context
, config
, 0,
2089 "Constrained delegation done on service ticket %s/%s",
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
);
2101 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
2105 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
2107 kdc_log(context
, config
, 0,
2108 "failed to decrypt ticket for "
2109 "constrained delegation from %s to %s ", cpn
, spn
);
2113 ret
= _krb5_principalname2krb5_principal(context
,
2120 ret
= krb5_unparse_name(context
, tp
, &tpn
);
2124 ret
= _krb5_principalname2krb5_principal(context
,
2131 ret
= krb5_unparse_name(context
, dp
, &dpn
);
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
;
2145 ret
= check_constrained_delegation(context
, config
, clientdb
,
2146 client
, server
, sp
);
2148 kdc_log(context
, config
, 0,
2149 "constrained delegation from %s (%s) as %s to %s not allowed",
2150 cpn
, dpn
, tpn
, spn
);
2154 ret
= verify_flags(context
, config
, &adtkt
, tpn
);
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
);
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
);
2183 * Check that the KDC issued the user's ticket.
2185 ret
= check_KRB5SignedPath(context
,
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
);
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)"
2209 spn
, tpn
, dpn
, cpn
, from
);
2213 kdc_log(context
, config
, 0, "constrained delegation for %s "
2214 "from %s (%s) to %s", tpn
, cpn
, dpn
, spn
);
2221 ret
= kdc_check_flags(context
, config
,
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
;
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");
2245 * If this is an referral, add server referral data to the
2252 kdc_log(context
, config
, 0,
2253 "Adding server referral to %s", ref_realm
);
2255 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
2259 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
2260 NULL
, s
, &pa
.padata_value
);
2261 krb5_crypto_destroy(context
, crypto
);
2263 kdc_log(context
, config
, 0,
2264 "Failed building server referral");
2267 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
2269 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
2270 krb5_data_free(&pa
.padata_value
);
2272 kdc_log(context
, config
, 0,
2273 "Add server referral METHOD-DATA failed");
2282 ret
= tgs_make_reply(context
,
2299 tkey_sign
->key
.keytype
,
2314 krb5_data_free(&rspac
);
2315 krb5_free_keyblock_contents(context
, &sessionkey
);
2317 _kdc_free_ent(context
, krbtgt_out
);
2319 _kdc_free_ent(context
, server
);
2321 _kdc_free_ent(context
, client
);
2322 if(s4u2self_impersonated_client
)
2323 _kdc_free_ent(context
, s4u2self_impersonated_client
);
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
);
2333 free_METHOD_DATA(&enc_pa_data
);
2335 free_EncTicketPart(&adtkt
);
2345 _kdc_tgs_rep(krb5_context context
,
2346 krb5_kdc_configuration
*config
,
2350 struct sockaddr
*from_addr
,
2353 AuthorizationData
*auth_data
= NULL
;
2354 krb5_error_code ret
;
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
;
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
);
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
);
2384 ret
= tgs_parse_request(context
, config
,
2385 &req
->req_body
, tgs_req
,
2395 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2396 /* kdc_log() is called in tgs_parse_request() */
2400 kdc_log(context
, config
, 0,
2401 "Failed parsing TGS-REQ from %s", from
);
2407 const PA_DATA
*pa
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FX_FAST
);
2409 kdc_log(context
, config
, 10, "Got TGS FAST request");
2413 ret
= tgs_build_reply(context
,
2428 kdc_log(context
, config
, 0,
2429 "Failed building TGS-REP to %s", from
);
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";
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
,
2458 free_METHOD_DATA(&error_method
);
2463 krb5_free_ticket(context
, ticket
);
2465 _kdc_free_ent(context
, krbtgt
);
2468 free_AuthorizationData(auth_data
);