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(astgs_request_t r
,
80 const krb5_principal client_principal
,
81 const krb5_principal delegated_proxy_principal
,
85 hdb_entry
*ticket_server
,
86 const EncryptionKey
*server_check_key
,
87 const EncryptionKey
*krbtgt_check_key
,
89 krb5_boolean
*kdc_issued
,
91 krb5_principal
*pac_canon_name
,
92 uint64_t *pac_attributes
)
94 krb5_context context
= r
->context
;
95 krb5_kdc_configuration
*config
= r
->config
;
98 krb5_boolean signedticket
;
103 *pac_canon_name
= NULL
;
105 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
107 ret
= _krb5_kdc_pac_ticket_parse(context
, tkt
, &signedticket
, &pac
);
112 if (config
->require_pac
)
113 ret
= KRB5KDC_ERR_TGT_REVOKED
;
117 /* Verify the server signature. */
118 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
, client_principal
,
119 server_check_key
, NULL
);
121 krb5_pac_free(context
, pac
);
125 /* Verify the KDC signatures. */
126 ret
= _kdc_pac_verify(r
,
127 client_principal
, delegated_proxy_principal
,
128 client
, server
, krbtgt
, &pac
);
130 if (pac_canon_name
) {
131 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
132 if (ret
&& ret
!= ENOENT
) {
133 krb5_pac_free(context
, pac
);
137 if (pac_attributes
&&
138 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
139 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
140 } else if (ret
== KRB5_PLUGIN_NO_HANDLE
) {
142 * We can't verify the KDC signatures if the ticket was issued by
143 * another realm's KDC.
145 if (krb5_realm_compare(context
, server
->principal
,
146 ticket_server
->principal
)) {
147 ret
= krb5_pac_verify(context
, pac
, 0, NULL
, NULL
,
150 krb5_pac_free(context
, pac
);
155 if (pac_canon_name
) {
156 ret
= _krb5_pac_get_canon_principal(context
, pac
, pac_canon_name
);
157 if (ret
&& ret
!= ENOENT
) {
158 krb5_pac_free(context
, pac
);
161 if (pac_attributes
&&
162 _krb5_pac_get_attributes_info(context
, pac
, pac_attributes
) != 0)
163 *pac_attributes
= KRB5_PAC_WAS_GIVEN_IMPLICITLY
;
166 /* Discard the PAC if the plugin didn't handle it */
167 krb5_pac_free(context
, pac
);
168 ret
= krb5_pac_init(context
, &pac
);
172 krb5_pac_free(context
, pac
);
176 *kdc_issued
= signedticket
||
177 krb5_principal_is_krbtgt(context
,
178 ticket_server
->principal
);
185 is_anon_tgs_request_p(const KDC_REQ_BODY
*b
,
186 const EncTicketPart
*tgt
)
188 KDCOptions f
= b
->kdc_options
;
191 * Versions of Heimdal from 1.0 to 7.6, inclusive, send both the
192 * request-anonymous and cname-in-addl-tkt flags for constrained
193 * delegation requests. A true anonymous TGS request will only
194 * have the request-anonymous flag set. (A corollary of this is
195 * that it is not possible to support anonymous constrained
196 * delegation requests, although they would be of limited utility.)
198 return tgt
->flags
.anonymous
||
199 (f
.request_anonymous
&& !f
.cname_in_addl_tkt
&& !b
->additional_tickets
);
206 static krb5_error_code
207 check_tgs_flags(astgs_request_t r
, KDC_REQ_BODY
*b
,
208 krb5_const_principal tgt_name
,
209 const EncTicketPart
*tgt
, EncTicketPart
*et
)
211 KDCOptions f
= b
->kdc_options
;
214 if (!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
) {
215 kdc_audit_addreason((kdc_request_t
)r
,
216 "Bad request to validate ticket");
217 return KRB5KDC_ERR_BADOPTION
;
219 if(*tgt
->starttime
> kdc_time
){
220 kdc_audit_addreason((kdc_request_t
)r
,
221 "Early request to validate ticket");
222 return KRB5KRB_AP_ERR_TKT_NYV
;
225 et
->flags
.invalid
= 0;
226 } else if (tgt
->flags
.invalid
) {
227 kdc_audit_addreason((kdc_request_t
)r
,
228 "Ticket-granting ticket has INVALID flag set");
229 return KRB5KRB_AP_ERR_TKT_INVALID
;
233 if (!tgt
->flags
.forwardable
) {
234 kdc_audit_addreason((kdc_request_t
)r
,
235 "Bad request for forwardable ticket");
236 return KRB5KDC_ERR_BADOPTION
;
238 et
->flags
.forwardable
= 1;
241 if (!tgt
->flags
.forwardable
) {
242 kdc_audit_addreason((kdc_request_t
)r
,
243 "Request to forward non-forwardable ticket");
244 return KRB5KDC_ERR_BADOPTION
;
246 et
->flags
.forwarded
= 1;
247 et
->caddr
= b
->addresses
;
249 if(tgt
->flags
.forwarded
)
250 et
->flags
.forwarded
= 1;
253 if (!tgt
->flags
.proxiable
) {
254 kdc_audit_addreason((kdc_request_t
)r
,
255 "Bad request for proxiable ticket");
256 return KRB5KDC_ERR_BADOPTION
;
258 et
->flags
.proxiable
= 1;
261 if (!tgt
->flags
.proxiable
) {
262 kdc_audit_addreason((kdc_request_t
)r
,
263 "Request to proxy non-proxiable ticket");
264 return KRB5KDC_ERR_BADOPTION
;
267 et
->caddr
= b
->addresses
;
272 if(f
.allow_postdate
){
273 if (!tgt
->flags
.may_postdate
) {
274 kdc_audit_addreason((kdc_request_t
)r
,
275 "Bad request for post-datable ticket");
276 return KRB5KDC_ERR_BADOPTION
;
278 et
->flags
.may_postdate
= 1;
281 if (!tgt
->flags
.may_postdate
) {
282 kdc_audit_addreason((kdc_request_t
)r
,
283 "Bad request for postdated ticket");
284 return KRB5KDC_ERR_BADOPTION
;
287 *et
->starttime
= *b
->from
;
288 et
->flags
.postdated
= 1;
289 et
->flags
.invalid
= 1;
290 } else if (b
->from
&& *b
->from
> kdc_time
+ r
->context
->max_skew
) {
291 kdc_audit_addreason((kdc_request_t
)r
,
292 "Ticket cannot be postdated");
293 return KRB5KDC_ERR_CANNOT_POSTDATE
;
297 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
298 kdc_audit_addreason((kdc_request_t
)r
,
299 "Bad request for renewable ticket");
300 return KRB5KDC_ERR_BADOPTION
;
302 et
->flags
.renewable
= 1;
303 ALLOC(et
->renew_till
);
304 _kdc_fix_time(&b
->rtime
);
305 *et
->renew_till
= *b
->rtime
;
309 if (!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
) {
310 kdc_audit_addreason((kdc_request_t
)r
,
311 "Request to renew non-renewable ticket");
312 return KRB5KDC_ERR_BADOPTION
;
314 old_life
= tgt
->endtime
;
316 old_life
-= *tgt
->starttime
;
318 old_life
-= tgt
->authtime
;
319 et
->endtime
= *et
->starttime
+ old_life
;
320 if (et
->renew_till
!= NULL
)
321 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
325 * RFC 8062 section 3 defines an anonymous ticket as one containing
326 * the anonymous principal and the anonymous ticket flag.
328 if (tgt
->flags
.anonymous
&&
329 !_kdc_is_anonymous(r
->context
, tgt_name
)) {
330 kdc_audit_addreason((kdc_request_t
)r
,
331 "Anonymous ticket flag set without "
332 "anonymous principal");
333 return KRB5KDC_ERR_BADOPTION
;
337 * RFC 8062 section 4.2 states that if the TGT is anonymous, the
338 * anonymous KDC option SHOULD be set, but it is not required.
339 * Treat an anonymous TGT as if the anonymous flag was set.
341 if (is_anon_tgs_request_p(b
, tgt
))
342 et
->flags
.anonymous
= 1;
348 * Determine if s4u2self is allowed from this client to this server
352 * Check that the client (user2user TGT, enc-tkt-in-skey) hosts the
353 * service given by the client.
355 * For example, regardless of the principal being impersonated, if the
356 * 'client' and 'server' (target) are the same, or server is an SPN
357 * alias of client, then it's safe.
361 _kdc_check_client_matches_target_service(krb5_context context
,
362 krb5_kdc_configuration
*config
,
365 hdb_entry
*target_server
,
366 krb5_const_principal target_server_principal
)
371 * Always allow the plugin to check, this might be faster, allow a
372 * policy or audit check and can look into the DB records
375 if (clientdb
->hdb_check_client_matches_target_service
) {
376 ret
= clientdb
->hdb_check_client_matches_target_service(context
,
382 } else if (krb5_principal_compare(context
,
384 target_server_principal
) == TRUE
) {
385 /* if client does a s4u2self to itself, and there is no plugin, that is ok */
388 ret
= KRB5KDC_ERR_BADOPTION
;
398 _kdc_verify_flags(krb5_context context
,
399 krb5_kdc_configuration
*config
,
400 const EncTicketPart
*et
,
403 if(et
->endtime
< kdc_time
){
404 kdc_log(context
, config
, 4, "Ticket expired (%s)", pstr
);
405 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
407 if(et
->flags
.invalid
){
408 kdc_log(context
, config
, 4, "Ticket not valid (%s)", pstr
);
409 return KRB5KRB_AP_ERR_TKT_NYV
;
418 static krb5_error_code
419 fix_transited_encoding(krb5_context context
,
420 krb5_kdc_configuration
*config
,
421 krb5_boolean check_policy
,
422 const TransitedEncoding
*tr
,
424 const char *client_realm
,
425 const char *server_realm
,
426 const char *tgt_realm
)
428 krb5_error_code ret
= 0;
429 char **realms
, **tmp
;
430 unsigned int num_realms
;
433 switch (tr
->tr_type
) {
434 case domain_X500_Compress
:
438 * Allow empty content of type 0 because that is was Microsoft
439 * generates in their TGT.
441 if (tr
->contents
.length
== 0)
443 kdc_log(context
, config
, 4,
444 "Transited type 0 with non empty content");
445 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
447 kdc_log(context
, config
, 4,
448 "Unknown transited type: %u", tr
->tr_type
);
449 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
452 ret
= krb5_domain_x500_decode(context
,
459 krb5_warn(context
, ret
,
460 "Decoding transited encoding");
465 * If the realm of the presented tgt is neither the client nor the server
466 * realm, it is a transit realm and must be added to transited set.
468 if (strcmp(client_realm
, tgt_realm
) != 0 &&
469 strcmp(server_realm
, tgt_realm
) != 0) {
470 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
474 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
480 realms
[num_realms
] = strdup(tgt_realm
);
481 if(realms
[num_realms
] == NULL
){
487 if(num_realms
== 0) {
488 if (strcmp(client_realm
, server_realm
) != 0)
489 kdc_log(context
, config
, 4,
490 "cross-realm %s -> %s", client_realm
, server_realm
);
494 for(i
= 0; i
< num_realms
; i
++)
495 l
+= strlen(realms
[i
]) + 2;
499 for(i
= 0; i
< num_realms
; i
++) {
501 strlcat(rs
, ", ", l
);
502 strlcat(rs
, realms
[i
], l
);
504 kdc_log(context
, config
, 4,
505 "cross-realm %s -> %s via [%s]",
506 client_realm
, server_realm
, rs
);
511 ret
= krb5_check_transited(context
, client_realm
,
513 realms
, num_realms
, NULL
);
515 krb5_warn(context
, ret
, "cross-realm %s -> %s",
516 client_realm
, server_realm
);
519 et
->flags
.transited_policy_checked
= 1;
521 et
->transited
.tr_type
= domain_X500_Compress
;
522 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
524 krb5_warn(context
, ret
, "Encoding transited encoding");
526 for(i
= 0; i
< num_realms
; i
++)
533 static krb5_error_code
534 tgs_make_reply(astgs_request_t r
,
535 const EncTicketPart
*tgt
,
536 const EncryptionKey
*serverkey
,
537 const EncryptionKey
*krbtgtkey
,
538 const krb5_keyblock
*sessionkey
,
540 AuthorizationData
*auth_data
,
541 const char *tgt_realm
,
543 krb5_boolean add_ticket_sig
)
545 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
546 krb5_data
*reply
= r
->reply
;
547 KDC_REP
*rep
= &r
->rep
;
548 EncTicketPart
*et
= &r
->et
;
549 EncKDCRepPart
*ek
= &r
->ek
;
550 KDCOptions f
= b
->kdc_options
;
554 heim_assert(r
->client_princ
!= NULL
, "invalid client name passed to tgs_make_reply");
557 rep
->msg_type
= krb_tgs_rep
;
559 et
->authtime
= tgt
->authtime
;
560 _kdc_fix_time(&b
->till
);
561 et
->endtime
= min(tgt
->endtime
, *b
->till
);
562 ALLOC(et
->starttime
);
563 *et
->starttime
= kdc_time
;
565 ret
= check_tgs_flags(r
, b
, r
->client_princ
, tgt
, et
);
569 /* We should check the transited encoding if:
570 1) the request doesn't ask not to be checked
571 2) globally enforcing a check
572 3) principal requires checking
573 4) we allow non-check per-principal, but principal isn't marked as allowing this
574 5) we don't globally allow this
577 #define GLOBAL_FORCE_TRANSITED_CHECK \
578 (r->config->trpolicy == TRPOLICY_ALWAYS_CHECK)
579 #define GLOBAL_ALLOW_PER_PRINCIPAL \
580 (r->config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
581 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
582 (r->config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
584 /* these will consult the database in future release */
585 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
586 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
588 ret
= fix_transited_encoding(r
->context
, r
->config
,
589 !f
.disable_transited_check
||
590 GLOBAL_FORCE_TRANSITED_CHECK
||
591 PRINCIPAL_FORCE_TRANSITED_CHECK(r
->server
) ||
592 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
593 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(r
->server
)) ||
594 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
596 krb5_principal_get_realm(r
->context
, r
->client_princ
),
597 krb5_principal_get_realm(r
->context
, r
->server
->principal
),
602 * RFC 6806 notes that names MUST NOT be changed in the response to a
603 * TGS request. Hence we ignore the setting of the canonicalize KDC
604 * option. However, for legacy interoperability we do allow the backend
605 * to override this by setting the force-canonicalize HDB flag in the
608 krb5_const_principal rsp
;
610 if (r
->server
->flags
.force_canonicalize
)
611 rsp
= r
->server
->principal
;
613 rsp
= r
->server_princ
;
615 ret
= copy_Realm(&rsp
->realm
, &rep
->ticket
.realm
);
617 ret
= _krb5_principal2principalname(&rep
->ticket
.sname
, rsp
);
621 ret
= copy_Realm(&r
->client_princ
->realm
, &rep
->crealm
);
626 * RFC 8062 states "if the ticket in the TGS request is an anonymous
627 * one, the client and client realm are copied from that ticket". So
628 * whilst the TGT flag check below is superfluous, it is included in
629 * order to follow the specification to its letter.
631 if (et
->flags
.anonymous
&& !tgt
->flags
.anonymous
)
632 _kdc_make_anonymous_principalname(&rep
->cname
);
634 ret
= copy_PrincipalName(&r
->client_princ
->name
, &rep
->cname
);
637 rep
->ticket
.tkt_vno
= 5;
639 ek
->caddr
= et
->caddr
;
643 life
= et
->endtime
- *et
->starttime
;
644 if(r
->client
&& r
->client
->max_life
)
645 life
= min(life
, *r
->client
->max_life
);
646 if(r
->server
->max_life
)
647 life
= min(life
, *r
->server
->max_life
);
648 et
->endtime
= *et
->starttime
+ life
;
650 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
651 et
->renew_till
== NULL
&& et
->endtime
< *b
->till
&&
652 tgt
->renew_till
!= NULL
)
654 et
->flags
.renewable
= 1;
655 ALLOC(et
->renew_till
);
656 *et
->renew_till
= *b
->till
;
660 renew
= *et
->renew_till
- *et
->starttime
;
661 if(r
->client
&& r
->client
->max_renew
)
662 renew
= min(renew
, *r
->client
->max_renew
);
663 if(r
->server
->max_renew
)
664 renew
= min(renew
, *r
->server
->max_renew
);
665 *et
->renew_till
= *et
->starttime
+ renew
;
669 *et
->renew_till
= min(*et
->renew_till
, *tgt
->renew_till
);
670 *et
->starttime
= min(*et
->starttime
, *et
->renew_till
);
671 et
->endtime
= min(et
->endtime
, *et
->renew_till
);
674 *et
->starttime
= min(*et
->starttime
, et
->endtime
);
676 if(*et
->starttime
== et
->endtime
){
677 ret
= KRB5KDC_ERR_NEVER_VALID
;
680 if(et
->renew_till
&& et
->endtime
== *et
->renew_till
){
681 free(et
->renew_till
);
682 et
->renew_till
= NULL
;
683 et
->flags
.renewable
= 0;
686 et
->flags
.pre_authent
= tgt
->flags
.pre_authent
;
687 et
->flags
.hw_authent
= tgt
->flags
.hw_authent
;
688 et
->flags
.ok_as_delegate
= r
->server
->flags
.ok_as_delegate
;
690 /* See MS-KILE 3.3.5.1 */
691 if (!r
->server
->flags
.forwardable
)
692 et
->flags
.forwardable
= 0;
693 if (!r
->server
->flags
.proxiable
)
694 et
->flags
.proxiable
= 0;
699 /* XXX check authdata */
701 if (et
->authorization_data
== NULL
) {
702 et
->authorization_data
= calloc(1, sizeof(*et
->authorization_data
));
703 if (et
->authorization_data
== NULL
) {
705 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
709 for(i
= 0; i
< auth_data
->len
; i
++) {
710 ret
= add_AuthorizationData(et
->authorization_data
, &auth_data
->val
[i
]);
712 krb5_set_error_message(r
->context
, ret
, "malloc: out of memory");
718 ret
= krb5_copy_keyblock_contents(r
->context
, sessionkey
, &et
->key
);
721 et
->crealm
= rep
->crealm
;
722 et
->cname
= rep
->cname
;
725 /* MIT must have at least one last_req */
726 ek
->last_req
.val
= calloc(1, sizeof(*ek
->last_req
.val
));
727 if (ek
->last_req
.val
== NULL
) {
731 ek
->last_req
.len
= 1; /* set after alloc to avoid null deref on cleanup */
732 ek
->nonce
= b
->nonce
;
733 ek
->flags
= et
->flags
;
734 ek
->authtime
= et
->authtime
;
735 ek
->starttime
= et
->starttime
;
736 ek
->endtime
= et
->endtime
;
737 ek
->renew_till
= et
->renew_till
;
738 ek
->srealm
= rep
->ticket
.realm
;
739 ek
->sname
= rep
->ticket
.sname
;
741 _kdc_log_timestamp(r
, "TGS-REQ", et
->authtime
, et
->starttime
,
742 et
->endtime
, et
->renew_till
);
744 if (krb5_enctype_valid(r
->context
, serverkey
->keytype
) != 0
745 && _kdc_is_weak_exception(r
->server
->principal
, serverkey
->keytype
))
747 krb5_enctype_enable(r
->context
, serverkey
->keytype
);
751 if (r
->canon_client_princ
) {
754 (void) krb5_unparse_name(r
->context
, r
->canon_client_princ
, &cpn
);
755 kdc_audit_addkv((kdc_request_t
)r
, 0, "canon_client_name", "%s",
756 cpn
? cpn
: "<unknown>");
761 * For anonymous tickets, we should filter out positive authorization data
762 * that could reveal the client's identity, and return a policy error for
763 * restrictive authorization data. Policy for unknown authorization types
764 * is implementation dependent.
766 if (r
->pac
&& !et
->flags
.anonymous
) {
767 kdc_audit_setkv_number((kdc_request_t
)r
, "pac_attributes",
771 * PACs are included when issuing TGTs, if there is no PAC_ATTRIBUTES
772 * buffer (legacy behavior) or if the attributes buffer indicates the
773 * AS client requested one.
775 if (_kdc_include_pac_p(r
)) {
776 krb5_boolean is_tgs
=
777 krb5_principal_is_krbtgt(r
->context
, r
->server
->principal
);
779 ret
= _krb5_kdc_pac_sign_ticket(r
->context
, r
->pac
, r
->client_princ
, serverkey
,
780 krbtgtkey
, rodc_id
, NULL
, r
->canon_client_princ
,
782 is_tgs
? &r
->pac_attributes
: NULL
);
788 ret
= _kdc_finalize_reply(r
);
792 /* It is somewhat unclear where the etype in the following
793 encryption should come from. What we have is a session
794 key in the passed tgt, and a list of preferred etypes
795 *for the new ticket*. Should we pick the best possible
796 etype, given the keytype in the tgt, or should we look
797 at the etype list here as well? What if the tgt
798 session key is DES3 and we want a ticket with a (say)
799 CAST session key. Should the DES3 etype be added to the
800 etype list, even if we don't want a session key with
802 ret
= _kdc_encode_reply(r
->context
, r
->config
, r
, b
->nonce
,
803 serverkey
->keytype
, kvno
,
804 serverkey
, 0, r
->rk_is_subkey
, reply
);
806 krb5_enctype_disable(r
->context
, serverkey
->keytype
);
808 _log_astgs_req(r
, serverkey
->keytype
);
814 static krb5_error_code
815 tgs_check_authenticator(krb5_context context
,
816 krb5_kdc_configuration
*config
,
817 krb5_auth_context ac
,
821 krb5_authenticator auth
;
825 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
827 kdc_log(context
, config
, 2,
828 "Out of memory checking PA-TGS Authenticator");
831 if(auth
->cksum
== NULL
){
832 kdc_log(context
, config
, 4, "No authenticator in request");
833 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
837 if (!krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
838 kdc_log(context
, config
, 4, "Bad checksum type in authenticator: %d",
839 auth
->cksum
->cksumtype
);
840 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
844 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
846 const char *msg
= krb5_get_error_message(context
, ret
);
847 kdc_log(context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
848 krb5_free_error_message(context
, msg
);
853 * RFC4120 says the checksum must be collision-proof, but it does
854 * not require it to be keyed (as the authenticator is encrypted).
856 _krb5_crypto_set_flags(context
, crypto
, KRB5_CRYPTO_FLAG_ALLOW_UNKEYED_CHECKSUM
);
857 ret
= _kdc_verify_checksum(context
,
859 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
862 krb5_crypto_destroy(context
, crypto
);
864 const char *msg
= krb5_get_error_message(context
, ret
);
865 kdc_log(context
, config
, 4,
866 "Failed to verify authenticator checksum: %s", msg
);
867 krb5_free_error_message(context
, msg
);
870 free_Authenticator(auth
);
876 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
877 const KDCOptions
* const options
, krb5_principal server
,
882 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
885 if (server
->name
.name_string
.len
== 1)
886 name
= server
->name
.name_string
.val
[0];
887 else if (server
->name
.name_string
.len
> 1)
888 name
= server
->name
.name_string
.val
[1];
892 kdc_log(context
, config
, 5, "Searching referral for %s", name
);
894 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
897 static krb5_error_code
898 validate_fast_ad(astgs_request_t r
, krb5_authdata
*auth_data
)
903 krb5_data_zero(&data
);
905 if (!r
->config
->enable_fast
)
908 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
909 KRB5_AUTHDATA_FX_FAST_USED
, &data
);
911 r
->fast_asserted
= 1;
912 krb5_data_free(&data
);
915 ret
= _krb5_get_ad(r
->context
, auth_data
, NULL
,
916 KRB5_AUTHDATA_FX_FAST_ARMOR
, &data
);
918 kdc_log(r
->context
, r
->config
, 2,
919 "Invalid ticket usage: TGS-REQ contains AD-fx-fast-armor");
920 krb5_data_free(&data
);
921 return KRB5KRB_AP_ERR_BAD_INTEGRITY
;
927 static krb5_error_code
928 tgs_parse_request(astgs_request_t r
,
929 const PA_DATA
*tgs_req
,
930 krb5_enctype
*krbtgt_etype
,
932 const struct sockaddr
*from_addr
,
935 AuthorizationData
**auth_data
)
937 krb5_kdc_configuration
*config
= r
->config
;
938 KDC_REQ_BODY
*b
= &r
->req
.req_body
;
939 static char failed
[] = "<unparse_name failed>";
942 krb5_principal princ
;
943 krb5_auth_context ac
= NULL
;
944 krb5_flags ap_req_options
;
945 krb5_flags verify_ap_req_flags
= 0;
947 krb5uint32 krbtgt_kvno
; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */
948 krb5uint32 krbtgt_kvno_try
;
949 int kvno_search_tries
= 4; /* number of kvnos to try when tkt_vno == 0 */
950 const Keys
*krbtgt_keys
;/* keyset for TGT tkt_vno */
952 krb5_keyblock
*subkey
= NULL
;
959 memset(&ap_req
, 0, sizeof(ap_req
));
960 ret
= krb5_decode_ap_req(r
->context
, &tgs_req
->padata_value
, &ap_req
);
962 const char *msg
= krb5_get_error_message(r
->context
, ret
);
963 kdc_log(r
->context
, config
, 4, "Failed to decode AP-REQ: %s", msg
);
964 krb5_free_error_message(r
->context
, msg
);
968 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
969 /* XXX check for ticket.sname == req.sname */
970 kdc_log(r
->context
, config
, 4, "PA-DATA is not a ticket-granting ticket");
971 ret
= KRB5KDC_ERR_POLICY
; /* ? */
975 _krb5_principalname2krb5_principal(r
->context
,
978 ap_req
.ticket
.realm
);
980 krbtgt_kvno
= ap_req
.ticket
.enc_part
.kvno
? *ap_req
.ticket
.enc_part
.kvno
: 0;
981 ret
= _kdc_db_fetch(r
->context
, config
, princ
, HDB_F_GET_KRBTGT
,
982 &krbtgt_kvno
, &r
->krbtgtdb
, &r
->krbtgt
);
984 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
985 /* XXX Factor out this unparsing of the same princ all over */
987 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
990 krb5_free_principal(r
->context
, princ
);
991 kdc_log(r
->context
, config
, 5,
992 "Ticket-granting ticket account %s does not have secrets at "
993 "this KDC, need to proxy", p
);
996 ret
= HDB_ERR_NOT_FOUND_HERE
;
998 } else if (ret
== HDB_ERR_KVNO_NOT_FOUND
) {
1000 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1003 krb5_free_principal(r
->context
, princ
);
1004 kdc_log(r
->context
, config
, 5,
1005 "Ticket-granting ticket account %s does not have keys for "
1006 "kvno %d at this KDC", p
, krbtgt_kvno
);
1009 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1011 } else if (ret
== HDB_ERR_NO_MKEY
) {
1013 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1016 krb5_free_principal(r
->context
, princ
);
1017 kdc_log(r
->context
, config
, 5,
1018 "Missing master key for decrypting keys for ticket-granting "
1019 "ticket account %s with kvno %d at this KDC", p
, krbtgt_kvno
);
1022 ret
= HDB_ERR_KVNO_NOT_FOUND
;
1025 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1027 ret
= krb5_unparse_name(r
->context
, princ
, &p
);
1030 kdc_log(r
->context
, config
, 4,
1031 "Ticket-granting ticket %s not found in database: %s", p
, msg
);
1032 krb5_free_principal(r
->context
, princ
);
1033 krb5_free_error_message(r
->context
, msg
);
1036 ret
= KRB5KRB_AP_ERR_NOT_US
;
1040 krbtgt_kvno_try
= krbtgt_kvno
? krbtgt_kvno
: r
->krbtgt
->kvno
;
1041 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1044 krbtgt_keys
= hdb_kvno2keys(r
->context
, r
->krbtgt
, krbtgt_kvno_try
);
1045 ret
= hdb_enctype2key(r
->context
, r
->krbtgt
, krbtgt_keys
,
1046 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1047 if (ret
&& krbtgt_kvno
== 0 && kvno_search_tries
> 0) {
1048 kvno_search_tries
--;
1052 char *str
= NULL
, *p
= NULL
;
1054 /* We should implement the MIT `trace_format()' concept */
1055 (void) krb5_enctype_to_string(r
->context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1056 (void) krb5_unparse_name(r
->context
, princ
, &p
);
1057 kdc_log(r
->context
, config
, 4,
1058 "No server key with enctype %s found for %s",
1059 str
? str
: "<unknown enctype>",
1060 p
? p
: "<unparse_name failed>");
1063 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1067 if (b
->kdc_options
.validate
)
1068 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1070 if (r
->config
->warn_ticket_addresses
)
1071 verify_ap_req_flags
|= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS
;
1073 ret
= krb5_verify_ap_req2(r
->context
,
1078 verify_ap_req_flags
,
1081 KRB5_KU_TGS_REQ_AUTH
);
1082 if (r
->ticket
&& r
->ticket
->ticket
.caddr
)
1083 kdc_audit_addaddrs((kdc_request_t
)r
, r
->ticket
->ticket
.caddr
, "tixaddrs");
1084 if (r
->config
->warn_ticket_addresses
&& ret
== KRB5KRB_AP_ERR_BADADDR
&&
1085 r
->ticket
!= NULL
) {
1086 kdc_audit_setkv_bool((kdc_request_t
)r
, "wrongaddr", TRUE
);
1089 if (ret
== KRB5KRB_AP_ERR_BAD_INTEGRITY
&& kvno_search_tries
> 0) {
1090 kvno_search_tries
--;
1095 krb5_free_principal(r
->context
, princ
);
1097 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1098 kdc_log(r
->context
, config
, 4, "Failed to verify AP-REQ: %s", msg
);
1099 krb5_free_error_message(r
->context
, msg
);
1103 r
->ticket_key
= tkey
;
1106 krb5_authenticator auth
;
1108 ret
= krb5_auth_con_getauthenticator(r
->context
, ac
, &auth
);
1110 *csec
= malloc(sizeof(**csec
));
1111 if (*csec
== NULL
) {
1112 krb5_free_authenticator(r
->context
, &auth
);
1113 kdc_log(r
->context
, config
, 4, "malloc failed");
1116 **csec
= auth
->ctime
;
1117 *cusec
= malloc(sizeof(**cusec
));
1118 if (*cusec
== NULL
) {
1119 krb5_free_authenticator(r
->context
, &auth
);
1120 kdc_log(r
->context
, config
, 4, "malloc failed");
1123 **cusec
= auth
->cusec
;
1125 ret
= validate_fast_ad(r
, auth
->authorization_data
);
1126 krb5_free_authenticator(r
->context
, &auth
);
1132 ret
= tgs_check_authenticator(r
->context
, config
, ac
, b
, &r
->ticket
->ticket
.key
);
1134 krb5_auth_con_free(r
->context
, ac
);
1138 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1139 r
->rk_is_subkey
= 1;
1141 ret
= krb5_auth_con_getremotesubkey(r
->context
, ac
, &subkey
);
1143 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1144 krb5_auth_con_free(r
->context
, ac
);
1145 kdc_log(r
->context
, config
, 4, "Failed to get remote subkey: %s", msg
);
1146 krb5_free_error_message(r
->context
, msg
);
1150 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1151 r
->rk_is_subkey
= 0;
1153 ret
= krb5_auth_con_getkey(r
->context
, ac
, &subkey
);
1155 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1156 krb5_auth_con_free(r
->context
, ac
);
1157 kdc_log(r
->context
, config
, 4, "Failed to get session key: %s", msg
);
1158 krb5_free_error_message(r
->context
, msg
);
1163 krb5_auth_con_free(r
->context
, ac
);
1164 kdc_log(r
->context
, config
, 4,
1165 "Failed to get key for enc-authorization-data");
1166 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1170 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
1171 ret
= krb5_copy_keyblock_contents(r
->context
, subkey
, &r
->reply_key
);
1172 krb5_free_keyblock(r
->context
, subkey
);
1176 if (b
->enc_authorization_data
) {
1179 ret
= krb5_crypto_init(r
->context
, &r
->reply_key
, 0, &crypto
);
1181 const char *msg
= krb5_get_error_message(r
->context
, ret
);
1182 krb5_auth_con_free(r
->context
, ac
);
1183 kdc_log(r
->context
, config
, 4, "krb5_crypto_init failed: %s", msg
);
1184 krb5_free_error_message(r
->context
, msg
);
1187 ret
= krb5_decrypt_EncryptedData (r
->context
,
1190 b
->enc_authorization_data
,
1192 krb5_crypto_destroy(r
->context
, crypto
);
1194 krb5_auth_con_free(r
->context
, ac
);
1195 kdc_log(r
->context
, config
, 4,
1196 "Failed to decrypt enc-authorization-data");
1197 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1201 if (*auth_data
== NULL
) {
1202 krb5_auth_con_free(r
->context
, ac
);
1203 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1206 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1208 krb5_auth_con_free(r
->context
, ac
);
1211 kdc_log(r
->context
, config
, 4, "Failed to decode authorization data");
1212 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1217 ret
= validate_fast_ad(r
, r
->ticket
->ticket
.authorization_data
);
1223 * Check for FAST request
1226 ret
= _kdc_fast_unwrap_request(r
, r
->ticket
, ac
);
1230 krb5_auth_con_free(r
->context
, ac
);
1233 free_AP_REQ(&ap_req
);
1238 static krb5_error_code
1239 build_server_referral(krb5_context context
,
1240 krb5_kdc_configuration
*config
,
1241 krb5_crypto session
,
1242 krb5_const_realm referred_realm
,
1243 const PrincipalName
*true_principal_name
,
1244 const PrincipalName
*requested_principal
,
1247 PA_ServerReferralData ref
;
1248 krb5_error_code ret
;
1253 memset(&ref
, 0, sizeof(ref
));
1255 if (referred_realm
) {
1256 ALLOC(ref
.referred_realm
);
1257 if (ref
.referred_realm
== NULL
)
1259 *ref
.referred_realm
= strdup(referred_realm
);
1260 if (*ref
.referred_realm
== NULL
)
1263 if (true_principal_name
) {
1264 ALLOC(ref
.true_principal_name
);
1265 if (ref
.true_principal_name
== NULL
)
1267 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1271 if (requested_principal
) {
1272 ALLOC(ref
.requested_principal_name
);
1273 if (ref
.requested_principal_name
== NULL
)
1275 ret
= copy_PrincipalName(requested_principal
,
1276 ref
.requested_principal_name
);
1281 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1282 data
.data
, data
.length
,
1284 free_PA_ServerReferralData(&ref
);
1287 if (data
.length
!= size
)
1288 krb5_abortx(context
, "internal asn.1 encoder error");
1290 ret
= krb5_encrypt_EncryptedData(context
, session
,
1291 KRB5_KU_PA_SERVER_REFERRAL
,
1292 data
.data
, data
.length
,
1298 ASN1_MALLOC_ENCODE(EncryptedData
,
1299 outdata
->data
, outdata
->length
,
1301 free_EncryptedData(&ed
);
1304 if (outdata
->length
!= size
)
1305 krb5_abortx(context
, "internal asn.1 encoder error");
1309 free_PA_ServerReferralData(&ref
);
1310 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1315 * This function is intended to be used when failure to find the client is
1319 _kdc_db_fetch_client(krb5_context context
,
1320 krb5_kdc_configuration
*config
,
1324 const char *krbtgt_realm
,
1326 hdb_entry
**client_out
)
1328 krb5_error_code ret
;
1329 hdb_entry
*client
= NULL
;
1334 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| flags
,
1335 NULL
, clientdb
, &client
);
1336 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1338 * This is OK, we are just trying to find out if they have
1339 * been disabled or deleted in the meantime; missing secrets
1344 * If the client belongs to the same realm as our TGS, it
1345 * should exist in the local database.
1349 if (strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1350 if (ret
== HDB_ERR_NOENTRY
)
1351 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1352 kdc_log(context
, config
, 4, "Client no longer in database: %s", cpn
);
1356 msg
= krb5_get_error_message(context
, ret
);
1357 kdc_log(context
, config
, 4, "Client not found in database: %s", msg
);
1358 krb5_free_error_message(context
, msg
);
1359 } else if (client
->flags
.invalid
|| !client
->flags
.client
) {
1360 kdc_log(context
, config
, 4, "Client has invalid bit set");
1361 _kdc_free_ent(context
, *clientdb
, client
);
1362 return KRB5KDC_ERR_POLICY
;
1365 *client_out
= client
;
1370 static krb5_error_code
1371 tgs_build_reply(astgs_request_t priv
,
1372 krb5_enctype krbtgt_etype
,
1373 AuthorizationData
**auth_data
,
1374 const struct sockaddr
*from_addr
)
1376 krb5_context context
= priv
->context
;
1377 krb5_kdc_configuration
*config
= priv
->config
;
1378 KDC_REQ_BODY
*b
= &priv
->req
.req_body
;
1379 const char *from
= priv
->from
;
1380 krb5_error_code ret
, ret2
;
1381 krb5_principal krbtgt_out_principal
= NULL
;
1382 krb5_principal user2user_princ
= NULL
;
1383 char *spn
= NULL
, *cpn
= NULL
, *krbtgt_out_n
= NULL
;
1384 char *user2user_name
= NULL
;
1385 HDB
*user2user_krbtgtdb
;
1386 hdb_entry
*user2user_krbtgt
= NULL
;
1387 HDB
*clientdb
= NULL
;
1388 HDB
*serverdb
= NULL
;
1389 krb5_realm ref_realm
= NULL
;
1390 EncTicketPart
*tgt
= &priv
->ticket
->ticket
;
1391 const EncryptionKey
*ekey
;
1392 krb5_keyblock sessionkey
;
1394 krb5_pac user2user_pac
= NULL
;
1396 krb5_boolean add_ticket_sig
= FALSE
;
1397 const char *tgt_realm
= /* Realm of TGT issuer */
1398 krb5_principal_get_realm(context
, priv
->krbtgt
->principal
);
1399 const char *our_realm
= /* Realm of this KDC */
1400 krb5_principal_get_comp_string(context
, priv
->krbtgt
->principal
, 1);
1401 char **capath
= NULL
;
1402 size_t num_capath
= 0;
1405 hdb_entry
*krbtgt_out
= NULL
;
1409 EncTicketPart adtkt
;
1411 krb5_boolean kdc_issued
= FALSE
;
1414 int flags
= HDB_F_FOR_TGS_REQ
;
1418 memset(&sessionkey
, 0, sizeof(sessionkey
));
1419 memset(&adtkt
, 0, sizeof(adtkt
));
1425 * The canonicalize KDC option is passed as a hint to the backend, but
1426 * can typically be ignored. Per RFC 6806, names are not canonicalized
1427 * in response to a TGS request (although we make an exception, see
1428 * force-canonicalize below).
1430 if (b
->kdc_options
.canonicalize
)
1431 flags
|= HDB_F_CANON
;
1434 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1435 _kdc_set_const_e_text(priv
, "No server in request");
1439 _krb5_principalname2krb5_principal(context
, &priv
->server_princ
, *s
, r
);
1440 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1444 _krb5_principalname2krb5_principal(context
, &priv
->client_princ
,
1445 tgt
->cname
, tgt
->crealm
);
1446 ret
= krb5_unparse_name(context
, priv
->client_princ
, &priv
->cname
);
1450 result
= unparse_flags(KDCOptions2int(b
->kdc_options
),
1451 asn1_KDCOptions_units(),
1452 opt_str
, sizeof(opt_str
));
1454 kdc_log(context
, config
, 4,
1455 "TGS-REQ %s from %s for %s [%s]",
1456 cpn
, from
, spn
, opt_str
);
1458 kdc_log(context
, config
, 4,
1459 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1467 _kdc_free_ent(context
, serverdb
, priv
->server
);
1468 priv
->server
= NULL
;
1469 ret
= _kdc_db_fetch(context
, config
, priv
->server_princ
,
1470 HDB_F_GET_SERVER
| HDB_F_DELAY_NEW_KEYS
| flags
,
1471 NULL
, &serverdb
, &priv
->server
);
1472 priv
->serverdb
= serverdb
;
1473 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
1474 kdc_log(context
, config
, 5, "target %s does not have secrets at this KDC, need to proxy", spn
);
1475 kdc_audit_addreason((kdc_request_t
)priv
, "Target not found here");
1477 } else if (ret
== HDB_ERR_WRONG_REALM
) {
1479 ref_realm
= strdup(priv
->server
->principal
->realm
);
1480 if (ref_realm
== NULL
) {
1481 ret
= krb5_enomem(context
);
1485 kdc_log(context
, config
, 4,
1486 "Returning a referral to realm %s for "
1489 krb5_free_principal(context
, priv
->server_princ
);
1490 priv
->server_princ
= NULL
;
1491 ret
= krb5_make_principal(context
, &priv
->server_princ
, r
, KRB5_TGS_NAME
,
1497 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1504 const char *new_rlm
, *msg
;
1508 priv
->error_code
= ret
; /* advise policy plugin of failure reason */
1509 ret2
= _kdc_referral_policy(priv
);
1511 krb5_xfree(priv
->sname
);
1513 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1517 } else if (ret2
!= KRB5_PLUGIN_NO_HANDLE
) {
1519 } else if ((req_rlm
= get_krbtgt_realm(&priv
->server_princ
->name
)) != NULL
) {
1520 if (capath
== NULL
) {
1521 /* With referalls, hierarchical capaths are always enabled */
1522 ret2
= _krb5_find_capath(context
, tgt
->crealm
, our_realm
,
1523 req_rlm
, TRUE
, &capath
, &num_capath
);
1526 kdc_audit_addreason((kdc_request_t
)priv
,
1527 "No trusted path from client realm to ours");
1531 new_rlm
= num_capath
> 0 ? capath
[--num_capath
] : NULL
;
1533 kdc_log(context
, config
, 5, "krbtgt from %s via %s for "
1534 "realm %s not found, trying %s", tgt
->crealm
,
1535 our_realm
, req_rlm
, new_rlm
);
1538 ref_realm
= strdup(new_rlm
);
1539 if (ref_realm
== NULL
) {
1540 ret
= krb5_enomem(context
);
1544 krb5_free_principal(context
, priv
->server_princ
);
1545 priv
->server_princ
= NULL
;
1546 krb5_make_principal(context
, &priv
->server_princ
, r
,
1547 KRB5_TGS_NAME
, ref_realm
, NULL
);
1550 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1556 } else if (need_referral(context
, config
, &b
->kdc_options
, priv
->server_princ
, &realms
)) {
1557 if (strcmp(realms
[0], priv
->server_princ
->realm
) != 0) {
1558 kdc_log(context
, config
, 4,
1559 "Returning a referral to realm %s for "
1560 "server %s that was not found",
1562 krb5_free_principal(context
, priv
->server_princ
);
1563 priv
->server_princ
= NULL
;
1564 krb5_make_principal(context
, &priv
->server_princ
, r
, KRB5_TGS_NAME
,
1568 ret
= krb5_unparse_name(context
, priv
->server_princ
, &priv
->sname
);
1570 krb5_free_host_realm(context
, realms
);
1576 ref_realm
= strdup(realms
[0]);
1578 krb5_free_host_realm(context
, realms
);
1581 krb5_free_host_realm(context
, realms
);
1583 msg
= krb5_get_error_message(context
, ret
);
1584 kdc_log(context
, config
, 3,
1585 "Server not found in database: %s: %s", spn
, msg
);
1586 krb5_free_error_message(context
, msg
);
1587 if (ret
== HDB_ERR_NOENTRY
)
1588 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1589 kdc_audit_addreason((kdc_request_t
)priv
,
1590 "Service principal unknown");
1595 * Now refetch the primary krbtgt, and get the current kvno (the
1596 * sign check may have been on an old kvno, and the server may
1597 * have been an incoming trust)
1600 ret
= krb5_make_principal(context
,
1601 &krbtgt_out_principal
,
1607 kdc_log(context
, config
, 4,
1608 "Failed to make krbtgt principal name object for "
1609 "authz-data signatures");
1612 ret
= krb5_unparse_name(context
, krbtgt_out_principal
, &krbtgt_out_n
);
1614 kdc_log(context
, config
, 4,
1615 "Failed to make krbtgt principal name object for "
1616 "authz-data signatures");
1620 ret
= _kdc_db_fetch(context
, config
, krbtgt_out_principal
,
1621 HDB_F_GET_KRBTGT
, NULL
, &krbtgt_outdb
, &krbtgt_out
);
1624 ret
= krb5_unparse_name(context
, priv
->krbtgt
->principal
, &ktpn
);
1625 kdc_log(context
, config
, 4,
1626 "No such principal %s (needed for authz-data signature keys) "
1627 "while processing TGS-REQ for service %s with krbtgt %s",
1628 krbtgt_out_n
, spn
, (ret
== 0) ? ktpn
: "<unknown>");
1630 ret
= KRB5KRB_AP_ERR_NOT_US
;
1635 * Select enctype, return key and kvno.
1641 if(b
->kdc_options
.enc_tkt_in_skey
) {
1645 krb5uint32 second_kvno
= 0;
1646 krb5uint32
*kvno_ptr
= NULL
;
1649 hdb_entry
*user2user_client
= NULL
;
1650 krb5_boolean user2user_kdc_issued
= FALSE
;
1653 if(b
->additional_tickets
== NULL
||
1654 b
->additional_tickets
->len
== 0){
1655 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1656 kdc_log(context
, config
, 4,
1657 "No second ticket present in user-to-user request");
1658 kdc_audit_addreason((kdc_request_t
)priv
,
1659 "No second ticket present in user-to-user request");
1662 t
= &b
->additional_tickets
->val
[0];
1663 if(!get_krbtgt_realm(&t
->sname
)){
1664 kdc_log(context
, config
, 4,
1665 "Additional ticket is not a ticket-granting ticket");
1666 kdc_audit_addreason((kdc_request_t
)priv
,
1667 "Additional ticket is not a ticket-granting ticket");
1668 ret
= KRB5KDC_ERR_POLICY
;
1671 ret
= _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1675 ret
= krb5_unparse_name(context
, p
, &tpn
);
1678 if(t
->enc_part
.kvno
){
1679 second_kvno
= *t
->enc_part
.kvno
;
1680 kvno_ptr
= &second_kvno
;
1682 ret
= _kdc_db_fetch(context
, config
, p
,
1683 HDB_F_GET_KRBTGT
, kvno_ptr
,
1684 &user2user_krbtgtdb
, &user2user_krbtgt
);
1685 krb5_free_principal(context
, p
);
1687 if (ret
== HDB_ERR_NOENTRY
)
1688 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1689 kdc_audit_addreason((kdc_request_t
)priv
,
1690 "User-to-user service principal (TGS) unknown");
1694 ret
= hdb_enctype2key(context
, user2user_krbtgt
, NULL
,
1695 t
->enc_part
.etype
, &uukey
);
1697 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1698 kdc_audit_addreason((kdc_request_t
)priv
,
1699 "User-to-user enctype not supported");
1703 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1705 kdc_audit_addreason((kdc_request_t
)priv
,
1706 "User-to-user TGT decrypt failure");
1711 ret
= _kdc_verify_flags(context
, config
, &adtkt
, tpn
);
1713 kdc_audit_addreason((kdc_request_t
)priv
,
1714 "User-to-user TGT expired or invalid");
1720 /* Fetch the name from the TGT. */
1721 ret
= _krb5_principalname2krb5_principal(context
, &user2user_princ
,
1722 adtkt
.cname
, adtkt
.crealm
);
1726 ret
= krb5_unparse_name(context
, user2user_princ
, &user2user_name
);
1731 * Look up the name given in the TGT in the database. The user
1732 * claims to have a ticket-granting-ticket to our KDC, so we should
1733 * fail hard if we can't find the user - otherwise we can't do
1736 ret
= _kdc_db_fetch(context
, config
, user2user_princ
,
1737 HDB_F_GET_CLIENT
| flags
,
1738 NULL
, &user2user_db
, &user2user_client
);
1739 if (ret
== HDB_ERR_NOENTRY
)
1740 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1745 * The account is present in the database, now check the
1748 * We check this as a client (because the purpose of
1749 * user2user is that the server flag is not set, because
1750 * the long-term key is not strong, but this does mean
1751 * that a client with an expired password can't get accept
1752 * a user2user ticket.
1754 ret
= kdc_check_flags(priv
,
1759 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1764 * Also check that the account is the same one specified in the
1767 ret
= _kdc_check_client_matches_target_service(context
,
1774 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1778 /* Verify the PAC of the TGT. */
1779 ret
= _kdc_check_pac(priv
, user2user_princ
, NULL
,
1780 user2user_client
, user2user_krbtgt
, user2user_krbtgt
, user2user_krbtgt
,
1781 &uukey
->key
, &priv
->ticket_key
->key
, &adtkt
,
1782 &user2user_kdc_issued
, &user2user_pac
, NULL
, NULL
);
1783 _kdc_free_ent(context
, user2user_db
, user2user_client
);
1785 const char *msg
= krb5_get_error_message(context
, ret
);
1786 kdc_log(context
, config
, 0,
1787 "Verify PAC failed for %s (%s) from %s with %s",
1788 spn
, user2user_name
, from
, msg
);
1789 krb5_free_error_message(context
, msg
);
1793 if ((config
->require_pac
&& !user2user_pac
)
1794 || (user2user_pac
&& !user2user_kdc_issued
))
1796 ret
= KRB5KDC_ERR_BADOPTION
;
1797 kdc_log(context
, config
, 0,
1798 "Ticket not signed with PAC; user-to-user failed (%s).",
1799 user2user_pac
? "Ticket unsigned" : "No PAC");
1804 for(i
= 0; i
< b
->etype
.len
; i
++)
1805 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1807 if(i
== b
->etype
.len
) {
1808 kdc_log(context
, config
, 4,
1809 "Addition ticket has no matching etypes");
1810 krb5_clear_error_message(context
);
1811 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1812 kdc_audit_addreason((kdc_request_t
)priv
,
1813 "No matching enctypes for 2nd ticket");
1816 etype
= b
->etype
.val
[i
];
1821 ret
= _kdc_find_etype(priv
, krb5_principal_is_krbtgt(context
, priv
->server_princ
)
1823 b
->etype
.val
, b
->etype
.len
, &etype
, NULL
,
1826 kdc_log(context
, config
, 4,
1827 "Server (%s) has no support for etypes", spn
);
1828 kdc_audit_addreason((kdc_request_t
)priv
,
1829 "Enctype not supported");
1832 ret
= _kdc_get_preferred_key(context
, config
, priv
->server
, spn
,
1835 kdc_log(context
, config
, 4,
1836 "Server (%s) has no supported etypes", spn
);
1837 kdc_audit_addreason((kdc_request_t
)priv
,
1838 "Enctype not supported");
1842 kvno
= priv
->server
->kvno
;
1845 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1851 * Check that service is in the same realm as the krbtgt. If it's
1852 * not the same, it's someone that is using a uni-directional trust
1857 * The first realm is the realm of the service, the second is
1858 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1859 * encrypted to. The redirection via the krbtgt_out entry allows
1860 * the DB to possibly correct the case of the realm (Samba4 does
1861 * this) before the strcmp()
1863 if (strcmp(krb5_principal_get_realm(context
, priv
->server
->principal
),
1864 krb5_principal_get_realm(context
, krbtgt_out
->principal
)) != 0) {
1866 ret
= krb5_unparse_name(context
, krbtgt_out
->principal
, &ktpn
);
1867 kdc_log(context
, config
, 4,
1868 "Request with wrong krbtgt: %s",
1869 (ret
== 0) ? ktpn
: "<unknown>");
1872 ret
= KRB5KRB_AP_ERR_NOT_US
;
1873 kdc_audit_addreason((kdc_request_t
)priv
, "Request with wrong TGT");
1877 ret
= _kdc_get_preferred_key(context
, config
, krbtgt_out
, krbtgt_out_n
,
1880 kdc_log(context
, config
, 4,
1881 "Failed to find key for krbtgt PAC signature");
1882 kdc_audit_addreason((kdc_request_t
)priv
,
1883 "Failed to find key for krbtgt PAC signature");
1886 ret
= hdb_enctype2key(context
, krbtgt_out
, NULL
,
1887 tkey_sign
->key
.keytype
, &tkey_sign
);
1889 kdc_log(context
, config
, 4,
1890 "Failed to find key for krbtgt PAC signature");
1891 kdc_audit_addreason((kdc_request_t
)priv
,
1892 "Failed to find key for krbtgt PAC signature");
1896 if (_kdc_synthetic_princ_used_p(context
, priv
->ticket
))
1897 flags
|= HDB_F_SYNTHETIC_OK
;
1899 ret
= _kdc_db_fetch_client(context
, config
, flags
, priv
->client_princ
,
1900 cpn
, our_realm
, &clientdb
, &priv
->client
);
1903 /* flags &= ~HDB_F_SYNTHETIC_OK; */ /* `flags' is not used again below */
1904 priv
->clientdb
= clientdb
;
1906 ret
= _kdc_check_pac(priv
, priv
->client_princ
, NULL
,
1907 priv
->client
, priv
->server
,
1908 priv
->krbtgt
, priv
->krbtgt
,
1909 &priv
->ticket_key
->key
, &priv
->ticket_key
->key
, tgt
,
1910 &kdc_issued
, &priv
->pac
, &priv
->canon_client_princ
,
1911 &priv
->pac_attributes
);
1913 const char *msg
= krb5_get_error_message(context
, ret
);
1914 kdc_audit_addreason((kdc_request_t
)priv
, "PAC check failed");
1915 kdc_log(context
, config
, 4,
1916 "Verify PAC failed for %s (%s) from %s with %s",
1917 spn
, cpn
, from
, msg
);
1918 krb5_free_error_message(context
, msg
);
1927 * Services for User: protocol transition and constrained delegation
1930 ret
= _kdc_validate_services_for_user(priv
);
1938 ret
= kdc_check_flags(priv
, FALSE
, priv
->client
, priv
->server
);
1942 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1943 !krb5_principal_compare(context
,
1944 priv
->krbtgt
->principal
,
1945 priv
->server
->principal
)){
1946 kdc_audit_addreason((kdc_request_t
)priv
, "Inconsistent request");
1947 kdc_log(context
, config
, 4, "Inconsistent request.");
1948 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1952 /* check for valid set of addresses */
1953 if (!_kdc_check_addresses(priv
, tgt
->caddr
, from_addr
)) {
1954 if (config
->check_ticket_addresses
) {
1955 ret
= KRB5KRB_AP_ERR_BADADDR
;
1956 kdc_audit_setkv_bool((kdc_request_t
)priv
, "wrongaddr", TRUE
);
1957 kdc_log(context
, config
, 4, "Request from wrong address");
1958 kdc_audit_addreason((kdc_request_t
)priv
, "Request from wrong address");
1960 } else if (config
->warn_ticket_addresses
) {
1961 kdc_audit_setkv_bool((kdc_request_t
)priv
, "wrongaddr", TRUE
);
1965 /* check local and per-principal anonymous ticket issuance policy */
1966 if (is_anon_tgs_request_p(b
, tgt
)) {
1967 ret
= _kdc_check_anon_policy(priv
);
1973 * If this is an referral, add server referral data to the
1980 kdc_log(context
, config
, 3,
1981 "Adding server referral to %s", ref_realm
);
1983 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1987 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1988 NULL
, s
, &pa
.padata_value
);
1989 krb5_crypto_destroy(context
, crypto
);
1991 kdc_audit_addreason((kdc_request_t
)priv
, "Referral build failed");
1992 kdc_log(context
, config
, 4,
1993 "Failed building server referral");
1996 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1998 ret
= add_METHOD_DATA(priv
->rep
.padata
, &pa
);
1999 krb5_data_free(&pa
.padata_value
);
2001 kdc_log(context
, config
, 4,
2002 "Add server referral METHOD-DATA failed");
2008 * Only add ticket signature if the requested server is not krbtgt, and
2009 * either the header server is krbtgt or, in the case of renewal/validation
2010 * if it was signed with PAC ticket signature and we verified it.
2011 * Currently Heimdal only allows renewal of krbtgt anyway but that might
2012 * change one day (see issue #763) so make sure to check for it.
2016 !krb5_principal_is_krbtgt(context
, priv
->server
->principal
)) {
2018 /* Validate armor TGT before potentially including device claims */
2019 if (priv
->armor_ticket
) {
2020 ret
= _kdc_fast_check_armor_pac(priv
, HDB_F_FOR_TGS_REQ
);
2025 add_ticket_sig
= TRUE
;
2029 * Active-Directory implementations use the high part of the kvno as the
2030 * read-only-dc identifier, we need to embed it in the PAC KDC signatures.
2033 rodc_id
= krbtgt_out
->kvno
>> 16;
2039 ret
= tgs_make_reply(priv
,
2051 free(user2user_name
);
2053 _krb5_free_capath(context
, capath
);
2055 krb5_free_keyblock_contents(context
, &sessionkey
);
2057 _kdc_free_ent(context
, krbtgt_outdb
, krbtgt_out
);
2058 if(user2user_krbtgt
)
2059 _kdc_free_ent(context
, user2user_krbtgtdb
, user2user_krbtgt
);
2061 krb5_free_principal(context
, user2user_princ
);
2062 krb5_free_principal(context
, krbtgt_out_principal
);
2065 free_EncTicketPart(&adtkt
);
2067 krb5_pac_free(context
, user2user_pac
);
2077 _kdc_tgs_rep(astgs_request_t r
)
2079 krb5_kdc_configuration
*config
= r
->config
;
2080 KDC_REQ
*req
= &r
->req
;
2081 krb5_data
*data
= r
->reply
;
2082 const char *from
= r
->from
;
2083 struct sockaddr
*from_addr
= r
->addr
;
2084 int datagram_reply
= r
->datagram_reply
;
2085 AuthorizationData
*auth_data
= NULL
;
2086 krb5_error_code ret
;
2088 const PA_DATA
*tgs_req
, *pa
;
2089 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2091 time_t *csec
= NULL
;
2096 if(req
->padata
== NULL
){
2097 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2098 kdc_log(r
->context
, config
, 4,
2099 "TGS-REQ from %s without PA-DATA", from
);
2104 pa
= _kdc_find_padata(&r
->req
, &i
, KRB5_PADATA_FX_FAST_ARMOR
);
2106 kdc_log(r
->context
, r
->config
, 10, "Found TGS-REQ FAST armor inside TGS-REQ pa-data");
2107 ret
= KRB5KRB_ERR_GENERIC
;
2112 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2113 if(tgs_req
== NULL
){
2114 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2116 kdc_log(r
->context
, config
, 4,
2117 "TGS-REQ from %s without PA-TGS-REQ", from
);
2120 ret
= tgs_parse_request(r
, tgs_req
,
2125 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2126 /* kdc_log() is called in tgs_parse_request() */
2130 kdc_log(r
->context
, config
, 4,
2131 "Failed parsing TGS-REQ from %s", from
);
2135 ret
= _kdc_fast_strengthen_reply_key(r
);
2139 ALLOC(r
->rep
.padata
);
2140 if (r
->rep
.padata
== NULL
) {
2142 krb5_set_error_message(r
->context
, ret
, N_("malloc: out of memory", ""));
2146 ret
= tgs_build_reply(r
,
2151 kdc_log(r
->context
, config
, 4,
2152 "Failed building TGS-REP to %s", from
);
2157 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2158 krb5_data_free(data
);
2159 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2160 _kdc_set_const_e_text(r
, "Reply packet too large");
2165 /* Overwrite ‘error_code’ only if we have an actual error. */
2166 r
->error_code
= ret
;
2169 krb5_error_code ret2
= _kdc_audit_request(r
);
2171 krb5_data_free(data
);
2176 if(ret
&& ret
!= HDB_ERR_NOT_FOUND_HERE
&& data
->data
== NULL
){
2177 METHOD_DATA error_method
= { 0, NULL
};
2179 kdc_log(r
->context
, config
, 5, "tgs-req: sending error: %d to client", ret
);
2180 ret
= _kdc_fast_mk_error(r
,
2184 r
->error_code
? r
->error_code
: ret
,
2185 r
->client_princ
? r
->client_princ
:(r
->ticket
!= NULL
? r
->ticket
->client
: NULL
),
2186 r
->server_princ
? r
->server_princ
:(r
->ticket
!= NULL
? r
->ticket
->server
: NULL
),
2189 free_METHOD_DATA(&error_method
);
2194 free_TGS_REP(&r
->rep
);
2195 free_TransitedEncoding(&r
->et
.transited
);
2196 free(r
->et
.starttime
);
2197 free(r
->et
.renew_till
);
2198 if(r
->et
.authorization_data
) {
2199 free_AuthorizationData(r
->et
.authorization_data
);
2200 free(r
->et
.authorization_data
);
2202 free_LastReq(&r
->ek
.last_req
);
2203 if (r
->et
.key
.keyvalue
.data
) {
2204 memset_s(r
->et
.key
.keyvalue
.data
, 0, r
->et
.key
.keyvalue
.length
,
2205 r
->et
.key
.keyvalue
.length
);
2207 free_EncryptionKey(&r
->et
.key
);
2209 if (r
->canon_client_princ
) {
2210 krb5_free_principal(r
->context
, r
->canon_client_princ
);
2211 r
->canon_client_princ
= NULL
;
2213 if (r
->armor_crypto
) {
2214 krb5_crypto_destroy(r
->context
, r
->armor_crypto
);
2215 r
->armor_crypto
= NULL
;
2217 if (r
->armor_ticket
)
2218 krb5_free_ticket(r
->context
, r
->armor_ticket
);
2219 if (r
->armor_server
)
2220 _kdc_free_ent(r
->context
, r
->armor_serverdb
, r
->armor_server
);
2221 if (r
->explicit_armor_client
)
2222 _kdc_free_ent(r
->context
,
2223 r
->explicit_armor_clientdb
,
2224 r
->explicit_armor_client
);
2225 if (r
->explicit_armor_pac
)
2226 krb5_pac_free(r
->context
, r
->explicit_armor_pac
);
2227 krb5_free_keyblock_contents(r
->context
, &r
->reply_key
);
2228 krb5_free_keyblock_contents(r
->context
, &r
->strengthen_key
);
2231 krb5_free_ticket(r
->context
, r
->ticket
);
2233 _kdc_free_ent(r
->context
, r
->krbtgtdb
, r
->krbtgt
);
2236 _kdc_free_ent(r
->context
, r
->clientdb
, r
->client
);
2237 krb5_free_principal(r
->context
, r
->client_princ
);
2239 _kdc_free_ent(r
->context
, r
->serverdb
, r
->server
);
2240 krb5_free_principal(r
->context
, r
->server_princ
);
2241 _kdc_free_fast_state(&r
->fast
);
2242 krb5_pac_free(r
->context
, r
->pac
);
2245 free_AuthorizationData(auth_data
);