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 * return TRUE if client was a synthetic principal, as indicated by
55 _kdc_synthetic_princ_used_p(krb5_context context
, krb5_ticket
*ticket
)
57 krb5_data synthetic_princ_used
;
60 ret
= krb5_ticket_get_authorization_data_type(context
, ticket
,
61 KRB5_AUTHDATA_SYNTHETIC_PRINC_USED
,
62 &synthetic_princ_used
);
64 ret
= krb5_ticket_get_authorization_data_type(context
, ticket
,
65 KRB5_AUTHDATA_INITIAL_VERIFIED_CAS
,
66 &synthetic_princ_used
);
69 krb5_data_free(&synthetic_princ_used
);
79 _kdc_check_pac(krb5_context context
,
80 krb5_kdc_configuration
*config
,
81 const krb5_principal client_principal
,
82 const krb5_principal delegated_proxy_principal
,
86 hdb_entry_ex
*ticket_server
,
87 const EncryptionKey
*server_check_key
,
88 const EncryptionKey
*krbtgt_check_key
,
90 krb5_boolean
*kdc_issued
,
92 krb5_principal
*pac_canon_name
,
93 uint64_t *pac_attributes
)
97 krb5_boolean signedticket
;
102 *pac_canon_name
= NULL
;
104 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
106 ret
= _krb5_kdc_pac_ticket_parse(context
, tkt
, &signedticket
, &pac
);
111 if (config
->require_pac
)
112 ret
= KRB5KDC_ERR_TGT_REVOKED
;
116 /* Verify the server signature. */
117 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
, client_principal
,
118 server_check_key
, NULL
);
120 krb5_pac_free(context
, pac
);
124 /* Verify the KDC signatures. */
125 ret
= _kdc_pac_verify(context
, client_principal
, delegated_proxy_principal
,
126 client
, server
, krbtgt
, &pac
);
128 if (pac_canon_name
) {
129 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
130 if (ret
&& ret
!= ENOENT
) {
131 krb5_pac_free(context
, pac
);
135 if (pac_attributes
&&
136 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
137 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
138 } else if (ret
== KRB5_PLUGIN_NO_HANDLE
) {
140 * We can't verify the KDC signatures if the ticket was issued by
141 * another realm's KDC.
143 if (krb5_realm_compare(context
, server
->entry
.principal
,
144 ticket_server
->entry
.principal
)) {
145 ret
= krb5_pac_verify(context
, pac
, 0, NULL
, NULL
,
148 krb5_pac_free(context
, pac
);
153 if (pac_canon_name
) {
154 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
155 if (ret
&& ret
!= ENOENT
) {
156 krb5_pac_free(context
, pac
);
159 if (pac_attributes
&&
160 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
161 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
164 /* Discard the PAC if the plugin didn't handle it */
165 krb5_pac_free(context
, pac
);
166 ret
= krb5_pac_init(context
, &pac
);
170 krb5_pac_free(context
, pac
);
174 *kdc_issued
= signedticket
||
175 krb5_principal_is_krbtgt(context
,
176 ticket_server
->entry
.principal
);
183 is_anon_tgs_request_p(const KDC_REQ_BODY
*b
,
184 const EncTicketPart
*tgt
)
186 KDCOptions f
= b
->kdc_options
;
189 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
190 * request-anonymous and cname-in-addl-tkt flags for constrained
191 * delegation requests. A true anonymous TGS request will only
192 * have the request-anonymous flag set. (A corollary of this is
193 * that it is not possible to support anonymous constrained
194 * delegation requests, although they would be of limited utility.)
196 return tgt
->flags
.anonymous
||
197 (f
.request_anonymous
&& !f
.cname_in_addl_tkt
&& !b
->additional_tickets
);
204 static krb5_error_code
205 check_tgs_flags(astgs_request_t r
, KDC_REQ_BODY
*b
,
206 krb5_const_principal tgt_name
,
207 const EncTicketPart
*tgt
, EncTicketPart
*et
)
209 KDCOptions f
= b
->kdc_options
;
212 if (!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
) {
213 _kdc_audit_addreason((kdc_request_t
)r
,
214 "Bad request to validate ticket");
215 return KRB5KDC_ERR_BADOPTION
;
217 if(*tgt
->starttime
> kdc_time
){
218 _kdc_audit_addreason((kdc_request_t
)r
,
219 "Early request to validate ticket");
220 return KRB5KRB_AP_ERR_TKT_NYV
;
223 et
->flags
.invalid
= 0;
224 } else if (tgt
->flags
.invalid
) {
225 _kdc_audit_addreason((kdc_request_t
)r
,
226 "Ticket-granting ticket has INVALID flag set");
227 return KRB5KRB_AP_ERR_TKT_INVALID
;
231 if (!tgt
->flags
.forwardable
) {
232 _kdc_audit_addreason((kdc_request_t
)r
,
233 "Bad request for forwardable ticket");
234 return KRB5KDC_ERR_BADOPTION
;
236 et
->flags
.forwardable
= 1;
239 if (!tgt
->flags
.forwardable
) {
240 _kdc_audit_addreason((kdc_request_t
)r
,
241 "Request to forward non-forwardable ticket");
242 return KRB5KDC_ERR_BADOPTION
;
244 et
->flags
.forwarded
= 1;
245 et
->caddr
= b
->addresses
;
247 if(tgt
->flags
.forwarded
)
248 et
->flags
.forwarded
= 1;
251 if (!tgt
->flags
.proxiable
) {
252 _kdc_audit_addreason((kdc_request_t
)r
,
253 "Bad request for proxiable ticket");
254 return KRB5KDC_ERR_BADOPTION
;
256 et
->flags
.proxiable
= 1;
259 if (!tgt
->flags
.proxiable
) {
260 _kdc_audit_addreason((kdc_request_t
)r
,
261 "Request to proxy non-proxiable ticket");
262 return KRB5KDC_ERR_BADOPTION
;
265 et
->caddr
= b
->addresses
;
270 if(f
.allow_postdate
){
271 if (!tgt
->flags
.may_postdate
) {
272 _kdc_audit_addreason((kdc_request_t
)r
,
273 "Bad request for post-datable ticket");
274 return KRB5KDC_ERR_BADOPTION
;
276 et
->flags
.may_postdate
= 1;
279 if (!tgt
->flags
.may_postdate
) {
280 _kdc_audit_addreason((kdc_request_t
)r
,
281 "Bad request for postdated ticket");
282 return KRB5KDC_ERR_BADOPTION
;
285 *et
->starttime
= *b
->from
;
286 et
->flags
.postdated
= 1;
287 et
->flags
.invalid
= 1;
288 } else if (b
->from
&& *b
->from
> kdc_time
+ r
->context
->max_skew
) {
289 _kdc_audit_addreason((kdc_request_t
)r
,
290 "Ticket cannot be postdated");
291 return KRB5KDC_ERR_CANNOT_POSTDATE
;
295 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
296 _kdc_audit_addreason((kdc_request_t
)r
,
297 "Bad request for renewable ticket");
298 return KRB5KDC_ERR_BADOPTION
;
300 et
->flags
.renewable
= 1;
301 ALLOC(et
->renew_till
);
302 _kdc_fix_time(&b
->rtime
);
303 *et
->renew_till
= *b
->rtime
;
307 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
308 _kdc_audit_addreason((kdc_request_t
)r
,
309 "Request to renew non-renewable ticket");
310 return KRB5KDC_ERR_BADOPTION
;
312 old_life
= tgt
->endtime
;
314 old_life
-= *tgt
->starttime
;
316 old_life
-= tgt
->authtime
;
317 et
->endtime
= *et
->starttime
+ old_life
;
318 if (et
->renew_till
!= NULL
)
319 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
323 * RFC 8062 section 3 defines an anonymous ticket as one containing
324 * the anonymous principal and the anonymous ticket flag.
326 if (tgt
->flags
.anonymous
&&
327 !_kdc_is_anonymous(r
->context
, tgt_name
)) {
328 _kdc_audit_addreason((kdc_request_t
)r
,
329 "Anonymous ticket flag set without "
330 "anonymous principal");
331 return KRB5KDC_ERR_BADOPTION
;
335 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
336 * anonymous KDC option SHOULD be set, but it is not required.
337 * Treat an anonymous TGT as if the anonymous flag was set.
339 if (is_anon_tgs_request_p(b
, tgt
))
340 et
->flags
.anonymous
= 1;
346 * Determine if constrained delegation is allowed from this client to this server
349 static krb5_error_code
350 check_constrained_delegation(krb5_context context
,
351 krb5_kdc_configuration
*config
,
353 hdb_entry_ex
*client
,
354 hdb_entry_ex
*server
,
355 krb5_const_principal target
)
357 const HDB_Ext_Constrained_delegation_acl
*acl
;
362 * constrained_delegation (S4U2Proxy) only works within
363 * the same realm. We use the already canonicalized version
364 * of the principals here, while "target" is the principal
365 * provided by the client.
367 if(!krb5_realm_compare(context
, client
->entry
.principal
, server
->entry
.principal
)) {
368 ret
= KRB5KDC_ERR_BADOPTION
;
369 kdc_log(context
, config
, 4,
370 "Bad request for constrained delegation");
374 if (clientdb
->hdb_check_constrained_delegation
) {
375 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, target
);
379 /* if client delegates to itself, that ok */
380 if (krb5_principal_compare(context
, client
->entry
.principal
, server
->entry
.principal
) == TRUE
)
383 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
385 krb5_clear_error_message(context
);
390 for (i
= 0; i
< acl
->len
; i
++) {
391 if (krb5_principal_compare(context
, target
, &acl
->val
[i
]) == TRUE
)
395 ret
= KRB5KDC_ERR_BADOPTION
;
397 kdc_log(context
, config
, 4,
398 "Bad request for constrained delegation");
403 * Determine if s4u2self is allowed from this client to this server
407 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
408 * service given by the client.
410 * For example, regardless of the principal being impersonated, if the
411 * 'client' and 'server' (target) are the same, or server is an SPN
412 * alias of client, then it's safe.
415 static krb5_error_code
416 check_client_matches_target_service(krb5_context context
,
417 krb5_kdc_configuration
*config
,
419 hdb_entry_ex
*client
,
420 hdb_entry_ex
*target_server
,
421 krb5_const_principal target_server_principal
)
426 * Always allow the plugin to check, this might be faster, allow a
427 * policy or audit check and can look into the DB records
430 if (clientdb
->hdb_check_client_matches_target_service
) {
431 ret
= clientdb
->hdb_check_client_matches_target_service(context
,
437 } else if (krb5_principal_compare(context
,
438 client
->entry
.principal
,
439 target_server_principal
) == TRUE
) {
440 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
443 ret
= KRB5KDC_ERR_BADOPTION
;
453 _kdc_verify_flags(krb5_context context
,
454 krb5_kdc_configuration
*config
,
455 const EncTicketPart
*et
,
458 if(et
->endtime
< kdc_time
){
459 kdc_log(context
, config
, 4, "Ticket expired (%s)", pstr
);
460 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
462 if(et
->flags
.invalid
){
463 kdc_log(context
, config
, 4, "Ticket not valid (%s)", pstr
);
464 return KRB5KRB_AP_ERR_TKT_NYV
;
473 static krb5_error_code
474 fix_transited_encoding(krb5_context context
,
475 krb5_kdc_configuration
*config
,
476 krb5_boolean check_policy
,
477 const TransitedEncoding
*tr
,
479 const char *client_realm
,
480 const char *server_realm
,
481 const char *tgt_realm
)
483 krb5_error_code ret
= 0;
484 char **realms
, **tmp
;
485 unsigned int num_realms
;
488 switch (tr
->tr_type
) {
489 case domain_X500_Compress
:
493 * Allow empty content of type 0 because that is was Microsoft
494 * generates in their TGT.
496 if (tr
->contents
.length
== 0)
498 kdc_log(context
, config
, 4,
499 "Transited type 0 with non empty content");
500 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
502 kdc_log(context
, config
, 4,
503 "Unknown transited type: %u", tr
->tr_type
);
504 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
507 ret
= krb5_domain_x500_decode(context
,
514 krb5_warn(context
, ret
,
515 "Decoding transited encoding");
520 * If the realm of the presented tgt is neither the client nor the server
521 * realm, it is a transit realm and must be added to transited set.
523 if (strcmp(client_realm
, tgt_realm
) != 0 &&
524 strcmp(server_realm
, tgt_realm
) != 0) {
525 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
529 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
535 realms
[num_realms
] = strdup(tgt_realm
);
536 if(realms
[num_realms
] == NULL
){
542 if(num_realms
== 0) {
543 if (strcmp(client_realm
, server_realm
) != 0)
544 kdc_log(context
, config
, 4,
545 "cross-realm %s -> %s", client_realm
, server_realm
);
549 for(i
= 0; i
< num_realms
; i
++)
550 l
+= strlen(realms
[i
]) + 2;
554 for(i
= 0; i
< num_realms
; i
++) {
556 strlcat(rs
, ", ", l
);
557 strlcat(rs
, realms
[i
], l
);
559 kdc_log(context
, config
, 4,
560 "cross-realm %s -> %s via [%s]",
561 client_realm
, server_realm
, rs
);
566 ret
= krb5_check_transited(context
, client_realm
,
568 realms
, num_realms
, NULL
);
570 krb5_warn(context
, ret
, "cross-realm %s -> %s",
571 client_realm
, server_realm
);
574 et
->flags
.transited_policy_checked
= 1;
576 et
->transited
.tr_type
= domain_X500_Compress
;
577 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
579 krb5_warn(context
, ret
, "Encoding transited encoding");
581 for(i
= 0; i
< num_realms
; i
++)
588 static krb5_error_code
589 tgs_make_reply(astgs_request_t r
,
590 krb5_principal tgt_name
,
591 const EncTicketPart
*tgt
,
592 const EncryptionKey
*serverkey
,
593 const EncryptionKey
*krbtgtkey
,
594 const krb5_keyblock
*sessionkey
,
596 AuthorizationData
*auth_data
,
597 hdb_entry_ex
*server
,
598 krb5_principal server_principal
,
599 hdb_entry_ex
*client
,
600 krb5_principal client_principal
,
601 const char *tgt_realm
,
603 krb5_boolean add_ticket_sig
)
605 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
606 const char **e_text
= &r
->e_text
;
607 krb5_data
*reply
= r
->reply
;
608 KDC_REP
*rep
= &r
->rep
;
609 EncTicketPart
*et
= &r
->et
;
610 EncKDCRepPart
*ek
= &r
->ek
;
611 KDCOptions f
= b
->kdc_options
;
616 rep
->msg_type
= krb_tgs_rep
;
618 et
->authtime
= tgt
->authtime
;
619 _kdc_fix_time(&b
->till
);
620 et
->endtime
= min(tgt
->endtime
, *b
->till
);
621 ALLOC(et
->starttime
);
622 *et
->starttime
= kdc_time
;
624 ret
= check_tgs_flags(r
, b
, tgt_name
, tgt
, et
);
628 /* We should check the transited encoding if:
629 1) the request doesn't ask not to be checked
630 2) globally enforcing a check
631 3) principal requires checking
632 4) we allow non-check per-principal, but principal isn't marked as allowing this
633 5) we don't globally allow this
636 #define GLOBAL_FORCE_TRANSITED_CHECK \
637 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
638 #define GLOBAL_ALLOW_PER_PRINCIPAL \
639 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
640 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
641 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
643 /* these will consult the database in future release */
644 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
645 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
647 ret
= fix_transited_encoding(r
->context
, r
->config
,
648 !f
.disable_transited_check
||
649 GLOBAL_FORCE_TRANSITED_CHECK
||
650 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
651 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
652 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
653 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
655 krb5_principal_get_realm(r
->context
, client_principal
),
656 krb5_principal_get_realm(r
->context
, server
->entry
.principal
),
661 ret
= copy_Realm(&server_principal
->realm
, &rep
->ticket
.realm
);
664 _krb5_principal2principalname(&rep
->ticket
.sname
, server_principal
);
665 ret
= copy_Realm(&tgt_name
->realm
, &rep
->crealm
);
670 * RFC 8062 states "if the ticket in the TGS request is an anonymous
671 * one, the client and client realm are copied from that ticket". So
672 * whilst the TGT flag check below is superfluous, it is included in
673 * order to follow the specification to its letter.
675 if (et
->flags
.anonymous
&& !tgt
->flags
.anonymous
)
676 _kdc_make_anonymous_principalname(&rep
->cname
);
678 ret
= copy_PrincipalName(&tgt_name
->name
, &rep
->cname
);
681 rep
->ticket
.tkt_vno
= 5;
683 ek
->caddr
= et
->caddr
;
687 life
= et
->endtime
- *et
->starttime
;
688 if(client
&& client
->entry
.max_life
)
689 life
= min(life
, *client
->entry
.max_life
);
690 if(server
->entry
.max_life
)
691 life
= min(life
, *server
->entry
.max_life
);
692 et
->endtime
= *et
->starttime
+ life
;
694 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
695 et
->renew_till
== NULL
&& et
->endtime
< *b
->till
&&
696 tgt
->renew_till
!= NULL
)
698 et
->flags
.renewable
= 1;
699 ALLOC(et
->renew_till
);
700 *et
->renew_till
= *b
->till
;
704 renew
= *et
->renew_till
- *et
->starttime
;
705 if(client
&& client
->entry
.max_renew
)
706 renew
= min(renew
, *client
->entry
.max_renew
);
707 if(server
->entry
.max_renew
)
708 renew
= min(renew
, *server
->entry
.max_renew
);
709 *et
->renew_till
= *et
->starttime
+ renew
;
713 *et
->renew_till
= min(*et
->renew_till
, *tgt
->renew_till
);
714 *et
->starttime
= min(*et
->starttime
, *et
->renew_till
);
715 et
->endtime
= min(et
->endtime
, *et
->renew_till
);
718 *et
->starttime
= min(*et
->starttime
, et
->endtime
);
720 if(*et
->starttime
== et
->endtime
){
721 ret
= KRB5KDC_ERR_NEVER_VALID
;
724 if(et
->renew_till
&& et
->endtime
== *et
->renew_till
){
725 free(et
->renew_till
);
726 et
->renew_till
= NULL
;
727 et
->flags
.renewable
= 0;
730 et
->flags
.pre_authent
= tgt
->flags
.pre_authent
;
731 et
->flags
.hw_authent
= tgt
->flags
.hw_authent
;
732 et
->flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
734 /* See MS-KILE 3.3.5.1 */
735 if (!server
->entry
.flags
.forwardable
)
736 et
->flags
.forwardable
= 0;
737 if (!server
->entry
.flags
.proxiable
)
738 et
->flags
.proxiable
= 0;
743 /* XXX check authdata */
745 if (et
->authorization_data
== NULL
) {
746 et
->authorization_data
= calloc(1, sizeof(*et
->authorization_data
));
747 if (et
->authorization_data
== NULL
) {
749 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
753 for(i
= 0; i
< auth_data
->len
; i
++) {
754 ret
= add_AuthorizationData(et
->authorization_data
, &auth_data
->val
[i
]);
756 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
762 ret
= krb5_copy_keyblock_contents(r
->context
, sessionkey
, &et
->key
);
765 et
->crealm
= rep
->crealm
;
766 et
->cname
= rep
->cname
;
769 /* MIT must have at least one last_req */
770 ek
->last_req
.val
= calloc(1, sizeof(*ek
->last_req
.val
));
771 if (ek
->last_req
.val
== NULL
) {
775 ek
->last_req
.len
= 1; /* set after alloc to avoid null deref on cleanup */
776 ek
->nonce
= b
->nonce
;
777 ek
->flags
= et
->flags
;
778 ek
->authtime
= et
->authtime
;
779 ek
->starttime
= et
->starttime
;
780 ek
->endtime
= et
->endtime
;
781 ek
->renew_till
= et
->renew_till
;
782 ek
->srealm
= rep
->ticket
.realm
;
783 ek
->sname
= rep
->ticket
.sname
;
785 _kdc_log_timestamp(r
, "TGS-REQ", et
->authtime
, et
->starttime
,
786 et
->endtime
, et
->renew_till
);
788 rep
->padata
= r
->outpadata
.len
? &r
->outpadata
: NULL
;
790 if (krb5_enctype_valid(r
->context
, serverkey
->keytype
) != 0
791 && _kdc_is_weak_exception(server
->entry
.principal
, serverkey
->keytype
))
793 krb5_enctype_enable(r
->context
, serverkey
->keytype
);
797 if (r
->client_princ
) {
800 krb5_unparse_name(r
->context
, r
->client_princ
, &cpn
);
801 _kdc_audit_addkv((kdc_request_t
)r
, 0, "canon_client_name", "%s",
802 cpn
? cpn
: "<unknown>");
807 * For anonymous tickets, we should filter out positive authorization data
808 * that could reveal the client's identity, and return a policy error for
809 * restrictive authorization data. Policy for unknown authorization types
810 * is implementation dependent.
812 if (r
->pac
&& !et
->flags
.anonymous
) {
813 _kdc_audit_addkv((kdc_request_t
)r
, 0, "pac_attributes", "%lx",
814 (long)r
->pac_attributes
);
817 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
818 * buffer (legacy behavior) or if the attributes buffer indicates the
819 * AS client requested one.
821 if (_kdc_include_pac_p(r
)) {
822 krb5_boolean is_tgs
=
823 krb5_principal_is_krbtgt(r
->context
, server
->entry
.principal
);
825 ret
= _krb5_kdc_pac_sign_ticket(r
->context
, r
->pac
, tgt_name
, serverkey
,
826 krbtgtkey
, rodc_id
, NULL
, r
->client_princ
,
828 is_tgs
? &r
->pac_attributes
: NULL
);
834 ret
= _kdc_finalize_reply(r
);
838 /* It is somewhat unclear where the etype in the following
839 encryption should come from. What we have is a session
840 key in the passed tgt, and a list of preferred etypes
841 *for the new ticket*. Should we pick the best possible
842 etype, given the keytype in the tgt, or should we look
843 at the etype list here as well? What if the tgt
844 session key is DES3 and we want a ticket with a (say)
845 CAST session key. Should the DES3 etype be added to the
846 etype list, even if we don't want a session key with
848 ret
= _kdc_encode_reply(r
->context
, r
->config
, r
, b
->nonce
,
849 serverkey
->keytype
, kvno
,
850 serverkey
, 0, r
->rk_is_subkey
,
853 krb5_enctype_disable(r
->context
, serverkey
->keytype
);
855 _log_astgs_req(r
, serverkey
->keytype
);
861 static krb5_error_code
862 tgs_check_authenticator(krb5_context context
,
863 krb5_kdc_configuration
*config
,
864 krb5_auth_context ac
,
869 krb5_authenticator auth
;
873 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
874 if(auth
->cksum
== NULL
){
875 kdc_log(context
, config
, 4, "No authenticator in request");
876 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
880 if (!krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
881 kdc_log(context
, config
, 4, "Bad checksum type in authenticator: %d",
882 auth
->cksum
->cksumtype
);
883 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
887 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
889 const char *msg
= krb5_get_error_message(context
, ret
);
890 kdc_log(context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
891 krb5_free_error_message(context
, msg
);
896 * RFC4120 says the checksum must be collision-proof, but it does
897 * not require it to be keyed (as the authenticator is encrypted).
899 _krb5_crypto_set_flags(context
, crypto
, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
);
900 ret
= _kdc_verify_checksum(context
,
902 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
905 krb5_crypto_destroy(context
, crypto
);
907 const char *msg
= krb5_get_error_message(context
, ret
);
908 kdc_log(context
, config
, 4,
909 "Failed to verify authenticator checksum: %s", msg
);
910 krb5_free_error_message(context
, msg
);
913 free_Authenticator(auth
);
919 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
920 const KDCOptions
* const options
, krb5_principal server
,
925 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
928 if (server
->name
.name_string
.len
== 1)
929 name
= server
->name
.name_string
.val
[0];
930 else if (server
->name
.name_string
.len
== 3) {
932 This is used to give referrals for the
933 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
934 SPN form, which is used for inter-domain communication in AD
936 name
= server
->name
.name_string
.val
[2];
937 kdc_log(context
, config
, 4, "Giving 3 part referral for %s", name
);
938 *realms
= malloc(sizeof(char *)*2);
939 if (*realms
== NULL
) {
940 krb5_set_error_message(context
, ENOMEM
, N_("malloc: out of memory", ""));
943 (*realms
)[0] = strdup(name
);
946 } else if (server
->name
.name_string
.len
> 1)
947 name
= server
->name
.name_string
.val
[1];
951 kdc_log(context
, config
, 5, "Searching referral for %s", name
);
953 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
956 static krb5_error_code
957 validate_fast_ad(astgs_request_t r
, krb5_authdata
*auth_data
)
962 krb5_data_zero(&data
);
964 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
965 KRB5_AUTHDATA_FX_FAST_USED
, &data
);
967 r
->fast_asserted
= 1;
968 krb5_data_free(&data
);
971 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
972 KRB5_AUTHDATA_FX_FAST_ARMOR
, &data
);
974 kdc_log(r
->context
, r
->config
, 2,
975 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
976 krb5_data_free(&data
);
977 return KRB5KRB_AP_ERR_BAD_INTEGRITY
;
983 static krb5_error_code
984 tgs_parse_request(astgs_request_t r
,
985 const PA_DATA
*tgs_req
,
986 hdb_entry_ex
**krbtgt
,
987 krb5_enctype
*krbtgt_etype
,
988 krb5_ticket
**ticket
,
991 const struct sockaddr
*from_addr
,
994 AuthorizationData
**auth_data
)
996 krb5_kdc_configuration
*config
= r
->config
;
997 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
998 static char failed
[] = "<unparse_name failed>";
1000 krb5_error_code ret
;
1001 krb5_principal princ
;
1002 krb5_auth_context ac
= NULL
;
1003 krb5_flags ap_req_options
;
1004 krb5_flags verify_ap_req_flags
= 0;
1006 krb5uint32 krbtgt_kvno
; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
1007 krb5uint32 krbtgt_kvno_try
;
1008 int kvno_search_tries
= 4; /* number of kvnos to try when tkt_vno == 0 */
1009 const Keys
*krbtgt_keys
;/* keyset for TGT tkt_vno */
1011 krb5_keyblock
*subkey
= NULL
;
1018 memset(&ap_req
, 0, sizeof(ap_req
));
1019 ret
= krb5_decode_ap_req(r
->context
, &tgs_req
->padata_value
, &ap_req
);
1021 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1022 kdc_log(r
->context
, config
, 4, "Failed to decode AP-REQ: %s", msg
);
1023 krb5_free_error_message(r
->context
, msg
);
1027 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1028 /* XXX check for ticket.sname == req.sname */
1029 kdc_log(r
->context
, config
, 4, "PA-DATA is not a ticket-granting ticket");
1030 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1034 _krb5_principalname2krb5_principal(r
->context
,
1036 ap_req
.ticket
.sname
,
1037 ap_req
.ticket
.realm
);
1039 krbtgt_kvno
= ap_req
.ticket
.enc_part
.kvno
? *ap_req
.ticket
.enc_part
.kvno
: 0;
1040 ret
= _kdc_db_fetch(r
->context
, config
, princ
, HDB_F_GET_KRBTGT
,
1041 &krbtgt_kvno
, NULL
, krbtgt
);
1043 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1044 /* XXX Factor out this unparsing of the same princ all over */
1046 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1049 krb5_free_principal(r
->context
, princ
);
1050 kdc_log(r
->context
, config
, 5,
1051 "Ticket-granting ticket account %s does not have secrets at "
1052 "this KDC, need to proxy", p
);
1055 ret
= HDB_ERR_NOT_FOUND_HERE
;
1057 } else if (ret
== HDB_ERR_KVNO_NOT_FOUND
) {
1059 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1062 krb5_free_principal(r
->context
, princ
);
1063 kdc_log(r
->context
, config
, 5,
1064 "Ticket-granting ticket account %s does not have keys for "
1065 "kvno %d at this KDC", p
, krbtgt_kvno
);
1068 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1070 } else if (ret
== HDB_ERR_NO_MKEY
) {
1072 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1075 krb5_free_principal(r
->context
, princ
);
1076 kdc_log(r
->context
, config
, 5,
1077 "Missing master key for decrypting keys for ticket-granting "
1078 "ticket account %s with kvno %d at this KDC", p
, krbtgt_kvno
);
1081 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1084 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1086 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1089 kdc_log(r
->context
, config
, 4,
1090 "Ticket-granting ticket %s not found in database: %s", p
, msg
);
1091 krb5_free_principal(r
->context
, princ
);
1092 krb5_free_error_message(r
->context
, msg
);
1095 ret
= KRB5KRB_AP_ERR_NOT_US
;
1099 krbtgt_kvno_try
= krbtgt_kvno
? krbtgt_kvno
: (*krbtgt
)->entry
.kvno
;
1100 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1103 krbtgt_keys
= hdb_kvno2keys(r
->context
, &(*krbtgt
)->entry
, krbtgt_kvno_try
);
1104 ret
= hdb_enctype2key(r
->context
, &(*krbtgt
)->entry
, krbtgt_keys
,
1105 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1106 if (ret
&& krbtgt_kvno
== 0 && kvno_search_tries
> 0) {
1107 kvno_search_tries
--;
1111 char *str
= NULL
, *p
= NULL
;
1113 krb5_enctype_to_string(r
->context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1114 krb5_unparse_name(r
->context
, princ
, &p
);
1115 kdc_log(r
->context
, config
, 4,
1116 "No server key with enctype %s found for %s",
1117 str
? str
: "<unknown enctype>",
1118 p
? p
: "<unparse_name failed>");
1121 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1125 if (b
->kdc_options
.validate
)
1126 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1128 if (r
->config
->warn_ticket_addresses
)
1129 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS
;
1131 ret
= krb5_verify_ap_req2(r
->context
,
1136 verify_ap_req_flags
,
1139 KRB5_KU_TGS_REQ_AUTH
);
1140 if (ticket
&& *ticket
&& (*ticket
)->ticket
.caddr
)
1141 _kdc_audit_addaddrs((kdc_request_t
)r
, (*ticket
)->ticket
.caddr
, "tixaddrs");
1142 if (r
->config
->warn_ticket_addresses
&& ret
== KRB5KRB_AP_ERR_BADADDR
&&
1144 _kdc_audit_addkv((kdc_request_t
)r
, 0, "wrongaddr", "yes");
1147 if (ret
== KRB5KRB_AP_ERR_BAD_INTEGRITY
&& kvno_search_tries
> 0) {
1148 kvno_search_tries
--;
1153 krb5_free_principal(r
->context
, princ
);
1155 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1156 kdc_log(r
->context
, config
, 4, "Failed to verify AP-REQ: %s", msg
);
1157 krb5_free_error_message(r
->context
, msg
);
1161 r
->ticket_key
= tkey
;
1164 krb5_authenticator auth
;
1166 ret
= krb5_auth_con_getauthenticator(r
->context
, ac
, &auth
);
1168 *csec
= malloc(sizeof(**csec
));
1169 if (*csec
== NULL
) {
1170 krb5_free_authenticator(r
->context
, &auth
);
1171 kdc_log(r
->context
, config
, 4, "malloc failed");
1174 **csec
= auth
->ctime
;
1175 *cusec
= malloc(sizeof(**cusec
));
1176 if (*cusec
== NULL
) {
1177 krb5_free_authenticator(r
->context
, &auth
);
1178 kdc_log(r
->context
, config
, 4, "malloc failed");
1181 **cusec
= auth
->cusec
;
1183 ret
= validate_fast_ad(r
, auth
->authorization_data
);
1184 krb5_free_authenticator(r
->context
, &auth
);
1190 ret
= tgs_check_authenticator(r
->context
, config
,
1191 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1193 krb5_auth_con_free(r
->context
, ac
);
1197 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1198 r
->rk_is_subkey
= 1;
1200 ret
= krb5_auth_con_getremotesubkey(r
->context
, ac
, &subkey
);
1202 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1203 krb5_auth_con_free(r
->context
, ac
);
1204 kdc_log(r
->context
, config
, 4, "Failed to get remote subkey: %s", msg
);
1205 krb5_free_error_message(r
->context
, msg
);
1209 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1210 r
->rk_is_subkey
= 0;
1212 ret
= krb5_auth_con_getkey(r
->context
, ac
, &subkey
);
1214 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1215 krb5_auth_con_free(r
->context
, ac
);
1216 kdc_log(r
->context
, config
, 4, "Failed to get session key: %s", msg
);
1217 krb5_free_error_message(r
->context
, msg
);
1222 krb5_auth_con_free(r
->context
, ac
);
1223 kdc_log(r
->context
, config
, 4,
1224 "Failed to get key for enc-authorization-data");
1225 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1229 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
1230 ret
= krb5_copy_keyblock_contents(r
->context
, subkey
, &r
->reply_key
);
1231 krb5_free_keyblock(r
->context
, subkey
);
1235 if (b
->enc_authorization_data
) {
1238 ret
= krb5_crypto_init(r
->context
, &r
->reply_key
, 0, &crypto
);
1240 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1241 krb5_auth_con_free(r
->context
, ac
);
1242 kdc_log(r
->context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
1243 krb5_free_error_message(r
->context
, msg
);
1246 ret
= krb5_decrypt_EncryptedData (r
->context
,
1249 b
->enc_authorization_data
,
1251 krb5_crypto_destroy(r
->context
, crypto
);
1253 krb5_auth_con_free(r
->context
, ac
);
1254 kdc_log(r
->context
, config
, 4,
1255 "Failed to decrypt enc-authorization-data");
1256 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1260 if (*auth_data
== NULL
) {
1261 krb5_auth_con_free(r
->context
, ac
);
1262 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1265 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1267 krb5_auth_con_free(r
->context
, ac
);
1270 kdc_log(r
->context
, config
, 4, "Failed to decode authorization data");
1271 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1276 ret
= validate_fast_ad(r
, (*ticket
)->ticket
.authorization_data
);
1282 * Check for FAST request
1285 ret
= _kdc_fast_unwrap_request(r
, *ticket
, ac
);
1289 krb5_auth_con_free(r
->context
, ac
);
1292 free_AP_REQ(&ap_req
);
1297 static krb5_error_code
1298 build_server_referral(krb5_context context
,
1299 krb5_kdc_configuration
*config
,
1300 krb5_crypto session
,
1301 krb5_const_realm referred_realm
,
1302 const PrincipalName
*true_principal_name
,
1303 const PrincipalName
*requested_principal
,
1306 PA_ServerReferralData ref
;
1307 krb5_error_code ret
;
1312 memset(&ref
, 0, sizeof(ref
));
1314 if (referred_realm
) {
1315 ALLOC(ref
.referred_realm
);
1316 if (ref
.referred_realm
== NULL
)
1318 *ref
.referred_realm
= strdup(referred_realm
);
1319 if (*ref
.referred_realm
== NULL
)
1322 if (true_principal_name
) {
1323 ALLOC(ref
.true_principal_name
);
1324 if (ref
.true_principal_name
== NULL
)
1326 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1330 if (requested_principal
) {
1331 ALLOC(ref
.requested_principal_name
);
1332 if (ref
.requested_principal_name
== NULL
)
1334 ret
= copy_PrincipalName(requested_principal
,
1335 ref
.requested_principal_name
);
1340 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1341 data
.data
, data
.length
,
1343 free_PA_ServerReferralData(&ref
);
1346 if (data
.length
!= size
)
1347 krb5_abortx(context
, "internal asn.1 encoder error");
1349 ret
= krb5_encrypt_EncryptedData(context
, session
,
1350 KRB5_KU_PA_SERVER_REFERRAL
,
1351 data
.data
, data
.length
,
1357 ASN1_MALLOC_ENCODE(EncryptedData
,
1358 outdata
->data
, outdata
->length
,
1360 free_EncryptedData(&ed
);
1363 if (outdata
->length
!= size
)
1364 krb5_abortx(context
, "internal asn.1 encoder error");
1368 free_PA_ServerReferralData(&ref
);
1369 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1374 * This function is intended to be used when failure to find the client is
1378 _kdc_db_fetch_client(krb5_context context
,
1379 krb5_kdc_configuration
*config
,
1383 const char *krbtgt_realm
,
1385 hdb_entry_ex
**client_out
)
1387 krb5_error_code ret
;
1388 hdb_entry_ex
*client
= NULL
;
1392 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| flags
,
1393 NULL
, clientdb
, &client
);
1394 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1396 * This is OK, we are just trying to find out if they have
1397 * been disabled or deleted in the meantime; missing secrets
1402 * If the client belongs to the same realm as our TGS, it
1403 * should exist in the local database.
1407 if (strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1408 if (ret
== HDB_ERR_NOENTRY
)
1409 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1410 kdc_log(context
, config
, 4, "Client no longer in database: %s", cpn
);
1414 msg
= krb5_get_error_message(context
, ret
);
1415 kdc_log(context
, config
, 4, "Client not found in database: %s", msg
);
1416 krb5_free_error_message(context
, msg
);
1417 } else if (client
->entry
.flags
.invalid
|| !client
->entry
.flags
.client
) {
1418 kdc_log(context
, config
, 4, "Client has invalid bit set");
1419 _kdc_free_ent(context
, client
);
1420 return KRB5KDC_ERR_POLICY
;
1423 *client_out
= client
;
1428 static krb5_error_code
1429 tgs_build_reply(astgs_request_t priv
,
1430 hdb_entry_ex
*krbtgt
,
1431 krb5_enctype krbtgt_etype
,
1432 krb5_ticket
*ticket
,
1433 const char **e_text
,
1434 AuthorizationData
**auth_data
,
1435 const struct sockaddr
*from_addr
)
1437 krb5_context context
= priv
->context
;
1438 krb5_kdc_configuration
*config
= priv
->config
;
1439 KDC_REQ
*req
= &priv
->req
;
1440 KDC_REQ_BODY
*b
= &priv
->req
.req_body
;
1441 const char *from
= priv
->from
;
1442 krb5_error_code ret
, ret2
;
1443 krb5_principal cp
= NULL
, sp
= NULL
, rsp
= NULL
, tp
= NULL
, dp
= NULL
;
1444 krb5_principal krbtgt_out_principal
= NULL
;
1445 krb5_principal user2user_princ
= NULL
;
1446 char *spn
= NULL
, *cpn
= NULL
, *tpn
= NULL
, *dpn
= NULL
, *krbtgt_out_n
= NULL
;
1447 char *user2user_name
= NULL
;
1448 hdb_entry_ex
*server
= NULL
, *client
= NULL
, *s4u2self_impersonated_client
= NULL
;
1449 hdb_entry_ex
*user2user_krbtgt
= NULL
;
1450 HDB
*clientdb
, *s4u2self_impersonated_clientdb
;
1451 HDB
*serverdb
= NULL
;
1452 krb5_realm ref_realm
= NULL
;
1453 EncTicketPart
*tgt
= &ticket
->ticket
;
1454 const EncryptionKey
*ekey
;
1455 krb5_keyblock sessionkey
;
1457 krb5_pac user2user_pac
= NULL
;
1459 krb5_boolean add_ticket_sig
= FALSE
;
1460 const char *tgt_realm
= /* Realm of TGT issuer */
1461 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
);
1462 const char *our_realm
= /* Realm of this KDC */
1463 krb5_principal_get_comp_string(context
, krbtgt
->entry
.principal
, 1);
1464 char **capath
= NULL
;
1465 size_t num_capath
= 0;
1467 hdb_entry_ex
*krbtgt_out
= NULL
;
1471 EncTicketPart adtkt
;
1473 krb5_boolean kdc_issued
= FALSE
;
1476 int flags
= HDB_F_FOR_TGS_REQ
;
1480 memset(&sessionkey
, 0, sizeof(sessionkey
));
1481 memset(&adtkt
, 0, sizeof(adtkt
));
1487 * The canonicalize KDC option is passed as a hint to the backend, but
1488 * can typically be ignored. Per RFC 6806, names are not canonicalized
1489 * in response to a TGS request (although we make an exception, see
1490 * force-canonicalize below).
1492 if (b
->kdc_options
.canonicalize
)
1493 flags
|= HDB_F_CANON
;
1496 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1497 _kdc_set_e_text(priv
, "No server in request");
1501 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1502 ret
= krb5_unparse_name(context
, sp
, &priv
->sname
);
1506 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1507 ret
= krb5_unparse_name(context
, cp
, &priv
->cname
);
1511 result
= unparse_flags(KDCOptions2int(b
->kdc_options
),
1512 asn1_KDCOptions_units(),
1513 opt_str
, sizeof(opt_str
));
1515 kdc_log(context
, config
, 4,
1516 "TGS-REQ %s from %s for %s [%s]",
1517 cpn
, from
, spn
, opt_str
);
1519 kdc_log(context
, config
, 4,
1520 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1527 priv
->server
= NULL
;
1529 _kdc_free_ent(context
, server
);
1531 ret
= _kdc_db_fetch(context
, config
, sp
,
1532 HDB_F_GET_SERVER
| HDB_F_DELAY_NEW_KEYS
| flags
,
1533 NULL
, &serverdb
, &server
);
1534 priv
->server
= server
;
1535 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1536 kdc_log(context
, config
, 5, "target %s does not have secrets at this KDC, need to proxy", spn
);
1537 _kdc_audit_addreason((kdc_request_t
)priv
, "Target not found here");
1539 } else if (ret
== HDB_ERR_WRONG_REALM
) {
1541 ref_realm
= strdup(server
->entry
.principal
->realm
);
1542 if (ref_realm
== NULL
) {
1543 ret
= krb5_enomem(context
);
1547 kdc_log(context
, config
, 4,
1548 "Returning a referral to realm %s for "
1551 krb5_free_principal(context
, sp
);
1553 ret
= krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1559 ret
= krb5_unparse_name(context
, sp
, &priv
->sname
);
1566 const char *new_rlm
, *msg
;
1570 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1571 if (capath
== NULL
) {
1572 /* With referalls, hierarchical capaths are always enabled */
1573 ret2
= _krb5_find_capath(context
, tgt
->crealm
, our_realm
,
1574 req_rlm
, TRUE
, &capath
, &num_capath
);
1577 _kdc_audit_addreason((kdc_request_t
)priv
,
1578 "No trusted path from client realm to ours");
1582 new_rlm
= num_capath
> 0 ? capath
[--num_capath
] : NULL
;
1584 kdc_log(context
, config
, 5, "krbtgt from %s via %s for "
1585 "realm %s not found, trying %s", tgt
->crealm
,
1586 our_realm
, req_rlm
, new_rlm
);
1589 ref_realm
= strdup(new_rlm
);
1590 if (ref_realm
== NULL
) {
1591 ret
= krb5_enomem(context
);
1595 krb5_free_principal(context
, sp
);
1597 krb5_make_principal(context
, &sp
, r
,
1598 KRB5_TGS_NAME
, ref_realm
, NULL
);
1601 ret
= krb5_unparse_name(context
, sp
, &priv
->sname
);
1607 } else if (need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1608 if (strcmp(realms
[0], sp
->realm
) != 0) {
1609 kdc_log(context
, config
, 4,
1610 "Returning a referral to realm %s for "
1611 "server %s that was not found",
1613 krb5_free_principal(context
, sp
);
1615 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1619 ret
= krb5_unparse_name(context
, sp
, &priv
->sname
);
1621 krb5_free_host_realm(context
, realms
);
1627 ref_realm
= strdup(realms
[0]);
1629 krb5_free_host_realm(context
, realms
);
1632 krb5_free_host_realm(context
, realms
);
1634 msg
= krb5_get_error_message(context
, ret
);
1635 kdc_log(context
, config
, 3,
1636 "Server not found in database: %s: %s", spn
, msg
);
1637 krb5_free_error_message(context
, msg
);
1638 if (ret
== HDB_ERR_NOENTRY
)
1639 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1640 _kdc_audit_addreason((kdc_request_t
)priv
,
1641 "Service principal unknown");
1646 * RFC 6806 notes that names MUST NOT be changed in the response to
1647 * a TGS request. Hence we ignore the setting of the canonicalize
1648 * KDC option. However, for legacy interoperability we do allow the
1649 * backend to override this by setting the force-canonicalize HDB
1650 * flag in the server entry.
1652 if (server
->entry
.flags
.force_canonicalize
)
1653 rsp
= server
->entry
.principal
;
1658 * Now refetch the primary krbtgt, and get the current kvno (the
1659 * sign check may have been on an old kvno, and the server may
1660 * have been an incoming trust)
1663 ret
= krb5_make_principal(context
,
1664 &krbtgt_out_principal
,
1670 kdc_log(context
, config
, 4,
1671 "Failed to make krbtgt principal name object for "
1672 "authz-data signatures");
1675 ret
= krb5_unparse_name(context
, krbtgt_out_principal
, &krbtgt_out_n
);
1677 kdc_log(context
, config
, 4,
1678 "Failed to make krbtgt principal name object for "
1679 "authz-data signatures");
1683 ret
= _kdc_db_fetch(context
, config
, krbtgt_out_principal
,
1684 HDB_F_GET_KRBTGT
, NULL
, NULL
, &krbtgt_out
);
1687 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &ktpn
);
1688 kdc_log(context
, config
, 4,
1689 "No such principal %s (needed for authz-data signature keys) "
1690 "while processing TGS-REQ for service %s with krbtg %s",
1691 krbtgt_out_n
, spn
, (ret
== 0) ? ktpn
: "<unknown>");
1693 ret
= KRB5KRB_AP_ERR_NOT_US
;
1698 * Select enctype, return key and kvno.
1704 if(b
->kdc_options
.enc_tkt_in_skey
) {
1708 krb5uint32 second_kvno
= 0;
1709 krb5uint32
*kvno_ptr
= NULL
;
1711 hdb_entry_ex
*user2user_client
= NULL
;
1712 krb5_boolean user2user_kdc_issued
= FALSE
;
1714 if(b
->additional_tickets
== NULL
||
1715 b
->additional_tickets
->len
== 0){
1716 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1717 kdc_log(context
, config
, 4,
1718 "No second ticket present in user-to-user request");
1719 _kdc_audit_addreason((kdc_request_t
)priv
,
1720 "No second ticket present in user-to-user request");
1723 t
= &b
->additional_tickets
->val
[0];
1724 if(!get_krbtgt_realm(&t
->sname
)){
1725 kdc_log(context
, config
, 4,
1726 "Additional ticket is not a ticket-granting ticket");
1727 _kdc_audit_addreason((kdc_request_t
)priv
,
1728 "Additional ticket is not a ticket-granting ticket");
1729 ret
= KRB5KDC_ERR_POLICY
;
1732 ret
= _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1736 ret
= krb5_unparse_name(context
, p
, &tpn
);
1739 if(t
->enc_part
.kvno
){
1740 second_kvno
= *t
->enc_part
.kvno
;
1741 kvno_ptr
= &second_kvno
;
1743 ret
= _kdc_db_fetch(context
, config
, p
,
1744 HDB_F_GET_KRBTGT
, kvno_ptr
,
1745 NULL
, &user2user_krbtgt
);
1746 krb5_free_principal(context
, p
);
1748 if (ret
== HDB_ERR_NOENTRY
)
1749 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1750 _kdc_audit_addreason((kdc_request_t
)priv
,
1751 "User-to-user service principal (TGS) unknown");
1754 ret
= hdb_enctype2key(context
, &user2user_krbtgt
->entry
, NULL
,
1755 t
->enc_part
.etype
, &uukey
);
1757 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1758 _kdc_audit_addreason((kdc_request_t
)priv
,
1759 "User-to-user enctype not supported");
1762 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1764 _kdc_audit_addreason((kdc_request_t
)priv
,
1765 "User-to-user TGT decrypt failure");
1769 ret
= _kdc_verify_flags(context
, config
, &adtkt
, tpn
);
1771 _kdc_audit_addreason((kdc_request_t
)priv
,
1772 "User-to-user TGT expired or invalid");
1776 /* Fetch the name from the TGT. */
1777 ret
= _krb5_principalname2krb5_principal(context
, &user2user_princ
,
1778 adtkt
.cname
, adtkt
.crealm
);
1782 ret
= krb5_unparse_name(context
, user2user_princ
, &user2user_name
);
1787 * Look up the name given in the TGT in the database. The user
1788 * claims to have a ticket-granting-ticket to our KDC, so we should
1789 * fail hard if we can't find the user - otherwise we can't do
1792 ret
= _kdc_db_fetch(context
, config
, user2user_princ
,
1793 HDB_F_GET_CLIENT
| flags
,
1794 NULL
, NULL
, &user2user_client
);
1795 if (ret
== HDB_ERR_NOENTRY
)
1796 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1801 * The account is present in the database, now check the
1804 * We check this as a client (because the purpose of
1805 * user2user is that the server flag is not set, because
1806 * the long-term key is not strong, but this does mean
1807 * that a client with an expired password can't get accept
1808 * a user2user ticket.
1810 ret
= kdc_check_flags(priv
,
1815 _kdc_free_ent(context
, user2user_client
);
1820 * Also check that the account is the same one specified in the
1823 ret
= check_client_matches_target_service(context
,
1830 _kdc_free_ent(context
, user2user_client
);
1834 /* Verify the PAC of the TGT. */
1835 ret
= _kdc_check_pac(context
, config
, user2user_princ
, NULL
,
1836 user2user_client
, user2user_krbtgt
, user2user_krbtgt
, user2user_krbtgt
,
1837 &uukey
->key
, &priv
->ticket_key
->key
, &adtkt
,
1838 &user2user_kdc_issued
, &user2user_pac
, NULL
, NULL
);
1839 _kdc_free_ent(context
, user2user_client
);
1841 const char *msg
= krb5_get_error_message(context
, ret
);
1842 kdc_log(context
, config
, 0,
1843 "Verify PAC failed for %s (%s) from %s with %s",
1844 spn
, user2user_name
, from
, msg
);
1845 krb5_free_error_message(context
, msg
);
1849 if ((config
->require_pac
&& !user2user_pac
)
1850 || (user2user_pac
&& !user2user_kdc_issued
))
1852 ret
= KRB5KDC_ERR_BADOPTION
;
1853 kdc_log(context
, config
, 0,
1854 "Ticket not signed with PAC; user-to-user failed (%s).",
1855 user2user_pac
? "Ticket unsigned" : "No PAC");
1860 for(i
= 0; i
< b
->etype
.len
; i
++)
1861 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1863 if(i
== b
->etype
.len
) {
1864 kdc_log(context
, config
, 4,
1865 "Addition ticket have not matching etypes");
1866 krb5_clear_error_message(context
);
1867 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1868 _kdc_audit_addreason((kdc_request_t
)priv
,
1869 "No matching enctypes for 2nd ticket");
1872 etype
= b
->etype
.val
[i
];
1877 ret
= _kdc_find_etype(priv
, krb5_principal_is_krbtgt(context
, sp
)
1879 b
->etype
.val
, b
->etype
.len
, &etype
, NULL
,
1882 kdc_log(context
, config
, 4,
1883 "Server (%s) has no support for etypes", spn
);
1884 _kdc_audit_addreason((kdc_request_t
)priv
,
1885 "Enctype not supported");
1888 ret
= _kdc_get_preferred_key(context
, config
, server
, spn
,
1891 kdc_log(context
, config
, 4,
1892 "Server (%s) has no supported etypes", spn
);
1893 _kdc_audit_addreason((kdc_request_t
)priv
,
1894 "Enctype not supported");
1898 kvno
= server
->entry
.kvno
;
1901 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1907 * Check that service is in the same realm as the krbtgt. If it's
1908 * not the same, it's someone that is using a uni-directional trust
1913 * The first realm is the realm of the service, the second is
1914 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1915 * encrypted to. The redirection via the krbtgt_out entry allows
1916 * the DB to possibly correct the case of the realm (Samba4 does
1917 * this) before the strcmp()
1919 if (strcmp(krb5_principal_get_realm(context
, server
->entry
.principal
),
1920 krb5_principal_get_realm(context
, krbtgt_out
->entry
.principal
)) != 0) {
1922 ret
= krb5_unparse_name(context
, krbtgt_out
->entry
.principal
, &ktpn
);
1923 kdc_log(context
, config
, 4,
1924 "Request with wrong krbtgt: %s",
1925 (ret
== 0) ? ktpn
: "<unknown>");
1928 ret
= KRB5KRB_AP_ERR_NOT_US
;
1929 _kdc_audit_addreason((kdc_request_t
)priv
, "Request with wrong TGT");
1933 ret
= _kdc_get_preferred_key(context
, config
, krbtgt_out
, krbtgt_out_n
,
1936 kdc_log(context
, config
, 4,
1937 "Failed to find key for krbtgt PAC signature");
1938 _kdc_audit_addreason((kdc_request_t
)priv
,
1939 "Failed to find key for krbtgt PAC signature");
1942 ret
= hdb_enctype2key(context
, &krbtgt_out
->entry
, NULL
,
1943 tkey_sign
->key
.keytype
, &tkey_sign
);
1945 kdc_log(context
, config
, 4,
1946 "Failed to find key for krbtgt PAC signature");
1947 _kdc_audit_addreason((kdc_request_t
)priv
,
1948 "Failed to find key for krbtgt PAC signature");
1952 if (_kdc_synthetic_princ_used_p(context
, ticket
))
1953 flags
|= HDB_F_SYNTHETIC_OK
;
1955 ret
= _kdc_db_fetch_client(context
, config
, flags
, cp
, cpn
, our_realm
,
1956 &clientdb
, &client
);
1959 flags
&= ~HDB_F_SYNTHETIC_OK
;
1960 priv
->client
= client
;
1962 heim_assert(priv
->client_princ
== NULL
, "client_princ should be NULL for TGS");
1964 ret
= _kdc_check_pac(context
, config
, cp
, NULL
, client
, server
, krbtgt
, krbtgt
,
1965 &priv
->ticket_key
->key
, &priv
->ticket_key
->key
, tgt
,
1966 &kdc_issued
, &priv
->pac
, &priv
->client_princ
, &priv
->pac_attributes
);
1968 const char *msg
= krb5_get_error_message(context
, ret
);
1969 _kdc_audit_addreason((kdc_request_t
)priv
, "PAC check failed");
1970 kdc_log(context
, config
, 4,
1971 "Verify PAC failed for %s (%s) from %s with %s",
1972 spn
, cpn
, from
, msg
);
1973 krb5_free_error_message(context
, msg
);
1981 /* by default the tgt principal matches the client principal */
1986 const PA_DATA
*sdata
;
1989 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1996 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1997 sdata
->padata_value
.length
,
2000 _kdc_audit_addreason((kdc_request_t
)priv
,
2001 "Failed to decode PA-S4U2Self");
2002 kdc_log(context
, config
, 4, "Failed to decode PA-S4U2Self");
2006 if (!krb5_checksum_is_keyed(context
, self
.cksum
.cksumtype
)) {
2007 free_PA_S4U2Self(&self
);
2008 _kdc_audit_addreason((kdc_request_t
)priv
,
2009 "PA-S4U2Self with unkeyed checksum");
2010 kdc_log(context
, config
, 4, "Reject PA-S4U2Self with unkeyed checksum");
2011 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
2015 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
2019 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
2021 const char *msg
= krb5_get_error_message(context
, ret
);
2022 free_PA_S4U2Self(&self
);
2023 krb5_data_free(&datack
);
2024 kdc_log(context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
2025 krb5_free_error_message(context
, msg
);
2029 /* Allow HMAC_MD5 checksum with any key type */
2030 if (self
.cksum
.cksumtype
== CKSUMTYPE_HMAC_MD5
) {
2031 struct krb5_crypto_iov iov
;
2032 unsigned char csdata
[16];
2035 cs
.checksum
.length
= sizeof(csdata
);
2036 cs
.checksum
.data
= &csdata
;
2038 iov
.data
.data
= datack
.data
;
2039 iov
.data
.length
= datack
.length
;
2040 iov
.flags
= KRB5_CRYPTO_TYPE_DATA
;
2042 ret
= _krb5_HMAC_MD5_checksum(context
, NULL
, &crypto
->key
,
2043 KRB5_KU_OTHER_CKSUM
, &iov
, 1,
2046 krb5_data_ct_cmp(&cs
.checksum
, &self
.cksum
.checksum
) != 0)
2047 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
2050 ret
= _kdc_verify_checksum(context
,
2052 KRB5_KU_OTHER_CKSUM
,
2056 krb5_data_free(&datack
);
2057 krb5_crypto_destroy(context
, crypto
);
2059 const char *msg
= krb5_get_error_message(context
, ret
);
2060 free_PA_S4U2Self(&self
);
2061 _kdc_audit_addreason((kdc_request_t
)priv
,
2062 "S4U2Self checksum failed");
2063 kdc_log(context
, config
, 4,
2064 "krb5_verify_checksum failed for S4U2Self: %s", msg
);
2065 krb5_free_error_message(context
, msg
);
2069 ret
= _krb5_principalname2krb5_principal(context
,
2073 free_PA_S4U2Self(&self
);
2077 ret
= krb5_unparse_name(context
, tp
, &tpn
);
2082 * Note no HDB_F_SYNTHETIC_OK -- impersonating non-existent clients
2083 * is probably not desirable!
2085 ret
= _kdc_db_fetch(context
, config
, tp
, HDB_F_GET_CLIENT
| flags
,
2086 NULL
, &s4u2self_impersonated_clientdb
,
2087 &s4u2self_impersonated_client
);
2092 * If the client belongs to the same realm as our krbtgt, it
2093 * should exist in the local database.
2097 if (ret
== HDB_ERR_NOENTRY
)
2098 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2099 msg
= krb5_get_error_message(context
, ret
);
2100 _kdc_audit_addreason((kdc_request_t
)priv
,
2101 "S4U2Self principal to impersonate not found");
2102 kdc_log(context
, config
, 2,
2103 "S4U2Self principal to impersonate %s not found in database: %s",
2105 krb5_free_error_message(context
, msg
);
2109 /* Ignore require_pwchange and pw_end attributes (as Windows does),
2110 * since S4U2Self is not password authentication. */
2111 s4u2self_impersonated_client
->entry
.flags
.require_pwchange
= FALSE
;
2112 free(s4u2self_impersonated_client
->entry
.pw_end
);
2113 s4u2self_impersonated_client
->entry
.pw_end
= NULL
;
2115 ret
= kdc_check_flags(priv
, FALSE
, s4u2self_impersonated_client
, priv
->server
);
2117 goto out
; /* kdc_check_flags() calls _kdc_audit_addreason() */
2119 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
2120 krb5_pac_free(context
, priv
->pac
);
2123 ret
= _kdc_pac_generate(context
,
2124 s4u2self_impersonated_client
,
2127 KRB5_PAC_WAS_GIVEN_IMPLICITLY
,
2130 kdc_log(context
, config
, 4, "PAC generation failed for -- %s", tpn
);
2135 * Check that service doing the impersonating is
2136 * requesting a ticket to it-self.
2138 ret
= check_client_matches_target_service(context
,
2145 kdc_log(context
, config
, 4, "S4U2Self: %s is not allowed "
2146 "to impersonate to service "
2147 "(tried for user %s to service %s)",
2153 * If the service isn't trusted for authentication to
2154 * delegation or if the impersonate client is disallowed
2155 * forwardable, remove the forwardable flag.
2158 if (client
->entry
.flags
.trusted_for_delegation
&&
2159 s4u2self_impersonated_client
->entry
.flags
.forwardable
) {
2160 str
= "[forwardable]";
2162 b
->kdc_options
.forwardable
= 0;
2165 kdc_log(context
, config
, 4, "s4u2self %s impersonating %s to "
2166 "service %s %s", cpn
, tpn
, spn
, str
);
2171 * Constrained delegation
2175 && b
->additional_tickets
!= NULL
2176 && b
->additional_tickets
->len
!= 0
2177 && b
->kdc_options
.cname_in_addl_tkt
2178 && b
->kdc_options
.enc_tkt_in_skey
== 0)
2180 hdb_entry_ex
*adclient
= NULL
;
2181 krb5_boolean ad_kdc_issued
= FALSE
;
2186 * We require that the service's krbtgt has a PAC.
2188 if (priv
->pac
== NULL
) {
2189 ret
= KRB5KDC_ERR_BADOPTION
;
2190 _kdc_audit_addreason((kdc_request_t
)priv
, "Missing PAC");
2191 kdc_log(context
, config
, 4,
2192 "Constrained delegation without PAC, %s/%s",
2197 krb5_pac_free(context
, priv
->pac
);
2200 krb5_free_principal(context
, priv
->client_princ
);
2201 priv
->client_princ
= NULL
;
2203 t
= &b
->additional_tickets
->val
[0];
2205 ret
= hdb_enctype2key(context
, &client
->entry
,
2206 hdb_kvno2keys(context
, &client
->entry
,
2207 t
->enc_part
.kvno
? * t
->enc_part
.kvno
: 0),
2208 t
->enc_part
.etype
, &clientkey
);
2210 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
2214 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
2216 _kdc_audit_addreason((kdc_request_t
)priv
,
2217 "Failed to decrypt constrained delegation ticket");
2218 kdc_log(context
, config
, 4,
2219 "failed to decrypt ticket for "
2220 "constrained delegation from %s to %s ", cpn
, spn
);
2224 ret
= _krb5_principalname2krb5_principal(context
,
2231 ret
= krb5_unparse_name(context
, tp
, &tpn
);
2235 _kdc_audit_addkv((kdc_request_t
)priv
, 0, "impersonatee", "%s", tpn
);
2237 ret
= _krb5_principalname2krb5_principal(context
,
2244 ret
= krb5_unparse_name(context
, dp
, &dpn
);
2248 /* check that ticket is valid */
2249 if (adtkt
.flags
.forwardable
== 0) {
2250 _kdc_audit_addreason((kdc_request_t
)priv
,
2251 "Missing forwardable flag on ticket for constrained delegation");
2252 kdc_log(context
, config
, 4,
2253 "Missing forwardable flag on ticket for "
2254 "constrained delegation from %s (%s) as %s to %s ",
2255 cpn
, dpn
, tpn
, spn
);
2256 ret
= KRB5KDC_ERR_BADOPTION
;
2260 ret
= check_constrained_delegation(context
, config
, clientdb
,
2261 client
, server
, sp
);
2263 _kdc_audit_addreason((kdc_request_t
)priv
,
2264 "Constrained delegation not allowed");
2265 kdc_log(context
, config
, 4,
2266 "constrained delegation from %s (%s) as %s to %s not allowed",
2267 cpn
, dpn
, tpn
, spn
);
2271 ret
= _kdc_verify_flags(context
, config
, &adtkt
, tpn
);
2273 _kdc_audit_addreason((kdc_request_t
)priv
,
2274 "Constrained delegation ticket expired or invalid");
2278 /* Try lookup the delegated client in DB */
2279 ret
= _kdc_db_fetch_client(context
, config
, flags
, tp
, tpn
, our_realm
,
2284 if (adclient
!= NULL
) {
2285 ret
= kdc_check_flags(priv
, FALSE
, adclient
, priv
->server
);
2287 _kdc_free_ent(context
, adclient
);
2293 * TODO: pass in t->sname and t->realm and build
2294 * a S4U_DELEGATION_INFO blob to the PAC.
2296 ret
= _kdc_check_pac(context
, config
, tp
, dp
, adclient
, server
, krbtgt
, client
,
2297 &clientkey
->key
, &priv
->ticket_key
->key
, &adtkt
,
2298 &ad_kdc_issued
, &priv
->pac
, &priv
->client_princ
, &priv
->pac_attributes
);
2300 _kdc_free_ent(context
, adclient
);
2302 const char *msg
= krb5_get_error_message(context
, ret
);
2303 _kdc_audit_addreason((kdc_request_t
)priv
,
2304 "Constrained delegation ticket PAC check failed");
2305 kdc_log(context
, config
, 4,
2306 "Verify delegated PAC failed to %s for client"
2307 "%s (%s) as %s from %s with %s",
2308 spn
, cpn
, dpn
, tpn
, from
, msg
);
2309 krb5_free_error_message(context
, msg
);
2313 if (priv
->pac
== NULL
|| !ad_kdc_issued
) {
2314 ret
= KRB5KDC_ERR_BADOPTION
;
2315 kdc_log(context
, config
, 4,
2316 "Ticket not signed with PAC; service %s failed for "
2317 "for delegation to %s for client %s (%s) from %s; (%s).",
2318 spn
, tpn
, dpn
, cpn
, from
, priv
->pac
? "Ticket unsigned" : "No PAC");
2319 _kdc_audit_addreason((kdc_request_t
)priv
,
2320 "Constrained delegation ticket not signed");
2324 kdc_log(context
, config
, 4, "constrained delegation for %s "
2325 "from %s (%s) to %s", tpn
, cpn
, dpn
, spn
);
2332 ret
= kdc_check_flags(priv
, FALSE
, priv
->client
, priv
->server
);
2336 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
2337 !krb5_principal_compare(context
,
2338 krbtgt
->entry
.principal
,
2339 server
->entry
.principal
)){
2340 _kdc_audit_addreason((kdc_request_t
)priv
, "Inconsistent request");
2341 kdc_log(context
, config
, 4, "Inconsistent request.");
2342 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
2346 /* check for valid set of addresses */
2347 if (!_kdc_check_addresses(priv
, tgt
->caddr
, from_addr
)) {
2348 if (config
->check_ticket_addresses
) {
2349 ret
= KRB5KRB_AP_ERR_BADADDR
;
2350 _kdc_audit_addkv((kdc_request_t
)priv
, 0, "wrongaddr", "yes");
2351 kdc_log(context
, config
, 4, "Request from wrong address");
2352 _kdc_audit_addreason((kdc_request_t
)priv
, "Request from wrong address");
2354 } else if (config
->warn_ticket_addresses
) {
2355 _kdc_audit_addkv((kdc_request_t
)priv
, 0, "wrongaddr", "yes");
2359 /* check local and per-principal anonymous ticket issuance policy */
2360 if (is_anon_tgs_request_p(b
, tgt
)) {
2361 ret
= _kdc_check_anon_policy(priv
);
2367 * If this is an referral, add server referral data to the
2374 kdc_log(context
, config
, 3,
2375 "Adding server referral to %s", ref_realm
);
2377 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
2381 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
2382 NULL
, s
, &pa
.padata_value
);
2383 krb5_crypto_destroy(context
, crypto
);
2385 _kdc_audit_addreason((kdc_request_t
)priv
, "Referral build failed");
2386 kdc_log(context
, config
, 4,
2387 "Failed building server referral");
2390 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
2392 ret
= add_METHOD_DATA(&priv
->outpadata
, &pa
);
2393 krb5_data_free(&pa
.padata_value
);
2395 kdc_log(context
, config
, 4,
2396 "Add server referral METHOD-DATA failed");
2402 * Only add ticket signature if the requested server is not krbtgt, and
2403 * either the header server is krbtgt or, in the case of renewal/validation
2404 * if it was signed with PAC ticket signature and we verified it.
2405 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2406 * change one day (see issue #763) so make sure to check for it.
2410 !krb5_principal_is_krbtgt(context
, server
->entry
.principal
)) {
2412 /* Validate armor TGT before potentially including device claims */
2413 if (priv
->armor_ticket
) {
2414 ret
= _kdc_fast_check_armor_pac(priv
);
2419 add_ticket_sig
= TRUE
;
2423 * Active-Directory implementations use the high part of the kvno as the
2424 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2427 rodc_id
= krbtgt_out
->entry
.kvno
>> 16;
2433 ret
= tgs_make_reply(priv
,
2450 free(user2user_name
);
2455 _krb5_free_capath(context
, capath
);
2457 krb5_free_keyblock_contents(context
, &sessionkey
);
2459 _kdc_free_ent(context
, krbtgt_out
);
2461 _kdc_free_ent(context
, server
);
2463 _kdc_free_ent(context
, client
);
2464 if(s4u2self_impersonated_client
)
2465 _kdc_free_ent(context
, s4u2self_impersonated_client
);
2466 if(user2user_krbtgt
)
2467 _kdc_free_ent(context
, user2user_krbtgt
);
2469 krb5_free_principal(context
, user2user_princ
);
2471 krb5_free_principal(context
, tp
);
2472 krb5_free_principal(context
, cp
);
2473 krb5_free_principal(context
, dp
);
2474 krb5_free_principal(context
, sp
);
2475 krb5_free_principal(context
, krbtgt_out_principal
);
2478 free_EncTicketPart(&adtkt
);
2480 krb5_pac_free(context
, user2user_pac
);
2490 _kdc_tgs_rep(astgs_request_t r
)
2492 krb5_kdc_configuration
*config
= r
->config
;
2493 KDC_REQ
*req
= &r
->req
;
2494 krb5_data
*data
= r
->reply
;
2495 const char *from
= r
->from
;
2496 struct sockaddr
*from_addr
= r
->addr
;
2497 int datagram_reply
= r
->datagram_reply
;
2498 AuthorizationData
*auth_data
= NULL
;
2499 krb5_error_code ret
;
2501 const PA_DATA
*tgs_req
, *pa
;
2503 hdb_entry_ex
*krbtgt
= NULL
;
2504 krb5_ticket
*ticket
= NULL
;
2505 const char *e_text
= NULL
;
2506 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2508 time_t *csec
= NULL
;
2511 if(req
->padata
== NULL
){
2512 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2513 kdc_log(r
->context
, config
, 4,
2514 "TGS-REQ from %s without PA-DATA", from
);
2519 pa
= _kdc_find_padata(&r
->req
, &i
, KRB5_PADATA_FX_FAST_ARMOR
);
2521 kdc_log(r
->context
, r
->config
, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2522 ret
= KRB5KRB_ERR_GENERIC
;
2527 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2528 if(tgs_req
== NULL
){
2529 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2531 kdc_log(r
->context
, config
, 4,
2532 "TGS-REQ from %s without PA-TGS-REQ", from
);
2535 ret
= tgs_parse_request(r
, tgs_req
,
2543 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2544 /* kdc_log() is called in tgs_parse_request() */
2548 kdc_log(r
->context
, config
, 4,
2549 "Failed parsing TGS-REQ from %s", from
);
2553 ret
= _kdc_fast_strengthen_reply_key(r
);
2557 ret
= tgs_build_reply(r
,
2565 kdc_log(r
->context
, config
, 4,
2566 "Failed building TGS-REP to %s", from
);
2571 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2572 krb5_data_free(data
);
2573 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2574 e_text
= "Reply packet too large";
2578 if(ret
&& ret
!= HDB_ERR_NOT_FOUND_HERE
&& data
->data
== NULL
){
2579 METHOD_DATA error_method
= { 0, NULL
};
2581 kdc_log(r
->context
, config
, 5, "tgs-req: sending error: %d to client", ret
);
2582 ret
= _kdc_fast_mk_error(r
,
2587 ticket
!= NULL
? ticket
->client
: NULL
,
2588 ticket
!= NULL
? ticket
->server
: NULL
,
2591 free_METHOD_DATA(&error_method
);
2596 r
->rep
.padata
= NULL
; /* may point to outpadata */
2597 free_TGS_REP(&r
->rep
);
2598 free_TransitedEncoding(&r
->et
.transited
);
2599 free(r
->et
.starttime
);
2600 free(r
->et
.renew_till
);
2601 if(r
->et
.authorization_data
) {
2602 free_AuthorizationData(r
->et
.authorization_data
);
2603 free(r
->et
.authorization_data
);
2605 free_LastReq(&r
->ek
.last_req
);
2606 if (r
->et
.key
.keyvalue
.data
) {
2607 memset_s(r
->et
.key
.keyvalue
.data
, 0, r
->et
.key
.keyvalue
.length
,
2608 r
->et
.key
.keyvalue
.length
);
2610 free_EncryptionKey(&r
->et
.key
);
2612 if (r
->client_princ
) {
2613 krb5_free_principal(r
->context
, r
->client_princ
);
2614 r
->client_princ
= NULL
;
2616 if (r
->armor_crypto
) {
2617 krb5_crypto_destroy(r
->context
, r
->armor_crypto
);
2618 r
->armor_crypto
= NULL
;
2620 if (r
->armor_ticket
)
2621 krb5_free_ticket(r
->context
, r
->armor_ticket
);
2622 if (r
->armor_server
)
2623 _kdc_free_ent(r
->context
, r
->armor_server
);
2624 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
2625 krb5_free_keyblock_contents(r
->context
, &r
->strengthen_key
);
2628 krb5_free_ticket(r
->context
, ticket
);
2630 _kdc_free_ent(r
->context
, krbtgt
);
2632 _kdc_free_fast_state(&r
->fast
);
2633 krb5_pac_free(r
->context
, r
->pac
);
2635 if (r
->outpadata
.len
)
2636 free_METHOD_DATA(&r
->outpadata
);
2639 free_AuthorizationData(auth_data
);