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
*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
, config
,
126 client_principal
, delegated_proxy_principal
,
127 client
, server
, krbtgt
, &pac
);
129 if (pac_canon_name
) {
130 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
131 if (ret
&& ret
!= ENOENT
) {
132 krb5_pac_free(context
, pac
);
136 if (pac_attributes
&&
137 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
138 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
139 } else if (ret
== KRB5_PLUGIN_NO_HANDLE
) {
141 * We can't verify the KDC signatures if the ticket was issued by
142 * another realm's KDC.
144 if (krb5_realm_compare(context
, server
->principal
,
145 ticket_server
->principal
)) {
146 ret
= krb5_pac_verify(context
, pac
, 0, NULL
, NULL
,
149 krb5_pac_free(context
, pac
);
154 if (pac_canon_name
) {
155 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
156 if (ret
&& ret
!= ENOENT
) {
157 krb5_pac_free(context
, pac
);
160 if (pac_attributes
&&
161 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
162 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
165 /* Discard the PAC if the plugin didn't handle it */
166 krb5_pac_free(context
, pac
);
167 ret
= krb5_pac_init(context
, &pac
);
171 krb5_pac_free(context
, pac
);
175 *kdc_issued
= signedticket
||
176 krb5_principal_is_krbtgt(context
,
177 ticket_server
->principal
);
184 is_anon_tgs_request_p(const KDC_REQ_BODY
*b
,
185 const EncTicketPart
*tgt
)
187 KDCOptions f
= b
->kdc_options
;
190 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
191 * request-anonymous and cname-in-addl-tkt flags for constrained
192 * delegation requests. A true anonymous TGS request will only
193 * have the request-anonymous flag set. (A corollary of this is
194 * that it is not possible to support anonymous constrained
195 * delegation requests, although they would be of limited utility.)
197 return tgt
->flags
.anonymous
||
198 (f
.request_anonymous
&& !f
.cname_in_addl_tkt
&& !b
->additional_tickets
);
205 static krb5_error_code
206 check_tgs_flags(astgs_request_t r
, KDC_REQ_BODY
*b
,
207 krb5_const_principal tgt_name
,
208 const EncTicketPart
*tgt
, EncTicketPart
*et
)
210 KDCOptions f
= b
->kdc_options
;
213 if (!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
) {
214 _kdc_audit_addreason((kdc_request_t
)r
,
215 "Bad request to validate ticket");
216 return KRB5KDC_ERR_BADOPTION
;
218 if(*tgt
->starttime
> kdc_time
){
219 _kdc_audit_addreason((kdc_request_t
)r
,
220 "Early request to validate ticket");
221 return KRB5KRB_AP_ERR_TKT_NYV
;
224 et
->flags
.invalid
= 0;
225 } else if (tgt
->flags
.invalid
) {
226 _kdc_audit_addreason((kdc_request_t
)r
,
227 "Ticket-granting ticket has INVALID flag set");
228 return KRB5KRB_AP_ERR_TKT_INVALID
;
232 if (!tgt
->flags
.forwardable
) {
233 _kdc_audit_addreason((kdc_request_t
)r
,
234 "Bad request for forwardable ticket");
235 return KRB5KDC_ERR_BADOPTION
;
237 et
->flags
.forwardable
= 1;
240 if (!tgt
->flags
.forwardable
) {
241 _kdc_audit_addreason((kdc_request_t
)r
,
242 "Request to forward non-forwardable ticket");
243 return KRB5KDC_ERR_BADOPTION
;
245 et
->flags
.forwarded
= 1;
246 et
->caddr
= b
->addresses
;
248 if(tgt
->flags
.forwarded
)
249 et
->flags
.forwarded
= 1;
252 if (!tgt
->flags
.proxiable
) {
253 _kdc_audit_addreason((kdc_request_t
)r
,
254 "Bad request for proxiable ticket");
255 return KRB5KDC_ERR_BADOPTION
;
257 et
->flags
.proxiable
= 1;
260 if (!tgt
->flags
.proxiable
) {
261 _kdc_audit_addreason((kdc_request_t
)r
,
262 "Request to proxy non-proxiable ticket");
263 return KRB5KDC_ERR_BADOPTION
;
266 et
->caddr
= b
->addresses
;
271 if(f
.allow_postdate
){
272 if (!tgt
->flags
.may_postdate
) {
273 _kdc_audit_addreason((kdc_request_t
)r
,
274 "Bad request for post-datable ticket");
275 return KRB5KDC_ERR_BADOPTION
;
277 et
->flags
.may_postdate
= 1;
280 if (!tgt
->flags
.may_postdate
) {
281 _kdc_audit_addreason((kdc_request_t
)r
,
282 "Bad request for postdated ticket");
283 return KRB5KDC_ERR_BADOPTION
;
286 *et
->starttime
= *b
->from
;
287 et
->flags
.postdated
= 1;
288 et
->flags
.invalid
= 1;
289 } else if (b
->from
&& *b
->from
> kdc_time
+ r
->context
->max_skew
) {
290 _kdc_audit_addreason((kdc_request_t
)r
,
291 "Ticket cannot be postdated");
292 return KRB5KDC_ERR_CANNOT_POSTDATE
;
296 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
297 _kdc_audit_addreason((kdc_request_t
)r
,
298 "Bad request for renewable ticket");
299 return KRB5KDC_ERR_BADOPTION
;
301 et
->flags
.renewable
= 1;
302 ALLOC(et
->renew_till
);
303 _kdc_fix_time(&b
->rtime
);
304 *et
->renew_till
= *b
->rtime
;
308 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
309 _kdc_audit_addreason((kdc_request_t
)r
,
310 "Request to renew non-renewable ticket");
311 return KRB5KDC_ERR_BADOPTION
;
313 old_life
= tgt
->endtime
;
315 old_life
-= *tgt
->starttime
;
317 old_life
-= tgt
->authtime
;
318 et
->endtime
= *et
->starttime
+ old_life
;
319 if (et
->renew_till
!= NULL
)
320 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
324 * RFC 8062 section 3 defines an anonymous ticket as one containing
325 * the anonymous principal and the anonymous ticket flag.
327 if (tgt
->flags
.anonymous
&&
328 !_kdc_is_anonymous(r
->context
, tgt_name
)) {
329 _kdc_audit_addreason((kdc_request_t
)r
,
330 "Anonymous ticket flag set without "
331 "anonymous principal");
332 return KRB5KDC_ERR_BADOPTION
;
336 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
337 * anonymous KDC option SHOULD be set, but it is not required.
338 * Treat an anonymous TGT as if the anonymous flag was set.
340 if (is_anon_tgs_request_p(b
, tgt
))
341 et
->flags
.anonymous
= 1;
347 * Determine if s4u2self is allowed from this client to this server
351 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
352 * service given by the client.
354 * For example, regardless of the principal being impersonated, if the
355 * 'client' and 'server' (target) are the same, or server is an SPN
356 * alias of client, then it's safe.
360 _kdc_check_client_matches_target_service(krb5_context context
,
361 krb5_kdc_configuration
*config
,
364 hdb_entry
*target_server
,
365 krb5_const_principal target_server_principal
)
370 * Always allow the plugin to check, this might be faster, allow a
371 * policy or audit check and can look into the DB records
374 if (clientdb
->hdb_check_client_matches_target_service
) {
375 ret
= clientdb
->hdb_check_client_matches_target_service(context
,
381 } else if (krb5_principal_compare(context
,
383 target_server_principal
) == TRUE
) {
384 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
387 ret
= KRB5KDC_ERR_BADOPTION
;
397 _kdc_verify_flags(krb5_context context
,
398 krb5_kdc_configuration
*config
,
399 const EncTicketPart
*et
,
402 if(et
->endtime
< kdc_time
){
403 kdc_log(context
, config
, 4, "Ticket expired (%s)", pstr
);
404 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
406 if(et
->flags
.invalid
){
407 kdc_log(context
, config
, 4, "Ticket not valid (%s)", pstr
);
408 return KRB5KRB_AP_ERR_TKT_NYV
;
417 static krb5_error_code
418 fix_transited_encoding(krb5_context context
,
419 krb5_kdc_configuration
*config
,
420 krb5_boolean check_policy
,
421 const TransitedEncoding
*tr
,
423 const char *client_realm
,
424 const char *server_realm
,
425 const char *tgt_realm
)
427 krb5_error_code ret
= 0;
428 char **realms
, **tmp
;
429 unsigned int num_realms
;
432 switch (tr
->tr_type
) {
433 case domain_X500_Compress
:
437 * Allow empty content of type 0 because that is was Microsoft
438 * generates in their TGT.
440 if (tr
->contents
.length
== 0)
442 kdc_log(context
, config
, 4,
443 "Transited type 0 with non empty content");
444 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
446 kdc_log(context
, config
, 4,
447 "Unknown transited type: %u", tr
->tr_type
);
448 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
451 ret
= krb5_domain_x500_decode(context
,
458 krb5_warn(context
, ret
,
459 "Decoding transited encoding");
464 * If the realm of the presented tgt is neither the client nor the server
465 * realm, it is a transit realm and must be added to transited set.
467 if (strcmp(client_realm
, tgt_realm
) != 0 &&
468 strcmp(server_realm
, tgt_realm
) != 0) {
469 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
473 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
479 realms
[num_realms
] = strdup(tgt_realm
);
480 if(realms
[num_realms
] == NULL
){
486 if(num_realms
== 0) {
487 if (strcmp(client_realm
, server_realm
) != 0)
488 kdc_log(context
, config
, 4,
489 "cross-realm %s -> %s", client_realm
, server_realm
);
493 for(i
= 0; i
< num_realms
; i
++)
494 l
+= strlen(realms
[i
]) + 2;
498 for(i
= 0; i
< num_realms
; i
++) {
500 strlcat(rs
, ", ", l
);
501 strlcat(rs
, realms
[i
], l
);
503 kdc_log(context
, config
, 4,
504 "cross-realm %s -> %s via [%s]",
505 client_realm
, server_realm
, rs
);
510 ret
= krb5_check_transited(context
, client_realm
,
512 realms
, num_realms
, NULL
);
514 krb5_warn(context
, ret
, "cross-realm %s -> %s",
515 client_realm
, server_realm
);
518 et
->flags
.transited_policy_checked
= 1;
520 et
->transited
.tr_type
= domain_X500_Compress
;
521 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
523 krb5_warn(context
, ret
, "Encoding transited encoding");
525 for(i
= 0; i
< num_realms
; i
++)
532 static krb5_error_code
533 tgs_make_reply(astgs_request_t r
,
534 const EncTicketPart
*tgt
,
535 const EncryptionKey
*serverkey
,
536 const EncryptionKey
*krbtgtkey
,
537 const krb5_keyblock
*sessionkey
,
539 AuthorizationData
*auth_data
,
541 krb5_principal server_principal
,
543 krb5_principal client_principal
,
544 const char *tgt_realm
,
546 krb5_boolean add_ticket_sig
)
548 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
549 krb5_data
*reply
= r
->reply
;
550 KDC_REP
*rep
= &r
->rep
;
551 EncTicketPart
*et
= &r
->et
;
552 EncKDCRepPart
*ek
= &r
->ek
;
553 KDCOptions f
= b
->kdc_options
;
557 heim_assert(r
->client_princ
!= NULL
, "invalid client name passed to tgs_make_reply");
560 rep
->msg_type
= krb_tgs_rep
;
562 et
->authtime
= tgt
->authtime
;
563 _kdc_fix_time(&b
->till
);
564 et
->endtime
= min(tgt
->endtime
, *b
->till
);
565 ALLOC(et
->starttime
);
566 *et
->starttime
= kdc_time
;
568 ret
= check_tgs_flags(r
, b
, r
->client_princ
, tgt
, et
);
572 /* We should check the transited encoding if:
573 1) the request doesn't ask not to be checked
574 2) globally enforcing a check
575 3) principal requires checking
576 4) we allow non-check per-principal, but principal isn't marked as allowing this
577 5) we don't globally allow this
580 #define GLOBAL_FORCE_TRANSITED_CHECK \
581 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
582 #define GLOBAL_ALLOW_PER_PRINCIPAL \
583 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
584 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
585 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
587 /* these will consult the database in future release */
588 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
589 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
591 ret
= fix_transited_encoding(r
->context
, r
->config
,
592 !f
.disable_transited_check
||
593 GLOBAL_FORCE_TRANSITED_CHECK
||
594 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
595 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
596 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
597 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
599 krb5_principal_get_realm(r
->context
, client_principal
),
600 krb5_principal_get_realm(r
->context
, server
->principal
),
605 ret
= copy_Realm(&server_principal
->realm
, &rep
->ticket
.realm
);
608 _krb5_principal2principalname(&rep
->ticket
.sname
, server_principal
);
609 ret
= copy_Realm(&r
->client_princ
->realm
, &rep
->crealm
);
614 * RFC 8062 states "if the ticket in the TGS request is an anonymous
615 * one, the client and client realm are copied from that ticket". So
616 * whilst the TGT flag check below is superfluous, it is included in
617 * order to follow the specification to its letter.
619 if (et
->flags
.anonymous
&& !tgt
->flags
.anonymous
)
620 _kdc_make_anonymous_principalname(&rep
->cname
);
622 ret
= copy_PrincipalName(&r
->client_princ
->name
, &rep
->cname
);
625 rep
->ticket
.tkt_vno
= 5;
627 ek
->caddr
= et
->caddr
;
631 life
= et
->endtime
- *et
->starttime
;
632 if(client
&& client
->max_life
)
633 life
= min(life
, *client
->max_life
);
635 life
= min(life
, *server
->max_life
);
636 et
->endtime
= *et
->starttime
+ life
;
638 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
639 et
->renew_till
== NULL
&& et
->endtime
< *b
->till
&&
640 tgt
->renew_till
!= NULL
)
642 et
->flags
.renewable
= 1;
643 ALLOC(et
->renew_till
);
644 *et
->renew_till
= *b
->till
;
648 renew
= *et
->renew_till
- *et
->starttime
;
649 if(client
&& client
->max_renew
)
650 renew
= min(renew
, *client
->max_renew
);
651 if(server
->max_renew
)
652 renew
= min(renew
, *server
->max_renew
);
653 *et
->renew_till
= *et
->starttime
+ renew
;
657 *et
->renew_till
= min(*et
->renew_till
, *tgt
->renew_till
);
658 *et
->starttime
= min(*et
->starttime
, *et
->renew_till
);
659 et
->endtime
= min(et
->endtime
, *et
->renew_till
);
662 *et
->starttime
= min(*et
->starttime
, et
->endtime
);
664 if(*et
->starttime
== et
->endtime
){
665 ret
= KRB5KDC_ERR_NEVER_VALID
;
668 if(et
->renew_till
&& et
->endtime
== *et
->renew_till
){
669 free(et
->renew_till
);
670 et
->renew_till
= NULL
;
671 et
->flags
.renewable
= 0;
674 et
->flags
.pre_authent
= tgt
->flags
.pre_authent
;
675 et
->flags
.hw_authent
= tgt
->flags
.hw_authent
;
676 et
->flags
.ok_as_delegate
= server
->flags
.ok_as_delegate
;
678 /* See MS-KILE 3.3.5.1 */
679 if (!server
->flags
.forwardable
)
680 et
->flags
.forwardable
= 0;
681 if (!server
->flags
.proxiable
)
682 et
->flags
.proxiable
= 0;
687 /* XXX check authdata */
689 if (et
->authorization_data
== NULL
) {
690 et
->authorization_data
= calloc(1, sizeof(*et
->authorization_data
));
691 if (et
->authorization_data
== NULL
) {
693 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
697 for(i
= 0; i
< auth_data
->len
; i
++) {
698 ret
= add_AuthorizationData(et
->authorization_data
, &auth_data
->val
[i
]);
700 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
706 ret
= krb5_copy_keyblock_contents(r
->context
, sessionkey
, &et
->key
);
709 et
->crealm
= rep
->crealm
;
710 et
->cname
= rep
->cname
;
713 /* MIT must have at least one last_req */
714 ek
->last_req
.val
= calloc(1, sizeof(*ek
->last_req
.val
));
715 if (ek
->last_req
.val
== NULL
) {
719 ek
->last_req
.len
= 1; /* set after alloc to avoid null deref on cleanup */
720 ek
->nonce
= b
->nonce
;
721 ek
->flags
= et
->flags
;
722 ek
->authtime
= et
->authtime
;
723 ek
->starttime
= et
->starttime
;
724 ek
->endtime
= et
->endtime
;
725 ek
->renew_till
= et
->renew_till
;
726 ek
->srealm
= rep
->ticket
.realm
;
727 ek
->sname
= rep
->ticket
.sname
;
729 _kdc_log_timestamp(r
, "TGS-REQ", et
->authtime
, et
->starttime
,
730 et
->endtime
, et
->renew_till
);
732 if (krb5_enctype_valid(r
->context
, serverkey
->keytype
) != 0
733 && _kdc_is_weak_exception(server
->principal
, serverkey
->keytype
))
735 krb5_enctype_enable(r
->context
, serverkey
->keytype
);
739 if (r
->canon_client_princ
) {
742 (void) krb5_unparse_name(r
->context
, r
->canon_client_princ
, &cpn
);
743 _kdc_audit_addkv((kdc_request_t
)r
, 0, "canon_client_name", "%s",
744 cpn
? cpn
: "<unknown>");
749 * For anonymous tickets, we should filter out positive authorization data
750 * that could reveal the client's identity, and return a policy error for
751 * restrictive authorization data. Policy for unknown authorization types
752 * is implementation dependent.
754 if (r
->pac
&& !et
->flags
.anonymous
) {
755 _kdc_audit_setkv_number((kdc_request_t
)r
, "pac_attributes",
759 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
760 * buffer (legacy behavior) or if the attributes buffer indicates the
761 * AS client requested one.
763 if (_kdc_include_pac_p(r
)) {
764 krb5_boolean is_tgs
=
765 krb5_principal_is_krbtgt(r
->context
, server
->principal
);
767 ret
= _krb5_kdc_pac_sign_ticket(r
->context
, r
->pac
, r
->client_princ
, serverkey
,
768 krbtgtkey
, rodc_id
, NULL
, r
->canon_client_princ
,
770 is_tgs
? &r
->pac_attributes
: NULL
);
776 ret
= _kdc_finalize_reply(r
);
780 /* It is somewhat unclear where the etype in the following
781 encryption should come from. What we have is a session
782 key in the passed tgt, and a list of preferred etypes
783 *for the new ticket*. Should we pick the best possible
784 etype, given the keytype in the tgt, or should we look
785 at the etype list here as well? What if the tgt
786 session key is DES3 and we want a ticket with a (say)
787 CAST session key. Should the DES3 etype be added to the
788 etype list, even if we don't want a session key with
790 ret
= _kdc_encode_reply(r
->context
, r
->config
, r
, b
->nonce
,
791 serverkey
->keytype
, kvno
,
792 serverkey
, 0, r
->rk_is_subkey
, reply
);
794 krb5_enctype_disable(r
->context
, serverkey
->keytype
);
796 _log_astgs_req(r
, serverkey
->keytype
);
802 static krb5_error_code
803 tgs_check_authenticator(krb5_context context
,
804 krb5_kdc_configuration
*config
,
805 krb5_auth_context ac
,
809 krb5_authenticator auth
;
813 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
814 if(auth
->cksum
== NULL
){
815 kdc_log(context
, config
, 4, "No authenticator in request");
816 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
820 if (!krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
821 kdc_log(context
, config
, 4, "Bad checksum type in authenticator: %d",
822 auth
->cksum
->cksumtype
);
823 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
827 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
829 const char *msg
= krb5_get_error_message(context
, ret
);
830 kdc_log(context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
831 krb5_free_error_message(context
, msg
);
836 * RFC4120 says the checksum must be collision-proof, but it does
837 * not require it to be keyed (as the authenticator is encrypted).
839 _krb5_crypto_set_flags(context
, crypto
, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
);
840 ret
= _kdc_verify_checksum(context
,
842 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
845 krb5_crypto_destroy(context
, crypto
);
847 const char *msg
= krb5_get_error_message(context
, ret
);
848 kdc_log(context
, config
, 4,
849 "Failed to verify authenticator checksum: %s", msg
);
850 krb5_free_error_message(context
, msg
);
853 free_Authenticator(auth
);
859 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
860 const KDCOptions
* const options
, krb5_principal server
,
865 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
868 if (server
->name
.name_string
.len
== 1)
869 name
= server
->name
.name_string
.val
[0];
870 else if (server
->name
.name_string
.len
> 1)
871 name
= server
->name
.name_string
.val
[1];
875 kdc_log(context
, config
, 5, "Searching referral for %s", name
);
877 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
880 static krb5_error_code
881 validate_fast_ad(astgs_request_t r
, krb5_authdata
*auth_data
)
886 krb5_data_zero(&data
);
888 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
889 KRB5_AUTHDATA_FX_FAST_USED
, &data
);
891 r
->fast_asserted
= 1;
892 krb5_data_free(&data
);
895 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
896 KRB5_AUTHDATA_FX_FAST_ARMOR
, &data
);
898 kdc_log(r
->context
, r
->config
, 2,
899 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
900 krb5_data_free(&data
);
901 return KRB5KRB_AP_ERR_BAD_INTEGRITY
;
907 static krb5_error_code
908 tgs_parse_request(astgs_request_t r
,
909 const PA_DATA
*tgs_req
,
910 krb5_enctype
*krbtgt_etype
,
912 const struct sockaddr
*from_addr
,
915 AuthorizationData
**auth_data
)
917 krb5_kdc_configuration
*config
= r
->config
;
918 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
919 static char failed
[] = "<unparse_name failed>";
922 krb5_principal princ
;
923 krb5_auth_context ac
= NULL
;
924 krb5_flags ap_req_options
;
925 krb5_flags verify_ap_req_flags
= 0;
927 krb5uint32 krbtgt_kvno
; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
928 krb5uint32 krbtgt_kvno_try
;
929 int kvno_search_tries
= 4; /* number of kvnos to try when tkt_vno == 0 */
930 const Keys
*krbtgt_keys
;/* keyset for TGT tkt_vno */
932 krb5_keyblock
*subkey
= NULL
;
939 memset(&ap_req
, 0, sizeof(ap_req
));
940 ret
= krb5_decode_ap_req(r
->context
, &tgs_req
->padata_value
, &ap_req
);
942 const char *msg
= krb5_get_error_message(r
->context
, ret
);
943 kdc_log(r
->context
, config
, 4, "Failed to decode AP-REQ: %s", msg
);
944 krb5_free_error_message(r
->context
, msg
);
948 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
949 /* XXX check for ticket.sname == req.sname */
950 kdc_log(r
->context
, config
, 4, "PA-DATA is not a ticket-granting ticket");
951 ret
= KRB5KDC_ERR_POLICY
; /* ? */
955 _krb5_principalname2krb5_principal(r
->context
,
958 ap_req
.ticket
.realm
);
960 krbtgt_kvno
= ap_req
.ticket
.enc_part
.kvno
? *ap_req
.ticket
.enc_part
.kvno
: 0;
961 ret
= _kdc_db_fetch(r
->context
, config
, princ
, HDB_F_GET_KRBTGT
,
962 &krbtgt_kvno
, &r
->krbtgtdb
, &r
->krbtgt
);
964 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
965 /* XXX Factor out this unparsing of the same princ all over */
967 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
970 krb5_free_principal(r
->context
, princ
);
971 kdc_log(r
->context
, config
, 5,
972 "Ticket-granting ticket account %s does not have secrets at "
973 "this KDC, need to proxy", p
);
976 ret
= HDB_ERR_NOT_FOUND_HERE
;
978 } else if (ret
== HDB_ERR_KVNO_NOT_FOUND
) {
980 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
983 krb5_free_principal(r
->context
, princ
);
984 kdc_log(r
->context
, config
, 5,
985 "Ticket-granting ticket account %s does not have keys for "
986 "kvno %d at this KDC", p
, krbtgt_kvno
);
989 ret
= HDB_ERR_KVNO_NOT_FOUND
;
991 } else if (ret
== HDB_ERR_NO_MKEY
) {
993 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
996 krb5_free_principal(r
->context
, princ
);
997 kdc_log(r
->context
, config
, 5,
998 "Missing master key for decrypting keys for ticket-granting "
999 "ticket account %s with kvno %d at this KDC", p
, krbtgt_kvno
);
1002 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1005 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1007 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1010 kdc_log(r
->context
, config
, 4,
1011 "Ticket-granting ticket %s not found in database: %s", p
, msg
);
1012 krb5_free_principal(r
->context
, princ
);
1013 krb5_free_error_message(r
->context
, msg
);
1016 ret
= KRB5KRB_AP_ERR_NOT_US
;
1020 krbtgt_kvno_try
= krbtgt_kvno
? krbtgt_kvno
: r
->krbtgt
->kvno
;
1021 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1024 krbtgt_keys
= hdb_kvno2keys(r
->context
, r
->krbtgt
, krbtgt_kvno_try
);
1025 ret
= hdb_enctype2key(r
->context
, r
->krbtgt
, krbtgt_keys
,
1026 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1027 if (ret
&& krbtgt_kvno
== 0 && kvno_search_tries
> 0) {
1028 kvno_search_tries
--;
1032 char *str
= NULL
, *p
= NULL
;
1034 krb5_enctype_to_string(r
->context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1035 krb5_unparse_name(r
->context
, princ
, &p
);
1036 kdc_log(r
->context
, config
, 4,
1037 "No server key with enctype %s found for %s",
1038 str
? str
: "<unknown enctype>",
1039 p
? p
: "<unparse_name failed>");
1042 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1046 if (b
->kdc_options
.validate
)
1047 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1049 if (r
->config
->warn_ticket_addresses
)
1050 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS
;
1052 ret
= krb5_verify_ap_req2(r
->context
,
1057 verify_ap_req_flags
,
1060 KRB5_KU_TGS_REQ_AUTH
);
1061 if (r
->ticket
&& r
->ticket
->ticket
.caddr
)
1062 _kdc_audit_addaddrs((kdc_request_t
)r
, r
->ticket
->ticket
.caddr
, "tixaddrs");
1063 if (r
->config
->warn_ticket_addresses
&& ret
== KRB5KRB_AP_ERR_BADADDR
&&
1064 r
->ticket
!= NULL
) {
1065 _kdc_audit_setkv_bool((kdc_request_t
)r
, "wrongaddr", TRUE
);
1068 if (ret
== KRB5KRB_AP_ERR_BAD_INTEGRITY
&& kvno_search_tries
> 0) {
1069 kvno_search_tries
--;
1074 krb5_free_principal(r
->context
, princ
);
1076 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1077 kdc_log(r
->context
, config
, 4, "Failed to verify AP-REQ: %s", msg
);
1078 krb5_free_error_message(r
->context
, msg
);
1082 r
->ticket_key
= tkey
;
1085 krb5_authenticator auth
;
1087 ret
= krb5_auth_con_getauthenticator(r
->context
, ac
, &auth
);
1089 *csec
= malloc(sizeof(**csec
));
1090 if (*csec
== NULL
) {
1091 krb5_free_authenticator(r
->context
, &auth
);
1092 kdc_log(r
->context
, config
, 4, "malloc failed");
1095 **csec
= auth
->ctime
;
1096 *cusec
= malloc(sizeof(**cusec
));
1097 if (*cusec
== NULL
) {
1098 krb5_free_authenticator(r
->context
, &auth
);
1099 kdc_log(r
->context
, config
, 4, "malloc failed");
1102 **cusec
= auth
->cusec
;
1104 ret
= validate_fast_ad(r
, auth
->authorization_data
);
1105 krb5_free_authenticator(r
->context
, &auth
);
1111 ret
= tgs_check_authenticator(r
->context
, config
, ac
, b
, &r
->ticket
->ticket
.key
);
1113 krb5_auth_con_free(r
->context
, ac
);
1117 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1118 r
->rk_is_subkey
= 1;
1120 ret
= krb5_auth_con_getremotesubkey(r
->context
, ac
, &subkey
);
1122 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1123 krb5_auth_con_free(r
->context
, ac
);
1124 kdc_log(r
->context
, config
, 4, "Failed to get remote subkey: %s", msg
);
1125 krb5_free_error_message(r
->context
, msg
);
1129 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1130 r
->rk_is_subkey
= 0;
1132 ret
= krb5_auth_con_getkey(r
->context
, ac
, &subkey
);
1134 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1135 krb5_auth_con_free(r
->context
, ac
);
1136 kdc_log(r
->context
, config
, 4, "Failed to get session key: %s", msg
);
1137 krb5_free_error_message(r
->context
, msg
);
1142 krb5_auth_con_free(r
->context
, ac
);
1143 kdc_log(r
->context
, config
, 4,
1144 "Failed to get key for enc-authorization-data");
1145 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1149 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
1150 ret
= krb5_copy_keyblock_contents(r
->context
, subkey
, &r
->reply_key
);
1151 krb5_free_keyblock(r
->context
, subkey
);
1155 if (b
->enc_authorization_data
) {
1158 ret
= krb5_crypto_init(r
->context
, &r
->reply_key
, 0, &crypto
);
1160 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1161 krb5_auth_con_free(r
->context
, ac
);
1162 kdc_log(r
->context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
1163 krb5_free_error_message(r
->context
, msg
);
1166 ret
= krb5_decrypt_EncryptedData (r
->context
,
1169 b
->enc_authorization_data
,
1171 krb5_crypto_destroy(r
->context
, crypto
);
1173 krb5_auth_con_free(r
->context
, ac
);
1174 kdc_log(r
->context
, config
, 4,
1175 "Failed to decrypt enc-authorization-data");
1176 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1180 if (*auth_data
== NULL
) {
1181 krb5_auth_con_free(r
->context
, ac
);
1182 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1185 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1187 krb5_auth_con_free(r
->context
, ac
);
1190 kdc_log(r
->context
, config
, 4, "Failed to decode authorization data");
1191 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1196 ret
= validate_fast_ad(r
, r
->ticket
->ticket
.authorization_data
);
1202 * Check for FAST request
1205 ret
= _kdc_fast_unwrap_request(r
, r
->ticket
, ac
);
1209 krb5_auth_con_free(r
->context
, ac
);
1212 free_AP_REQ(&ap_req
);
1217 static krb5_error_code
1218 build_server_referral(krb5_context context
,
1219 krb5_kdc_configuration
*config
,
1220 krb5_crypto session
,
1221 krb5_const_realm referred_realm
,
1222 const PrincipalName
*true_principal_name
,
1223 const PrincipalName
*requested_principal
,
1226 PA_ServerReferralData ref
;
1227 krb5_error_code ret
;
1232 memset(&ref
, 0, sizeof(ref
));
1234 if (referred_realm
) {
1235 ALLOC(ref
.referred_realm
);
1236 if (ref
.referred_realm
== NULL
)
1238 *ref
.referred_realm
= strdup(referred_realm
);
1239 if (*ref
.referred_realm
== NULL
)
1242 if (true_principal_name
) {
1243 ALLOC(ref
.true_principal_name
);
1244 if (ref
.true_principal_name
== NULL
)
1246 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1250 if (requested_principal
) {
1251 ALLOC(ref
.requested_principal_name
);
1252 if (ref
.requested_principal_name
== NULL
)
1254 ret
= copy_PrincipalName(requested_principal
,
1255 ref
.requested_principal_name
);
1260 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1261 data
.data
, data
.length
,
1263 free_PA_ServerReferralData(&ref
);
1266 if (data
.length
!= size
)
1267 krb5_abortx(context
, "internal asn.1 encoder error");
1269 ret
= krb5_encrypt_EncryptedData(context
, session
,
1270 KRB5_KU_PA_SERVER_REFERRAL
,
1271 data
.data
, data
.length
,
1277 ASN1_MALLOC_ENCODE(EncryptedData
,
1278 outdata
->data
, outdata
->length
,
1280 free_EncryptedData(&ed
);
1283 if (outdata
->length
!= size
)
1284 krb5_abortx(context
, "internal asn.1 encoder error");
1288 free_PA_ServerReferralData(&ref
);
1289 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1294 * This function is intended to be used when failure to find the client is
1298 _kdc_db_fetch_client(krb5_context context
,
1299 krb5_kdc_configuration
*config
,
1303 const char *krbtgt_realm
,
1305 hdb_entry
**client_out
)
1307 krb5_error_code ret
;
1308 hdb_entry
*client
= NULL
;
1312 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| flags
,
1313 NULL
, clientdb
, &client
);
1314 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1316 * This is OK, we are just trying to find out if they have
1317 * been disabled or deleted in the meantime; missing secrets
1322 * If the client belongs to the same realm as our TGS, it
1323 * should exist in the local database.
1327 if (strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1328 if (ret
== HDB_ERR_NOENTRY
)
1329 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1330 kdc_log(context
, config
, 4, "Client no longer in database: %s", cpn
);
1334 msg
= krb5_get_error_message(context
, ret
);
1335 kdc_log(context
, config
, 4, "Client not found in database: %s", msg
);
1336 krb5_free_error_message(context
, msg
);
1337 } else if (client
->flags
.invalid
|| !client
->flags
.client
) {
1338 kdc_log(context
, config
, 4, "Client has invalid bit set");
1339 _kdc_free_ent(context
, *clientdb
, client
);
1340 return KRB5KDC_ERR_POLICY
;
1343 *client_out
= client
;
1348 static krb5_error_code
1349 tgs_build_reply(astgs_request_t priv
,
1350 krb5_enctype krbtgt_etype
,
1351 AuthorizationData
**auth_data
,
1352 const struct sockaddr
*from_addr
)
1354 krb5_context context
= priv
->context
;
1355 krb5_kdc_configuration
*config
= priv
->config
;
1356 KDC_REQ_BODY
*b
= &priv
->req
.req_body
;
1357 const char *from
= priv
->from
;
1358 krb5_error_code ret
, ret2
;
1359 krb5_principal rsp
= NULL
;
1360 krb5_principal krbtgt_out_principal
= NULL
;
1361 krb5_principal user2user_princ
= NULL
;
1362 char *spn
= NULL
, *cpn
= NULL
, *krbtgt_out_n
= NULL
;
1363 char *user2user_name
= NULL
;
1364 hdb_entry
*server
= NULL
, *client
= NULL
;
1365 HDB
*user2user_krbtgtdb
;
1366 hdb_entry
*user2user_krbtgt
= NULL
;
1368 HDB
*serverdb
= NULL
;
1369 krb5_realm ref_realm
= NULL
;
1370 EncTicketPart
*tgt
= &priv
->ticket
->ticket
;
1371 const EncryptionKey
*ekey
;
1372 krb5_keyblock sessionkey
;
1374 krb5_pac user2user_pac
= NULL
;
1376 krb5_boolean add_ticket_sig
= FALSE
;
1377 const char *tgt_realm
= /* Realm of TGT issuer */
1378 krb5_principal_get_realm(context
, priv
->krbtgt
->principal
);
1379 const char *our_realm
= /* Realm of this KDC */
1380 krb5_principal_get_comp_string(context
, priv
->krbtgt
->principal
, 1);
1381 char **capath
= NULL
;
1382 size_t num_capath
= 0;
1385 hdb_entry
*krbtgt_out
= NULL
;
1389 EncTicketPart adtkt
;
1391 krb5_boolean kdc_issued
= FALSE
;
1394 int flags
= HDB_F_FOR_TGS_REQ
;
1398 memset(&sessionkey
, 0, sizeof(sessionkey
));
1399 memset(&adtkt
, 0, sizeof(adtkt
));
1405 * The canonicalize KDC option is passed as a hint to the backend, but
1406 * can typically be ignored. Per RFC 6806, names are not canonicalized
1407 * in response to a TGS request (although we make an exception, see
1408 * force-canonicalize below).
1410 if (b
->kdc_options
.canonicalize
)
1411 flags
|= HDB_F_CANON
;
1414 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1415 _kdc_set_const_e_text(priv
, "No server in request");
1419 _krb5_principalname2krb5_principal(context
, &priv
->server_princ
, *s
, r
);
1420 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1424 _krb5_principalname2krb5_principal(context
, &priv
->client_princ
,
1425 tgt
->cname
, tgt
->crealm
);
1426 ret
= krb5_unparse_name(context
, priv
->client_princ
, &priv
->cname
);
1430 result
= unparse_flags(KDCOptions2int(b
->kdc_options
),
1431 asn1_KDCOptions_units(),
1432 opt_str
, sizeof(opt_str
));
1434 kdc_log(context
, config
, 4,
1435 "TGS-REQ %s from %s for %s [%s]",
1436 cpn
, from
, spn
, opt_str
);
1438 kdc_log(context
, config
, 4,
1439 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1446 priv
->server
= NULL
;
1448 _kdc_free_ent(context
, serverdb
, server
);
1450 ret
= _kdc_db_fetch(context
, config
, priv
->server_princ
,
1451 HDB_F_GET_SERVER
| HDB_F_DELAY_NEW_KEYS
| flags
,
1452 NULL
, &serverdb
, &server
);
1453 priv
->server
= server
;
1454 priv
->serverdb
= serverdb
;
1455 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1456 kdc_log(context
, config
, 5, "target %s does not have secrets at this KDC, need to proxy", spn
);
1457 _kdc_audit_addreason((kdc_request_t
)priv
, "Target not found here");
1459 } else if (ret
== HDB_ERR_WRONG_REALM
) {
1461 ref_realm
= strdup(server
->principal
->realm
);
1462 if (ref_realm
== NULL
) {
1463 ret
= krb5_enomem(context
);
1467 kdc_log(context
, config
, 4,
1468 "Returning a referral to realm %s for "
1471 krb5_free_principal(context
, priv
->server_princ
);
1472 priv
->server_princ
= NULL
;
1473 ret
= krb5_make_principal(context
, &priv
->server_princ
, r
, KRB5_TGS_NAME
,
1479 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1486 const char *new_rlm
, *msg
;
1490 priv
->ret
= ret
; /* advise policy plugin of failure reason */
1491 ret2
= _kdc_referral_policy(priv
);
1493 krb5_xfree(priv
->sname
);
1495 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1499 } else if (ret2
!= KRB5_PLUGIN_NO_HANDLE
) {
1501 } else if ((req_rlm
= get_krbtgt_realm(&priv
->server_princ
->name
)) != NULL
) {
1502 if (capath
== NULL
) {
1503 /* With referalls, hierarchical capaths are always enabled */
1504 ret2
= _krb5_find_capath(context
, tgt
->crealm
, our_realm
,
1505 req_rlm
, TRUE
, &capath
, &num_capath
);
1508 _kdc_audit_addreason((kdc_request_t
)priv
,
1509 "No trusted path from client realm to ours");
1513 new_rlm
= num_capath
> 0 ? capath
[--num_capath
] : NULL
;
1515 kdc_log(context
, config
, 5, "krbtgt from %s via %s for "
1516 "realm %s not found, trying %s", tgt
->crealm
,
1517 our_realm
, req_rlm
, new_rlm
);
1520 ref_realm
= strdup(new_rlm
);
1521 if (ref_realm
== NULL
) {
1522 ret
= krb5_enomem(context
);
1526 krb5_free_principal(context
, priv
->server_princ
);
1527 priv
->server_princ
= NULL
;
1528 krb5_make_principal(context
, &priv
->server_princ
, r
,
1529 KRB5_TGS_NAME
, ref_realm
, NULL
);
1532 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1538 } else if (need_referral(context
, config
, &b
->kdc_options
, priv
->server_princ
, &realms
)) {
1539 if (strcmp(realms
[0], priv
->server_princ
->realm
) != 0) {
1540 kdc_log(context
, config
, 4,
1541 "Returning a referral to realm %s for "
1542 "server %s that was not found",
1544 krb5_free_principal(context
, priv
->server_princ
);
1545 priv
->server_princ
= NULL
;
1546 krb5_make_principal(context
, &priv
->server_princ
, r
, KRB5_TGS_NAME
,
1550 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1552 krb5_free_host_realm(context
, realms
);
1558 ref_realm
= strdup(realms
[0]);
1560 krb5_free_host_realm(context
, realms
);
1563 krb5_free_host_realm(context
, realms
);
1565 msg
= krb5_get_error_message(context
, ret
);
1566 kdc_log(context
, config
, 3,
1567 "Server not found in database: %s: %s", spn
, msg
);
1568 krb5_free_error_message(context
, msg
);
1569 if (ret
== HDB_ERR_NOENTRY
)
1570 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1571 _kdc_audit_addreason((kdc_request_t
)priv
,
1572 "Service principal unknown");
1577 * RFC 6806 notes that names MUST NOT be changed in the response to
1578 * a TGS request. Hence we ignore the setting of the canonicalize
1579 * KDC option. However, for legacy interoperability we do allow the
1580 * backend to override this by setting the force-canonicalize HDB
1581 * flag in the server entry.
1583 if (server
->flags
.force_canonicalize
)
1584 rsp
= server
->principal
;
1586 rsp
= priv
->server_princ
;
1589 * Now refetch the primary krbtgt, and get the current kvno (the
1590 * sign check may have been on an old kvno, and the server may
1591 * have been an incoming trust)
1594 ret
= krb5_make_principal(context
,
1595 &krbtgt_out_principal
,
1601 kdc_log(context
, config
, 4,
1602 "Failed to make krbtgt principal name object for "
1603 "authz-data signatures");
1606 ret
= krb5_unparse_name(context
, krbtgt_out_principal
, &krbtgt_out_n
);
1608 kdc_log(context
, config
, 4,
1609 "Failed to make krbtgt principal name object for "
1610 "authz-data signatures");
1614 ret
= _kdc_db_fetch(context
, config
, krbtgt_out_principal
,
1615 HDB_F_GET_KRBTGT
, NULL
, &krbtgt_outdb
, &krbtgt_out
);
1618 ret
= krb5_unparse_name(context
, priv
->krbtgt
->principal
, &ktpn
);
1619 kdc_log(context
, config
, 4,
1620 "No such principal %s (needed for authz-data signature keys) "
1621 "while processing TGS-REQ for service %s with krbtg %s",
1622 krbtgt_out_n
, spn
, (ret
== 0) ? ktpn
: "<unknown>");
1624 ret
= KRB5KRB_AP_ERR_NOT_US
;
1629 * Select enctype, return key and kvno.
1635 if(b
->kdc_options
.enc_tkt_in_skey
) {
1639 krb5uint32 second_kvno
= 0;
1640 krb5uint32
*kvno_ptr
= NULL
;
1643 hdb_entry
*user2user_client
= NULL
;
1644 krb5_boolean user2user_kdc_issued
= FALSE
;
1647 if(b
->additional_tickets
== NULL
||
1648 b
->additional_tickets
->len
== 0){
1649 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1650 kdc_log(context
, config
, 4,
1651 "No second ticket present in user-to-user request");
1652 _kdc_audit_addreason((kdc_request_t
)priv
,
1653 "No second ticket present in user-to-user request");
1656 t
= &b
->additional_tickets
->val
[0];
1657 if(!get_krbtgt_realm(&t
->sname
)){
1658 kdc_log(context
, config
, 4,
1659 "Additional ticket is not a ticket-granting ticket");
1660 _kdc_audit_addreason((kdc_request_t
)priv
,
1661 "Additional ticket is not a ticket-granting ticket");
1662 ret
= KRB5KDC_ERR_POLICY
;
1665 ret
= _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1669 ret
= krb5_unparse_name(context
, p
, &tpn
);
1672 if(t
->enc_part
.kvno
){
1673 second_kvno
= *t
->enc_part
.kvno
;
1674 kvno_ptr
= &second_kvno
;
1676 ret
= _kdc_db_fetch(context
, config
, p
,
1677 HDB_F_GET_KRBTGT
, kvno_ptr
,
1678 &user2user_krbtgtdb
, &user2user_krbtgt
);
1679 krb5_free_principal(context
, p
);
1681 if (ret
== HDB_ERR_NOENTRY
)
1682 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1683 _kdc_audit_addreason((kdc_request_t
)priv
,
1684 "User-to-user service principal (TGS) unknown");
1688 ret
= hdb_enctype2key(context
, user2user_krbtgt
, NULL
,
1689 t
->enc_part
.etype
, &uukey
);
1691 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1692 _kdc_audit_addreason((kdc_request_t
)priv
,
1693 "User-to-user enctype not supported");
1697 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1699 _kdc_audit_addreason((kdc_request_t
)priv
,
1700 "User-to-user TGT decrypt failure");
1705 ret
= _kdc_verify_flags(context
, config
, &adtkt
, tpn
);
1707 _kdc_audit_addreason((kdc_request_t
)priv
,
1708 "User-to-user TGT expired or invalid");
1714 /* Fetch the name from the TGT. */
1715 ret
= _krb5_principalname2krb5_principal(context
, &user2user_princ
,
1716 adtkt
.cname
, adtkt
.crealm
);
1720 ret
= krb5_unparse_name(context
, user2user_princ
, &user2user_name
);
1725 * Look up the name given in the TGT in the database. The user
1726 * claims to have a ticket-granting-ticket to our KDC, so we should
1727 * fail hard if we can't find the user - otherwise we can't do
1730 ret
= _kdc_db_fetch(context
, config
, user2user_princ
,
1731 HDB_F_GET_CLIENT
| flags
,
1732 NULL
, &user2user_db
, &user2user_client
);
1733 if (ret
== HDB_ERR_NOENTRY
)
1734 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1739 * The account is present in the database, now check the
1742 * We check this as a client (because the purpose of
1743 * user2user is that the server flag is not set, because
1744 * the long-term key is not strong, but this does mean
1745 * that a client with an expired password can't get accept
1746 * a user2user ticket.
1748 ret
= kdc_check_flags(priv
,
1753 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1758 * Also check that the account is the same one specified in the
1761 ret
= _kdc_check_client_matches_target_service(context
,
1768 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1772 /* Verify the PAC of the TGT. */
1773 ret
= _kdc_check_pac(context
, config
, user2user_princ
, NULL
,
1774 user2user_client
, user2user_krbtgt
, user2user_krbtgt
, user2user_krbtgt
,
1775 &uukey
->key
, &priv
->ticket_key
->key
, &adtkt
,
1776 &user2user_kdc_issued
, &user2user_pac
, NULL
, NULL
);
1777 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1779 const char *msg
= krb5_get_error_message(context
, ret
);
1780 kdc_log(context
, config
, 0,
1781 "Verify PAC failed for %s (%s) from %s with %s",
1782 spn
, user2user_name
, from
, msg
);
1783 krb5_free_error_message(context
, msg
);
1787 if ((config
->require_pac
&& !user2user_pac
)
1788 || (user2user_pac
&& !user2user_kdc_issued
))
1790 ret
= KRB5KDC_ERR_BADOPTION
;
1791 kdc_log(context
, config
, 0,
1792 "Ticket not signed with PAC; user-to-user failed (%s).",
1793 user2user_pac
? "Ticket unsigned" : "No PAC");
1798 for(i
= 0; i
< b
->etype
.len
; i
++)
1799 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1801 if(i
== b
->etype
.len
) {
1802 kdc_log(context
, config
, 4,
1803 "Addition ticket have not matching etypes");
1804 krb5_clear_error_message(context
);
1805 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1806 _kdc_audit_addreason((kdc_request_t
)priv
,
1807 "No matching enctypes for 2nd ticket");
1810 etype
= b
->etype
.val
[i
];
1815 ret
= _kdc_find_etype(priv
, krb5_principal_is_krbtgt(context
, priv
->server_princ
)
1817 b
->etype
.val
, b
->etype
.len
, &etype
, NULL
,
1820 kdc_log(context
, config
, 4,
1821 "Server (%s) has no support for etypes", spn
);
1822 _kdc_audit_addreason((kdc_request_t
)priv
,
1823 "Enctype not supported");
1826 ret
= _kdc_get_preferred_key(context
, config
, server
, spn
,
1829 kdc_log(context
, config
, 4,
1830 "Server (%s) has no supported etypes", spn
);
1831 _kdc_audit_addreason((kdc_request_t
)priv
,
1832 "Enctype not supported");
1836 kvno
= server
->kvno
;
1839 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1845 * Check that service is in the same realm as the krbtgt. If it's
1846 * not the same, it's someone that is using a uni-directional trust
1851 * The first realm is the realm of the service, the second is
1852 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1853 * encrypted to. The redirection via the krbtgt_out entry allows
1854 * the DB to possibly correct the case of the realm (Samba4 does
1855 * this) before the strcmp()
1857 if (strcmp(krb5_principal_get_realm(context
, server
->principal
),
1858 krb5_principal_get_realm(context
, krbtgt_out
->principal
)) != 0) {
1860 ret
= krb5_unparse_name(context
, krbtgt_out
->principal
, &ktpn
);
1861 kdc_log(context
, config
, 4,
1862 "Request with wrong krbtgt: %s",
1863 (ret
== 0) ? ktpn
: "<unknown>");
1866 ret
= KRB5KRB_AP_ERR_NOT_US
;
1867 _kdc_audit_addreason((kdc_request_t
)priv
, "Request with wrong TGT");
1871 ret
= _kdc_get_preferred_key(context
, config
, krbtgt_out
, krbtgt_out_n
,
1874 kdc_log(context
, config
, 4,
1875 "Failed to find key for krbtgt PAC signature");
1876 _kdc_audit_addreason((kdc_request_t
)priv
,
1877 "Failed to find key for krbtgt PAC signature");
1880 ret
= hdb_enctype2key(context
, krbtgt_out
, NULL
,
1881 tkey_sign
->key
.keytype
, &tkey_sign
);
1883 kdc_log(context
, config
, 4,
1884 "Failed to find key for krbtgt PAC signature");
1885 _kdc_audit_addreason((kdc_request_t
)priv
,
1886 "Failed to find key for krbtgt PAC signature");
1890 if (_kdc_synthetic_princ_used_p(context
, priv
->ticket
))
1891 flags
|= HDB_F_SYNTHETIC_OK
;
1893 ret
= _kdc_db_fetch_client(context
, config
, flags
, priv
->client_princ
,
1894 cpn
, our_realm
, &clientdb
, &client
);
1897 flags
&= ~HDB_F_SYNTHETIC_OK
;
1898 priv
->client
= client
;
1899 priv
->clientdb
= clientdb
;
1901 ret
= _kdc_check_pac(context
, config
, priv
->client_princ
, NULL
,
1902 priv
->client
, priv
->server
,
1903 priv
->krbtgt
, priv
->krbtgt
,
1904 &priv
->ticket_key
->key
, &priv
->ticket_key
->key
, tgt
,
1905 &kdc_issued
, &priv
->pac
, &priv
->canon_client_princ
,
1906 &priv
->pac_attributes
);
1908 const char *msg
= krb5_get_error_message(context
, ret
);
1909 _kdc_audit_addreason((kdc_request_t
)priv
, "PAC check failed");
1910 kdc_log(context
, config
, 4,
1911 "Verify PAC failed for %s (%s) from %s with %s",
1912 spn
, cpn
, from
, msg
);
1913 krb5_free_error_message(context
, msg
);
1922 * Services for User: protocol transition and constrained delegation
1925 ret
= _kdc_validate_services_for_user(priv
);
1933 ret
= kdc_check_flags(priv
, FALSE
, priv
->client
, priv
->server
);
1937 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1938 !krb5_principal_compare(context
,
1939 priv
->krbtgt
->principal
,
1940 priv
->server
->principal
)){
1941 _kdc_audit_addreason((kdc_request_t
)priv
, "Inconsistent request");
1942 kdc_log(context
, config
, 4, "Inconsistent request.");
1943 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1947 /* check for valid set of addresses */
1948 if (!_kdc_check_addresses(priv
, tgt
->caddr
, from_addr
)) {
1949 if (config
->check_ticket_addresses
) {
1950 ret
= KRB5KRB_AP_ERR_BADADDR
;
1951 _kdc_audit_setkv_bool((kdc_request_t
)priv
, "wrongaddr", TRUE
);
1952 kdc_log(context
, config
, 4, "Request from wrong address");
1953 _kdc_audit_addreason((kdc_request_t
)priv
, "Request from wrong address");
1955 } else if (config
->warn_ticket_addresses
) {
1956 _kdc_audit_setkv_bool((kdc_request_t
)priv
, "wrongaddr", TRUE
);
1960 /* check local and per-principal anonymous ticket issuance policy */
1961 if (is_anon_tgs_request_p(b
, tgt
)) {
1962 ret
= _kdc_check_anon_policy(priv
);
1968 * If this is an referral, add server referral data to the
1975 kdc_log(context
, config
, 3,
1976 "Adding server referral to %s", ref_realm
);
1978 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1982 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1983 NULL
, s
, &pa
.padata_value
);
1984 krb5_crypto_destroy(context
, crypto
);
1986 _kdc_audit_addreason((kdc_request_t
)priv
, "Referral build failed");
1987 kdc_log(context
, config
, 4,
1988 "Failed building server referral");
1991 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1993 ret
= add_METHOD_DATA(priv
->rep
.padata
, &pa
);
1994 krb5_data_free(&pa
.padata_value
);
1996 kdc_log(context
, config
, 4,
1997 "Add server referral METHOD-DATA failed");
2003 * Only add ticket signature if the requested server is not krbtgt, and
2004 * either the header server is krbtgt or, in the case of renewal/validation
2005 * if it was signed with PAC ticket signature and we verified it.
2006 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2007 * change one day (see issue #763) so make sure to check for it.
2011 !krb5_principal_is_krbtgt(context
, server
->principal
)) {
2013 /* Validate armor TGT before potentially including device claims */
2014 if (priv
->armor_ticket
) {
2015 ret
= _kdc_fast_check_armor_pac(priv
);
2020 add_ticket_sig
= TRUE
;
2024 * Active-Directory implementations use the high part of the kvno as the
2025 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2028 rodc_id
= krbtgt_out
->kvno
>> 16;
2034 ret
= tgs_make_reply(priv
,
2050 free(user2user_name
);
2052 _krb5_free_capath(context
, capath
);
2054 krb5_free_keyblock_contents(context
, &sessionkey
);
2056 _kdc_free_ent(context
, krbtgt_outdb
, krbtgt_out
);
2057 if(user2user_krbtgt
)
2058 _kdc_free_ent(context
, user2user_krbtgtdb
, user2user_krbtgt
);
2060 krb5_free_principal(context
, user2user_princ
);
2061 krb5_free_principal(context
, krbtgt_out_principal
);
2064 free_EncTicketPart(&adtkt
);
2066 krb5_pac_free(context
, user2user_pac
);
2076 _kdc_tgs_rep(astgs_request_t r
)
2078 krb5_kdc_configuration
*config
= r
->config
;
2079 KDC_REQ
*req
= &r
->req
;
2080 krb5_data
*data
= r
->reply
;
2081 const char *from
= r
->from
;
2082 struct sockaddr
*from_addr
= r
->addr
;
2083 int datagram_reply
= r
->datagram_reply
;
2084 AuthorizationData
*auth_data
= NULL
;
2085 krb5_error_code ret
;
2087 const PA_DATA
*tgs_req
, *pa
;
2088 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2090 time_t *csec
= NULL
;
2095 if(req
->padata
== NULL
){
2096 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2097 kdc_log(r
->context
, config
, 4,
2098 "TGS-REQ from %s without PA-DATA", from
);
2103 pa
= _kdc_find_padata(&r
->req
, &i
, KRB5_PADATA_FX_FAST_ARMOR
);
2105 kdc_log(r
->context
, r
->config
, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2106 ret
= KRB5KRB_ERR_GENERIC
;
2111 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2112 if(tgs_req
== NULL
){
2113 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2115 kdc_log(r
->context
, config
, 4,
2116 "TGS-REQ from %s without PA-TGS-REQ", from
);
2119 ret
= tgs_parse_request(r
, tgs_req
,
2124 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2125 /* kdc_log() is called in tgs_parse_request() */
2129 kdc_log(r
->context
, config
, 4,
2130 "Failed parsing TGS-REQ from %s", from
);
2134 ret
= _kdc_fast_strengthen_reply_key(r
);
2138 ALLOC(r
->rep
.padata
);
2139 if (r
->rep
.padata
== NULL
) {
2141 krb5_set_error_message(r
->context
, ret
, N_("malloc: out of memory", ""));
2145 ret
= tgs_build_reply(r
,
2150 kdc_log(r
->context
, config
, 4,
2151 "Failed building TGS-REP to %s", from
);
2156 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2157 krb5_data_free(data
);
2158 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2159 _kdc_set_const_e_text(r
, "Reply packet too large");
2164 _kdc_audit_request(r
);
2166 if(ret
&& ret
!= HDB_ERR_NOT_FOUND_HERE
&& data
->data
== NULL
){
2167 METHOD_DATA error_method
= { 0, NULL
};
2169 kdc_log(r
->context
, config
, 5, "tgs-req: sending error: %d to client", ret
);
2170 ret
= _kdc_fast_mk_error(r
,
2179 free_METHOD_DATA(&error_method
);
2184 free_TGS_REP(&r
->rep
);
2185 free_TransitedEncoding(&r
->et
.transited
);
2186 free(r
->et
.starttime
);
2187 free(r
->et
.renew_till
);
2188 if(r
->et
.authorization_data
) {
2189 free_AuthorizationData(r
->et
.authorization_data
);
2190 free(r
->et
.authorization_data
);
2192 free_LastReq(&r
->ek
.last_req
);
2193 if (r
->et
.key
.keyvalue
.data
) {
2194 memset_s(r
->et
.key
.keyvalue
.data
, 0, r
->et
.key
.keyvalue
.length
,
2195 r
->et
.key
.keyvalue
.length
);
2197 free_EncryptionKey(&r
->et
.key
);
2199 if (r
->canon_client_princ
) {
2200 krb5_free_principal(r
->context
, r
->canon_client_princ
);
2201 r
->canon_client_princ
= NULL
;
2203 if (r
->armor_crypto
) {
2204 krb5_crypto_destroy(r
->context
, r
->armor_crypto
);
2205 r
->armor_crypto
= NULL
;
2207 if (r
->armor_ticket
)
2208 krb5_free_ticket(r
->context
, r
->armor_ticket
);
2209 if (r
->armor_server
)
2210 _kdc_free_ent(r
->context
, r
->armor_serverdb
, r
->armor_server
);
2211 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
2212 krb5_free_keyblock_contents(r
->context
, &r
->strengthen_key
);
2215 krb5_free_ticket(r
->context
, r
->ticket
);
2217 _kdc_free_ent(r
->context
, r
->krbtgtdb
, r
->krbtgt
);
2220 _kdc_free_ent(r
->context
, r
->clientdb
, r
->client
);
2221 krb5_free_principal(r
->context
, r
->client_princ
);
2223 _kdc_free_ent(r
->context
, r
->serverdb
, r
->server
);
2224 krb5_free_principal(r
->context
, r
->server_princ
);
2225 _kdc_free_fast_state(&r
->fast
);
2226 krb5_pac_free(r
->context
, r
->pac
);
2229 free_AuthorizationData(auth_data
);