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];
54 static krb5_error_code
55 check_PAC(krb5_context context
,
56 krb5_kdc_configuration
*config
,
57 const krb5_principal client_principal
,
58 const krb5_principal delegated_proxy_principal
,
62 const EncryptionKey
*server_check_key
,
63 const EncryptionKey
*server_sign_key
,
64 const EncryptionKey
*krbtgt_sign_key
,
69 AuthorizationData
*ad
= tkt
->authorization_data
;
73 if (ad
== NULL
|| ad
->len
== 0)
76 for (i
= 0; i
< ad
->len
; i
++) {
77 AuthorizationData child
;
79 if (ad
->val
[i
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
82 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
83 ad
->val
[i
].ad_data
.length
,
87 krb5_set_error_message(context
, ret
, "Failed to decode "
88 "IF_RELEVANT with %d", ret
);
91 for (j
= 0; j
< child
.len
; j
++) {
93 if (child
.val
[j
].ad_type
== KRB5_AUTHDATA_WIN2K_PAC
) {
98 ret
= krb5_pac_parse(context
,
99 child
.val
[j
].ad_data
.data
,
100 child
.val
[j
].ad_data
.length
,
102 free_AuthorizationData(&child
);
106 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
,
108 server_check_key
, NULL
);
110 krb5_pac_free(context
, pac
);
114 ret
= _kdc_pac_verify(context
, client_principal
,
115 delegated_proxy_principal
,
116 client
, server
, krbtgt
, &pac
, &signed_pac
);
118 krb5_pac_free(context
, pac
);
123 * Only re-sign PAC if we could verify it with the PAC
124 * function. The no-verify case happens when we get in
125 * a PAC from cross realm from a Windows domain and
126 * that there is no PAC verification function.
130 ret
= _krb5_pac_sign(context
, pac
, tkt
->authtime
,
132 server_sign_key
, krbtgt_sign_key
, rspac
);
134 krb5_pac_free(context
, pac
);
139 free_AuthorizationData(&child
);
148 static krb5_error_code
149 check_tgs_flags(krb5_context context
,
150 krb5_kdc_configuration
*config
,
151 KDC_REQ_BODY
*b
, const EncTicketPart
*tgt
, EncTicketPart
*et
)
153 KDCOptions f
= b
->kdc_options
;
156 if(!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
){
157 kdc_log(context
, config
, 0,
158 "Bad request to validate ticket");
159 return KRB5KDC_ERR_BADOPTION
;
161 if(*tgt
->starttime
> kdc_time
){
162 kdc_log(context
, config
, 0,
163 "Early request to validate ticket");
164 return KRB5KRB_AP_ERR_TKT_NYV
;
167 et
->flags
.invalid
= 0;
168 }else if(tgt
->flags
.invalid
){
169 kdc_log(context
, config
, 0,
170 "Ticket-granting ticket has INVALID flag set");
171 return KRB5KRB_AP_ERR_TKT_INVALID
;
175 if(!tgt
->flags
.forwardable
){
176 kdc_log(context
, config
, 0,
177 "Bad request for forwardable ticket");
178 return KRB5KDC_ERR_BADOPTION
;
180 et
->flags
.forwardable
= 1;
183 if(!tgt
->flags
.forwardable
){
184 kdc_log(context
, config
, 0,
185 "Request to forward non-forwardable ticket");
186 return KRB5KDC_ERR_BADOPTION
;
188 et
->flags
.forwarded
= 1;
189 et
->caddr
= b
->addresses
;
191 if(tgt
->flags
.forwarded
)
192 et
->flags
.forwarded
= 1;
195 if(!tgt
->flags
.proxiable
){
196 kdc_log(context
, config
, 0,
197 "Bad request for proxiable ticket");
198 return KRB5KDC_ERR_BADOPTION
;
200 et
->flags
.proxiable
= 1;
203 if(!tgt
->flags
.proxiable
){
204 kdc_log(context
, config
, 0,
205 "Request to proxy non-proxiable ticket");
206 return KRB5KDC_ERR_BADOPTION
;
209 et
->caddr
= b
->addresses
;
214 if(f
.allow_postdate
){
215 if(!tgt
->flags
.may_postdate
){
216 kdc_log(context
, config
, 0,
217 "Bad request for post-datable ticket");
218 return KRB5KDC_ERR_BADOPTION
;
220 et
->flags
.may_postdate
= 1;
223 if(!tgt
->flags
.may_postdate
){
224 kdc_log(context
, config
, 0,
225 "Bad request for postdated ticket");
226 return KRB5KDC_ERR_BADOPTION
;
229 *et
->starttime
= *b
->from
;
230 et
->flags
.postdated
= 1;
231 et
->flags
.invalid
= 1;
232 }else if(b
->from
&& *b
->from
> kdc_time
+ context
->max_skew
){
233 kdc_log(context
, config
, 0, "Ticket cannot be postdated");
234 return KRB5KDC_ERR_CANNOT_POSTDATE
;
238 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
239 kdc_log(context
, config
, 0,
240 "Bad request for renewable ticket");
241 return KRB5KDC_ERR_BADOPTION
;
243 et
->flags
.renewable
= 1;
244 ALLOC(et
->renew_till
);
245 _kdc_fix_time(&b
->rtime
);
246 *et
->renew_till
= *b
->rtime
;
250 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
251 kdc_log(context
, config
, 0,
252 "Request to renew non-renewable ticket");
253 return KRB5KDC_ERR_BADOPTION
;
255 old_life
= tgt
->endtime
;
257 old_life
-= *tgt
->starttime
;
259 old_life
-= tgt
->authtime
;
260 et
->endtime
= *et
->starttime
+ old_life
;
261 if (et
->renew_till
!= NULL
)
262 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
266 /* checks for excess flags */
267 if(f
.request_anonymous
&& !config
->allow_anonymous
){
268 kdc_log(context
, config
, 0,
269 "Request for anonymous ticket");
270 return KRB5KDC_ERR_BADOPTION
;
277 * Determine if constrained delegation is allowed from this client to this server
280 static krb5_error_code
281 check_constrained_delegation(krb5_context context
,
282 krb5_kdc_configuration
*config
,
284 hdb_entry_ex
*client
,
285 hdb_entry_ex
*server
,
286 krb5_const_principal target
)
288 const HDB_Ext_Constrained_delegation_acl
*acl
;
293 * constrained_delegation (S4U2Proxy) only works within
294 * the same realm. We use the already canonicalized version
295 * of the principals here, while "target" is the principal
296 * provided by the client.
298 if(!krb5_realm_compare(context
, client
->entry
.principal
, server
->entry
.principal
)) {
299 ret
= KRB5KDC_ERR_BADOPTION
;
300 kdc_log(context
, config
, 0,
301 "Bad request for constrained delegation");
305 if (clientdb
->hdb_check_constrained_delegation
) {
306 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, target
);
310 /* if client delegates to itself, that ok */
311 if (krb5_principal_compare(context
, client
->entry
.principal
, server
->entry
.principal
) == TRUE
)
314 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
316 krb5_clear_error_message(context
);
321 for (i
= 0; i
< acl
->len
; i
++) {
322 if (krb5_principal_compare(context
, target
, &acl
->val
[i
]) == TRUE
)
326 ret
= KRB5KDC_ERR_BADOPTION
;
328 kdc_log(context
, config
, 0,
329 "Bad request for constrained delegation");
334 * Determine if s4u2self is allowed from this client to this server
336 * For example, regardless of the principal being impersonated, if the
337 * 'client' and 'server' are the same, then it's safe.
340 static krb5_error_code
341 check_s4u2self(krb5_context context
,
342 krb5_kdc_configuration
*config
,
344 hdb_entry_ex
*client
,
345 krb5_const_principal server
)
349 /* if client does a s4u2self to itself, that ok */
350 if (krb5_principal_compare(context
, client
->entry
.principal
, server
) == TRUE
)
353 if (clientdb
->hdb_check_s4u2self
) {
354 ret
= clientdb
->hdb_check_s4u2self(context
, clientdb
, client
, server
);
358 ret
= KRB5KDC_ERR_BADOPTION
;
367 static krb5_error_code
368 verify_flags (krb5_context context
,
369 krb5_kdc_configuration
*config
,
370 const EncTicketPart
*et
,
373 if(et
->endtime
< kdc_time
){
374 kdc_log(context
, config
, 0, "Ticket expired (%s)", pstr
);
375 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
377 if(et
->flags
.invalid
){
378 kdc_log(context
, config
, 0, "Ticket not valid (%s)", pstr
);
379 return KRB5KRB_AP_ERR_TKT_NYV
;
388 static krb5_error_code
389 fix_transited_encoding(krb5_context context
,
390 krb5_kdc_configuration
*config
,
391 krb5_boolean check_policy
,
392 const TransitedEncoding
*tr
,
394 const char *client_realm
,
395 const char *server_realm
,
396 const char *tgt_realm
)
398 krb5_error_code ret
= 0;
399 char **realms
, **tmp
;
400 unsigned int num_realms
;
403 switch (tr
->tr_type
) {
404 case DOMAIN_X500_COMPRESS
:
408 * Allow empty content of type 0 because that is was Microsoft
409 * generates in their TGT.
411 if (tr
->contents
.length
== 0)
413 kdc_log(context
, config
, 0,
414 "Transited type 0 with non empty content");
415 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
417 kdc_log(context
, config
, 0,
418 "Unknown transited type: %u", tr
->tr_type
);
419 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
422 ret
= krb5_domain_x500_decode(context
,
429 krb5_warn(context
, ret
,
430 "Decoding transited encoding");
433 if(strcmp(client_realm
, tgt_realm
) && strcmp(server_realm
, tgt_realm
)) {
434 /* not us, so add the previous realm to transited set */
435 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
439 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
445 realms
[num_realms
] = strdup(tgt_realm
);
446 if(realms
[num_realms
] == NULL
){
452 if(num_realms
== 0) {
453 if(strcmp(client_realm
, server_realm
))
454 kdc_log(context
, config
, 0,
455 "cross-realm %s -> %s", client_realm
, server_realm
);
459 for(i
= 0; i
< num_realms
; i
++)
460 l
+= strlen(realms
[i
]) + 2;
464 for(i
= 0; i
< num_realms
; i
++) {
466 strlcat(rs
, ", ", l
);
467 strlcat(rs
, realms
[i
], l
);
469 kdc_log(context
, config
, 0,
470 "cross-realm %s -> %s via [%s]",
471 client_realm
, server_realm
, rs
);
476 ret
= krb5_check_transited(context
, client_realm
,
478 realms
, num_realms
, NULL
);
480 krb5_warn(context
, ret
, "cross-realm %s -> %s",
481 client_realm
, server_realm
);
484 et
->flags
.transited_policy_checked
= 1;
486 et
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
487 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
489 krb5_warn(context
, ret
, "Encoding transited encoding");
491 for(i
= 0; i
< num_realms
; i
++)
498 static krb5_error_code
499 tgs_make_reply(krb5_context context
,
500 krb5_kdc_configuration
*config
,
502 krb5_const_principal tgt_name
,
503 const EncTicketPart
*tgt
,
504 const krb5_keyblock
*replykey
,
506 const EncryptionKey
*serverkey
,
507 const krb5_keyblock
*sessionkey
,
509 AuthorizationData
*auth_data
,
510 hdb_entry_ex
*server
,
511 krb5_principal server_principal
,
512 const char *server_name
,
513 hdb_entry_ex
*client
,
514 krb5_principal client_principal
,
515 hdb_entry_ex
*krbtgt
,
516 krb5_enctype krbtgt_etype
,
517 const krb5_data
*rspac
,
518 const METHOD_DATA
*enc_pa_data
,
525 KDCOptions f
= b
->kdc_options
;
529 memset(&rep
, 0, sizeof(rep
));
530 memset(&et
, 0, sizeof(et
));
531 memset(&ek
, 0, sizeof(ek
));
534 rep
.msg_type
= krb_tgs_rep
;
536 et
.authtime
= tgt
->authtime
;
537 _kdc_fix_time(&b
->till
);
538 et
.endtime
= min(tgt
->endtime
, *b
->till
);
540 *et
.starttime
= kdc_time
;
542 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
546 /* We should check the transited encoding if:
547 1) the request doesn't ask not to be checked
548 2) globally enforcing a check
549 3) principal requires checking
550 4) we allow non-check per-principal, but principal isn't marked as allowing this
551 5) we don't globally allow this
554 #define GLOBAL_FORCE_TRANSITED_CHECK \
555 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
556 #define GLOBAL_ALLOW_PER_PRINCIPAL \
557 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
558 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
559 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
561 /* these will consult the database in future release */
562 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
563 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
565 ret
= fix_transited_encoding(context
, config
,
566 !f
.disable_transited_check
||
567 GLOBAL_FORCE_TRANSITED_CHECK
||
568 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
569 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
570 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
571 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
572 &tgt
->transited
, &et
,
573 krb5_principal_get_realm(context
, client_principal
),
574 krb5_principal_get_realm(context
, server
->entry
.principal
),
575 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
));
579 copy_Realm(&server_principal
->realm
, &rep
.ticket
.realm
);
580 _krb5_principal2principalname(&rep
.ticket
.sname
, server_principal
);
581 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
583 if (f.request_anonymous)
584 _kdc_make_anonymous_principalname (&rep.cname);
587 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
588 rep
.ticket
.tkt_vno
= 5;
592 et
.caddr
= tgt
->caddr
;
596 life
= et
.endtime
- *et
.starttime
;
597 if(client
&& client
->entry
.max_life
)
598 life
= min(life
, *client
->entry
.max_life
);
599 if(server
->entry
.max_life
)
600 life
= min(life
, *server
->entry
.max_life
);
601 et
.endtime
= *et
.starttime
+ life
;
603 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
604 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
&&
605 tgt
->renew_till
!= NULL
)
607 et
.flags
.renewable
= 1;
608 ALLOC(et
.renew_till
);
609 *et
.renew_till
= *b
->till
;
613 renew
= *et
.renew_till
- et
.authtime
;
614 if(client
&& client
->entry
.max_renew
)
615 renew
= min(renew
, *client
->entry
.max_renew
);
616 if(server
->entry
.max_renew
)
617 renew
= min(renew
, *server
->entry
.max_renew
);
618 *et
.renew_till
= et
.authtime
+ renew
;
622 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
623 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
624 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
627 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
629 if(*et
.starttime
== et
.endtime
){
630 ret
= KRB5KDC_ERR_NEVER_VALID
;
633 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
635 et
.renew_till
= NULL
;
636 et
.flags
.renewable
= 0;
639 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
640 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
641 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
642 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
644 /* See MS-KILE 3.3.5.1 */
645 if (!server
->entry
.flags
.forwardable
)
646 et
.flags
.forwardable
= 0;
647 if (!server
->entry
.flags
.proxiable
)
648 et
.flags
.proxiable
= 0;
652 * No not need to filter out the any PAC from the
653 * auth_data since it's signed by the KDC.
655 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
656 KRB5_AUTHDATA_WIN2K_PAC
, rspac
);
664 /* XXX check authdata */
666 if (et
.authorization_data
== NULL
) {
667 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
668 if (et
.authorization_data
== NULL
) {
670 krb5_set_error_message(context
, ret
, "malloc: out of memory");
674 for(i
= 0; i
< auth_data
->len
; i
++) {
675 ret
= add_AuthorizationData(et
.authorization_data
, &auth_data
->val
[i
]);
677 krb5_set_error_message(context
, ret
, "malloc: out of memory");
683 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
686 et
.crealm
= tgt_name
->realm
;
687 et
.cname
= tgt_name
->name
;
690 /* MIT must have at least one last_req */
692 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
693 if (ek
.last_req
.val
== NULL
) {
699 ek
.authtime
= et
.authtime
;
700 ek
.starttime
= et
.starttime
;
701 ek
.endtime
= et
.endtime
;
702 ek
.renew_till
= et
.renew_till
;
703 ek
.srealm
= rep
.ticket
.realm
;
704 ek
.sname
= rep
.ticket
.sname
;
706 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
707 et
.endtime
, et
.renew_till
);
709 if (enc_pa_data
->len
) {
710 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
711 if (rep
.padata
== NULL
) {
715 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
720 if (krb5_enctype_valid(context
, et
.key
.keytype
) != 0
721 && _kdc_is_weak_exception(server
->entry
.principal
, et
.key
.keytype
))
723 krb5_enctype_enable(context
, et
.key
.keytype
);
728 /* It is somewhat unclear where the etype in the following
729 encryption should come from. What we have is a session
730 key in the passed tgt, and a list of preferred etypes
731 *for the new ticket*. Should we pick the best possible
732 etype, given the keytype in the tgt, or should we look
733 at the etype list here as well? What if the tgt
734 session key is DES3 and we want a ticket with a (say)
735 CAST session key. Should the DES3 etype be added to the
736 etype list, even if we don't want a session key with
738 ret
= _kdc_encode_reply(context
, config
,
739 &rep
, &et
, &ek
, et
.key
.keytype
,
741 serverkey
, 0, replykey
, rk_is_subkey
,
744 krb5_enctype_disable(context
, et
.key
.keytype
);
748 free_TransitedEncoding(&et
.transited
);
753 if(et
.authorization_data
) {
754 free_AuthorizationData(et
.authorization_data
);
755 free(et
.authorization_data
);
757 free_LastReq(&ek
.last_req
);
758 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
759 free_EncryptionKey(&et
.key
);
763 static krb5_error_code
764 tgs_check_authenticator(krb5_context context
,
765 krb5_kdc_configuration
*config
,
766 krb5_auth_context ac
,
771 krb5_authenticator auth
;
778 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
779 if(auth
->cksum
== NULL
){
780 kdc_log(context
, config
, 0, "No authenticator in request");
781 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
785 * according to RFC1510 it doesn't need to be keyed,
786 * but according to the latest draft it needs to.
790 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
793 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
794 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
795 auth
->cksum
->cksumtype
);
796 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
800 /* XXX should not re-encode this */
801 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
803 const char *msg
= krb5_get_error_message(context
, ret
);
804 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s", msg
);
805 krb5_free_error_message(context
, msg
);
808 if(buf_size
!= len
) {
810 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
811 *e_text
= "KDC internal error";
812 ret
= KRB5KRB_ERR_GENERIC
;
815 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
817 const char *msg
= krb5_get_error_message(context
, ret
);
819 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
820 krb5_free_error_message(context
, msg
);
823 ret
= krb5_verify_checksum(context
,
825 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
830 krb5_crypto_destroy(context
, crypto
);
832 const char *msg
= krb5_get_error_message(context
, ret
);
833 kdc_log(context
, config
, 0,
834 "Failed to verify authenticator checksum: %s", msg
);
835 krb5_free_error_message(context
, msg
);
838 free_Authenticator(auth
);
848 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
850 const char *new_realm
= krb5_config_get_string(context
,
861 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
862 const KDCOptions
* const options
, krb5_principal server
,
867 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
870 if (server
->name
.name_string
.len
== 1)
871 name
= server
->name
.name_string
.val
[0];
872 else if (server
->name
.name_string
.len
== 3) {
874 This is used to give referrals for the
875 E3514235-4B06-11D1-AB04-00C04FC2DCD2/NTDSGUID/DNSDOMAIN
876 SPN form, which is used for inter-domain communication in AD
878 name
= server
->name
.name_string
.val
[2];
879 kdc_log(context
, config
, 0, "Giving 3 part referral for %s", name
);
880 *realms
= malloc(sizeof(char *)*2);
881 if (*realms
== NULL
) {
882 krb5_set_error_message(context
, ENOMEM
, N_("malloc: out of memory", ""));
885 (*realms
)[0] = strdup(name
);
888 } else if (server
->name
.name_string
.len
> 1)
889 name
= server
->name
.name_string
.val
[1];
893 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
895 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
898 static krb5_error_code
899 tgs_parse_request(krb5_context context
,
900 krb5_kdc_configuration
*config
,
902 const PA_DATA
*tgs_req
,
903 hdb_entry_ex
**krbtgt
,
904 krb5_enctype
*krbtgt_etype
,
905 krb5_ticket
**ticket
,
908 const struct sockaddr
*from_addr
,
911 AuthorizationData
**auth_data
,
912 krb5_keyblock
**replykey
,
915 static char failed
[] = "<unparse_name failed>";
918 krb5_principal princ
;
919 krb5_auth_context ac
= NULL
;
920 krb5_flags ap_req_options
;
921 krb5_flags verify_ap_req_flags
;
924 krb5_keyblock
*subkey
= NULL
;
927 krb5uint32
*kvno_ptr
= NULL
;
934 memset(&ap_req
, 0, sizeof(ap_req
));
935 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
937 const char *msg
= krb5_get_error_message(context
, ret
);
938 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s", msg
);
939 krb5_free_error_message(context
, msg
);
943 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
944 /* XXX check for ticket.sname == req.sname */
945 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
946 ret
= KRB5KDC_ERR_POLICY
; /* ? */
950 _krb5_principalname2krb5_principal(context
,
953 ap_req
.ticket
.realm
);
955 if (ap_req
.ticket
.enc_part
.kvno
) {
956 kvno
= *ap_req
.ticket
.enc_part
.kvno
;
959 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, kvno_ptr
,
962 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
964 ret
= krb5_unparse_name(context
, princ
, &p
);
967 krb5_free_principal(context
, princ
);
968 kdc_log(context
, config
, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p
);
971 ret
= HDB_ERR_NOT_FOUND_HERE
;
974 const char *msg
= krb5_get_error_message(context
, ret
);
976 ret
= krb5_unparse_name(context
, princ
, &p
);
979 krb5_free_principal(context
, princ
);
980 kdc_log(context
, config
, 0,
981 "Ticket-granting ticket not found in database: %s", msg
);
982 krb5_free_error_message(context
, msg
);
985 ret
= KRB5KRB_AP_ERR_NOT_US
;
989 if(ap_req
.ticket
.enc_part
.kvno
&&
990 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
993 ret
= krb5_unparse_name (context
, princ
, &p
);
994 krb5_free_principal(context
, princ
);
997 kdc_log(context
, config
, 0,
998 "Ticket kvno = %d, DB kvno = %d (%s)",
999 *ap_req
.ticket
.enc_part
.kvno
,
1000 (*krbtgt
)->entry
.kvno
,
1004 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1008 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1010 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1011 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1013 char *str
= NULL
, *p
= NULL
;
1015 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1016 krb5_unparse_name(context
, princ
, &p
);
1017 kdc_log(context
, config
, 0,
1018 "No server key with enctype %s found for %s",
1019 str
? str
: "<unknown enctype>",
1020 p
? p
: "<unparse_name failed>");
1023 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1027 if (b
->kdc_options
.validate
)
1028 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1030 verify_ap_req_flags
= 0;
1032 ret
= krb5_verify_ap_req2(context
,
1037 verify_ap_req_flags
,
1040 KRB5_KU_TGS_REQ_AUTH
);
1042 krb5_free_principal(context
, princ
);
1044 const char *msg
= krb5_get_error_message(context
, ret
);
1045 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s", msg
);
1046 krb5_free_error_message(context
, msg
);
1051 krb5_authenticator auth
;
1053 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1055 *csec
= malloc(sizeof(**csec
));
1056 if (*csec
== NULL
) {
1057 krb5_free_authenticator(context
, &auth
);
1058 kdc_log(context
, config
, 0, "malloc failed");
1061 **csec
= auth
->ctime
;
1062 *cusec
= malloc(sizeof(**cusec
));
1063 if (*cusec
== NULL
) {
1064 krb5_free_authenticator(context
, &auth
);
1065 kdc_log(context
, config
, 0, "malloc failed");
1068 **cusec
= auth
->cusec
;
1069 krb5_free_authenticator(context
, &auth
);
1073 ret
= tgs_check_authenticator(context
, config
,
1074 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1076 krb5_auth_con_free(context
, ac
);
1080 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1083 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
1085 const char *msg
= krb5_get_error_message(context
, ret
);
1086 krb5_auth_con_free(context
, ac
);
1087 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s", msg
);
1088 krb5_free_error_message(context
, msg
);
1092 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1095 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1097 const char *msg
= krb5_get_error_message(context
, ret
);
1098 krb5_auth_con_free(context
, ac
);
1099 kdc_log(context
, config
, 0, "Failed to get session key: %s", msg
);
1100 krb5_free_error_message(context
, msg
);
1105 krb5_auth_con_free(context
, ac
);
1106 kdc_log(context
, config
, 0,
1107 "Failed to get key for enc-authorization-data");
1108 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1114 if (b
->enc_authorization_data
) {
1117 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1119 const char *msg
= krb5_get_error_message(context
, ret
);
1120 krb5_auth_con_free(context
, ac
);
1121 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1122 krb5_free_error_message(context
, msg
);
1125 ret
= krb5_decrypt_EncryptedData (context
,
1128 b
->enc_authorization_data
,
1130 krb5_crypto_destroy(context
, crypto
);
1132 krb5_auth_con_free(context
, ac
);
1133 kdc_log(context
, config
, 0,
1134 "Failed to decrypt enc-authorization-data");
1135 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1139 if (*auth_data
== NULL
) {
1140 krb5_auth_con_free(context
, ac
);
1141 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1144 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1146 krb5_auth_con_free(context
, ac
);
1149 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1150 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1155 krb5_auth_con_free(context
, ac
);
1158 free_AP_REQ(&ap_req
);
1163 static krb5_error_code
1164 build_server_referral(krb5_context context
,
1165 krb5_kdc_configuration
*config
,
1166 krb5_crypto session
,
1167 krb5_const_realm referred_realm
,
1168 const PrincipalName
*true_principal_name
,
1169 const PrincipalName
*requested_principal
,
1172 PA_ServerReferralData ref
;
1173 krb5_error_code ret
;
1178 memset(&ref
, 0, sizeof(ref
));
1180 if (referred_realm
) {
1181 ALLOC(ref
.referred_realm
);
1182 if (ref
.referred_realm
== NULL
)
1184 *ref
.referred_realm
= strdup(referred_realm
);
1185 if (*ref
.referred_realm
== NULL
)
1188 if (true_principal_name
) {
1189 ALLOC(ref
.true_principal_name
);
1190 if (ref
.true_principal_name
== NULL
)
1192 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1196 if (requested_principal
) {
1197 ALLOC(ref
.requested_principal_name
);
1198 if (ref
.requested_principal_name
== NULL
)
1200 ret
= copy_PrincipalName(requested_principal
,
1201 ref
.requested_principal_name
);
1206 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1207 data
.data
, data
.length
,
1209 free_PA_ServerReferralData(&ref
);
1212 if (data
.length
!= size
)
1213 krb5_abortx(context
, "internal asn.1 encoder error");
1215 ret
= krb5_encrypt_EncryptedData(context
, session
,
1216 KRB5_KU_PA_SERVER_REFERRAL
,
1217 data
.data
, data
.length
,
1223 ASN1_MALLOC_ENCODE(EncryptedData
,
1224 outdata
->data
, outdata
->length
,
1226 free_EncryptedData(&ed
);
1229 if (outdata
->length
!= size
)
1230 krb5_abortx(context
, "internal asn.1 encoder error");
1234 free_PA_ServerReferralData(&ref
);
1235 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1239 static krb5_error_code
1240 tgs_build_reply(krb5_context context
,
1241 krb5_kdc_configuration
*config
,
1244 hdb_entry_ex
*krbtgt
,
1245 krb5_enctype krbtgt_etype
,
1246 const krb5_keyblock
*replykey
,
1248 krb5_ticket
*ticket
,
1251 const char **e_text
,
1252 AuthorizationData
**auth_data
,
1253 const struct sockaddr
*from_addr
)
1255 krb5_error_code ret
;
1256 krb5_principal cp
= NULL
, sp
= NULL
, tp
= NULL
, dp
= NULL
;
1257 krb5_principal krbtgt_principal
= NULL
;
1258 char *spn
= NULL
, *cpn
= NULL
, *tpn
= NULL
, *dpn
= NULL
;
1259 hdb_entry_ex
*server
= NULL
, *client
= NULL
, *s4u2self_impersonated_client
= NULL
;
1260 HDB
*clientdb
, *s4u2self_impersonated_clientdb
;
1261 krb5_realm ref_realm
= NULL
;
1262 EncTicketPart
*tgt
= &ticket
->ticket
;
1263 const EncryptionKey
*ekey
;
1264 krb5_keyblock sessionkey
;
1268 hdb_entry_ex
*krbtgt_out
= NULL
;
1270 METHOD_DATA enc_pa_data
;
1275 EncTicketPart adtkt
;
1281 int flags
= HDB_F_FOR_TGS_REQ
;
1283 memset(&sessionkey
, 0, sizeof(sessionkey
));
1284 memset(&adtkt
, 0, sizeof(adtkt
));
1285 krb5_data_zero(&rspac
);
1286 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1291 if (b
->kdc_options
.canonicalize
)
1292 flags
|= HDB_F_CANON
;
1294 if(b
->kdc_options
.enc_tkt_in_skey
){
1299 krb5uint32 second_kvno
= 0;
1300 krb5uint32
*kvno_ptr
= NULL
;
1302 if(b
->additional_tickets
== NULL
||
1303 b
->additional_tickets
->len
== 0){
1304 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1305 kdc_log(context
, config
, 0,
1306 "No second ticket present in request");
1309 t
= &b
->additional_tickets
->val
[0];
1310 if(!get_krbtgt_realm(&t
->sname
)){
1311 kdc_log(context
, config
, 0,
1312 "Additional ticket is not a ticket-granting ticket");
1313 ret
= KRB5KDC_ERR_POLICY
;
1316 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1317 if(t
->enc_part
.kvno
){
1318 second_kvno
= *t
->enc_part
.kvno
;
1319 kvno_ptr
= &second_kvno
;
1321 ret
= _kdc_db_fetch(context
, config
, p
,
1322 HDB_F_GET_KRBTGT
, kvno_ptr
,
1324 krb5_free_principal(context
, p
);
1326 if (ret
== HDB_ERR_NOENTRY
)
1327 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1330 ret
= hdb_enctype2key(context
, &uu
->entry
,
1331 t
->enc_part
.etype
, &uukey
);
1333 _kdc_free_ent(context
, uu
);
1334 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1337 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1338 _kdc_free_ent(context
, uu
);
1342 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1348 } else if (s
== NULL
) {
1349 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1350 krb5_set_error_message(context
, ret
, "No server in request");
1354 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1355 ret
= krb5_unparse_name(context
, sp
, &spn
);
1358 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1359 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1362 unparse_flags (KDCOptions2int(b
->kdc_options
),
1363 asn1_KDCOptions_units(),
1364 opt_str
, sizeof(opt_str
));
1366 kdc_log(context
, config
, 0,
1367 "TGS-REQ %s from %s for %s [%s]",
1368 cpn
, from
, spn
, opt_str
);
1370 kdc_log(context
, config
, 0,
1371 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1378 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
| flags
,
1379 NULL
, NULL
, &server
);
1381 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
1382 kdc_log(context
, config
, 5, "target %s does not have secrets at this KDC, need to proxy", sp
);
1384 } else if (ret
== HDB_ERR_WRONG_REALM
) {
1387 ref_realm
= strdup(server
->entry
.principal
->realm
);
1388 if (ref_realm
== NULL
) {
1393 kdc_log(context
, config
, 5,
1394 "Returning a referral to realm %s for "
1397 krb5_free_principal(context
, sp
);
1401 ret
= krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1405 ret
= krb5_unparse_name(context
, sp
, &spn
);
1411 const char *new_rlm
, *msg
;
1415 if (!config
->autodetect_referrals
) {
1417 } else if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1419 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1421 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1422 "not found, trying %s",
1424 krb5_free_principal(context
, sp
);
1426 krb5_make_principal(context
, &sp
, r
,
1427 KRB5_TGS_NAME
, new_rlm
, NULL
);
1428 ret
= krb5_unparse_name(context
, sp
, &spn
);
1434 ref_realm
= strdup(new_rlm
);
1438 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1439 if (strcmp(realms
[0], sp
->realm
) != 0) {
1440 kdc_log(context
, config
, 5,
1441 "Returning a referral to realm %s for "
1442 "server %s that was not found",
1444 krb5_free_principal(context
, sp
);
1446 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1448 ret
= krb5_unparse_name(context
, sp
, &spn
);
1454 ref_realm
= strdup(realms
[0]);
1456 krb5_free_host_realm(context
, realms
);
1459 krb5_free_host_realm(context
, realms
);
1461 msg
= krb5_get_error_message(context
, ret
);
1462 kdc_log(context
, config
, 0,
1463 "Server not found in database: %s: %s", spn
, msg
);
1464 krb5_free_error_message(context
, msg
);
1465 if (ret
== HDB_ERR_NOENTRY
)
1466 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1471 * Select enctype, return key and kvno.
1477 if(b
->kdc_options
.enc_tkt_in_skey
) {
1480 for(i
= 0; i
< b
->etype
.len
; i
++)
1481 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1483 if(i
== b
->etype
.len
) {
1484 kdc_log(context
, config
, 0,
1485 "Addition ticket have not matching etypes");
1486 krb5_clear_error_message(context
);
1487 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1490 etype
= b
->etype
.val
[i
];
1495 ret
= _kdc_find_etype(context
,
1496 config
->tgs_use_strongest_session_key
, FALSE
,
1497 server
, b
->etype
.val
, b
->etype
.len
, NULL
,
1500 kdc_log(context
, config
, 0,
1501 "Server (%s) has no support for etypes", spn
);
1505 etype
= skey
->key
.keytype
;
1506 kvno
= server
->entry
.kvno
;
1509 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1515 * Check that service is in the same realm as the krbtgt. If it's
1516 * not the same, it's someone that is using a uni-directional trust
1521 * Validate authoriation data
1524 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1525 krbtgt_etype
, &tkey_check
);
1527 kdc_log(context
, config
, 0,
1528 "Failed to find key for krbtgt PAC check");
1532 /* Now refetch the primary krbtgt, and get the current kvno (the
1533 * sign check may have been on an old kvno, and the server may
1534 * have been an incoming trust) */
1535 ret
= krb5_make_principal(context
, &krbtgt_principal
,
1536 krb5_principal_get_comp_string(context
,
1537 krbtgt
->entry
.principal
,
1540 krb5_principal_get_comp_string(context
,
1541 krbtgt
->entry
.principal
,
1544 kdc_log(context
, config
, 0,
1545 "Failed to generate krbtgt principal");
1549 ret
= _kdc_db_fetch(context
, config
, krbtgt_principal
, HDB_F_GET_KRBTGT
, NULL
, NULL
, &krbtgt_out
);
1550 krb5_free_principal(context
, krbtgt_principal
);
1552 krb5_error_code ret2
;
1554 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &ktpn
);
1555 ret2
= krb5_unparse_name(context
, krbtgt_principal
, &ktpn2
);
1556 kdc_log(context
, config
, 0,
1557 "Request with wrong krbtgt: %s, %s not found in our database",
1558 (ret
== 0) ? ktpn
: "<unknown>", (ret2
== 0) ? ktpn2
: "<unknown>");
1563 ret
= KRB5KRB_AP_ERR_NOT_US
;
1567 /* The first realm is the realm of the service, the second is
1568 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1569 * encrypted to. The redirection via the krbtgt_out entry allows
1570 * the DB to possibly correct the case of the realm (Samba4 does
1571 * this) before the strcmp() */
1572 if (strcmp(krb5_principal_get_realm(context
, server
->entry
.principal
),
1573 krb5_principal_get_realm(context
, krbtgt_out
->entry
.principal
)) != 0) {
1575 ret
= krb5_unparse_name(context
, krbtgt_out
->entry
.principal
, &ktpn
);
1576 kdc_log(context
, config
, 0,
1577 "Request with wrong krbtgt: %s",
1578 (ret
== 0) ? ktpn
: "<unknown>");
1581 ret
= KRB5KRB_AP_ERR_NOT_US
;
1584 ret
= hdb_enctype2key(context
, &krbtgt_out
->entry
,
1585 krbtgt_etype
, &tkey_sign
);
1587 kdc_log(context
, config
, 0,
1588 "Failed to find key for krbtgt PAC signature");
1592 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| flags
,
1593 NULL
, &clientdb
, &client
);
1594 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
1595 /* This is OK, we are just trying to find out if they have
1596 * been disabled or deleted in the meantime, missing secrets
1599 const char *krbtgt_realm
, *msg
;
1602 * If the client belongs to the same realm as our krbtgt, it
1603 * should exist in the local database.
1607 krbtgt_realm
= krb5_principal_get_realm(context
, krbtgt_out
->entry
.principal
);
1609 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1610 if (ret
== HDB_ERR_NOENTRY
)
1611 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1612 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1617 msg
= krb5_get_error_message(context
, ret
);
1618 kdc_log(context
, config
, 1, "Client not found in database: %s", msg
);
1619 krb5_free_error_message(context
, msg
);
1622 ret
= check_PAC(context
, config
, cp
, NULL
,
1623 client
, server
, krbtgt
,
1625 ekey
, &tkey_sign
->key
,
1626 tgt
, &rspac
, &signedpath
);
1628 const char *msg
= krb5_get_error_message(context
, ret
);
1629 kdc_log(context
, config
, 0,
1630 "Verify PAC failed for %s (%s) from %s with %s",
1631 spn
, cpn
, from
, msg
);
1632 krb5_free_error_message(context
, msg
);
1640 /* by default the tgt principal matches the client principal */
1645 const PA_DATA
*sdata
;
1648 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1655 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1656 sdata
->padata_value
.length
,
1659 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1663 if (!krb5_checksum_is_keyed(context
, self
.cksum
.cksumtype
)) {
1664 free_PA_S4U2Self(&self
);
1665 kdc_log(context
, config
, 0, "Reject PA-S4U2Self with unkeyed checksum");
1666 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
1670 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1674 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1676 const char *msg
= krb5_get_error_message(context
, ret
);
1677 free_PA_S4U2Self(&self
);
1678 krb5_data_free(&datack
);
1679 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1680 krb5_free_error_message(context
, msg
);
1684 /* Allow HMAC_MD5 checksum with any key type */
1685 if (self
.cksum
.cksumtype
== CKSUMTYPE_HMAC_MD5
) {
1686 unsigned char csdata
[16];
1689 cs
.checksum
.length
= sizeof(csdata
);
1690 cs
.checksum
.data
= &csdata
;
1692 ret
= _krb5_HMAC_MD5_checksum(context
, &crypto
->key
,
1693 datack
.data
, datack
.length
,
1694 KRB5_KU_OTHER_CKSUM
, &cs
);
1696 krb5_data_ct_cmp(&cs
.checksum
, &self
.cksum
.checksum
) != 0)
1697 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
;
1700 ret
= krb5_verify_checksum(context
,
1702 KRB5_KU_OTHER_CKSUM
,
1707 krb5_data_free(&datack
);
1708 krb5_crypto_destroy(context
, crypto
);
1710 const char *msg
= krb5_get_error_message(context
, ret
);
1711 free_PA_S4U2Self(&self
);
1712 kdc_log(context
, config
, 0,
1713 "krb5_verify_checksum failed for S4U2Self: %s", msg
);
1714 krb5_free_error_message(context
, msg
);
1718 ret
= _krb5_principalname2krb5_principal(context
,
1722 free_PA_S4U2Self(&self
);
1726 ret
= krb5_unparse_name(context
, tp
, &tpn
);
1730 ret
= _kdc_db_fetch(context
, config
, tp
, HDB_F_GET_CLIENT
| flags
,
1731 NULL
, &s4u2self_impersonated_clientdb
,
1732 &s4u2self_impersonated_client
);
1737 * If the client belongs to the same realm as our krbtgt, it
1738 * should exist in the local database.
1742 if (ret
== HDB_ERR_NOENTRY
)
1743 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1744 msg
= krb5_get_error_message(context
, ret
);
1745 kdc_log(context
, config
, 1,
1746 "S2U4Self principal to impersonate %s not found in database: %s",
1748 krb5_free_error_message(context
, msg
);
1752 /* Ignore pw_end attributes (as Windows does),
1753 * since S4U2Self is not password authentication. */
1754 free(s4u2self_impersonated_client
->entry
.pw_end
);
1755 s4u2self_impersonated_client
->entry
.pw_end
= NULL
;
1757 ret
= kdc_check_flags(context
, config
, s4u2self_impersonated_client
, tpn
,
1762 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1765 krb5_data_free(&rspac
);
1766 ret
= _kdc_pac_generate(context
, s4u2self_impersonated_client
, NULL
, &p
);
1768 kdc_log(context
, config
, 0, "PAC generation failed for -- %s",
1773 ret
= _krb5_pac_sign(context
, p
, ticket
->ticket
.authtime
,
1774 s4u2self_impersonated_client
->entry
.principal
,
1775 ekey
, &tkey_sign
->key
,
1777 krb5_pac_free(context
, p
);
1779 kdc_log(context
, config
, 0, "PAC signing failed for -- %s",
1787 * Check that service doing the impersonating is
1788 * requesting a ticket to it-self.
1790 ret
= check_s4u2self(context
, config
, clientdb
, client
, sp
);
1792 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1793 "to impersonate to service "
1794 "(tried for user %s to service %s)",
1800 * If the service isn't trusted for authentication to
1801 * delegation or if the impersonate client is disallowed
1802 * forwardable, remove the forwardable flag.
1805 if (client
->entry
.flags
.trusted_for_delegation
&&
1806 s4u2self_impersonated_client
->entry
.flags
.forwardable
) {
1807 str
= "[forwardable]";
1809 b
->kdc_options
.forwardable
= 0;
1812 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
1813 "service %s %s", cpn
, tpn
, spn
, str
);
1818 * Constrained delegation
1822 && b
->additional_tickets
!= NULL
1823 && b
->additional_tickets
->len
!= 0
1824 && b
->kdc_options
.enc_tkt_in_skey
== 0)
1826 int ad_signedpath
= 0;
1831 * Require that the KDC have issued the service's krbtgt (not
1832 * self-issued ticket with kimpersonate(1).
1835 ret
= KRB5KDC_ERR_BADOPTION
;
1836 kdc_log(context
, config
, 0,
1837 "Constrained delegation done on service ticket %s/%s",
1842 t
= &b
->additional_tickets
->val
[0];
1844 ret
= hdb_enctype2key(context
, &client
->entry
,
1845 t
->enc_part
.etype
, &clientkey
);
1847 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1851 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
1853 kdc_log(context
, config
, 0,
1854 "failed to decrypt ticket for "
1855 "constrained delegation from %s to %s ", cpn
, spn
);
1859 ret
= _krb5_principalname2krb5_principal(context
,
1866 ret
= krb5_unparse_name(context
, tp
, &tpn
);
1870 ret
= _krb5_principalname2krb5_principal(context
,
1877 ret
= krb5_unparse_name(context
, dp
, &dpn
);
1881 /* check that ticket is valid */
1882 if (adtkt
.flags
.forwardable
== 0) {
1883 kdc_log(context
, config
, 0,
1884 "Missing forwardable flag on ticket for "
1885 "constrained delegation from %s (%s) as %s to %s ",
1886 cpn
, dpn
, tpn
, spn
);
1887 ret
= KRB5KDC_ERR_BADOPTION
;
1891 ret
= check_constrained_delegation(context
, config
, clientdb
,
1892 client
, server
, sp
);
1894 kdc_log(context
, config
, 0,
1895 "constrained delegation from %s (%s) as %s to %s not allowed",
1896 cpn
, dpn
, tpn
, spn
);
1900 ret
= verify_flags(context
, config
, &adtkt
, tpn
);
1905 krb5_data_free(&rspac
);
1908 * generate the PAC for the user.
1910 * TODO: pass in t->sname and t->realm and build
1911 * a S4U_DELEGATION_INFO blob to the PAC.
1913 ret
= check_PAC(context
, config
, tp
, dp
,
1914 client
, server
, krbtgt
,
1916 ekey
, &tkey_sign
->key
,
1917 &adtkt
, &rspac
, &ad_signedpath
);
1919 const char *msg
= krb5_get_error_message(context
, ret
);
1920 kdc_log(context
, config
, 0,
1921 "Verify delegated PAC failed to %s for client"
1922 "%s (%s) as %s from %s with %s",
1923 spn
, cpn
, dpn
, tpn
, from
, msg
);
1924 krb5_free_error_message(context
, msg
);
1928 if (!ad_signedpath
) {
1929 ret
= KRB5KDC_ERR_BADOPTION
;
1930 kdc_log(context
, config
, 0,
1931 "Ticket not signed with PAC nor SignedPath service %s failed "
1932 "for delegation to %s for client %s (%s)"
1934 spn
, tpn
, dpn
, cpn
, from
);
1938 kdc_log(context
, config
, 0, "constrained delegation for %s "
1939 "from %s (%s) to %s", tpn
, cpn
, dpn
, spn
);
1946 ret
= kdc_check_flags(context
, config
,
1953 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1954 !krb5_principal_compare(context
,
1955 krbtgt
->entry
.principal
,
1956 server
->entry
.principal
)){
1957 kdc_log(context
, config
, 0, "Inconsistent request.");
1958 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1962 /* check for valid set of addresses */
1963 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
1964 ret
= KRB5KRB_AP_ERR_BADADDR
;
1965 kdc_log(context
, config
, 0, "Request from wrong address");
1970 * If this is an referral, add server referral data to the
1977 kdc_log(context
, config
, 0,
1978 "Adding server referral to %s", ref_realm
);
1980 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1984 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1985 NULL
, s
, &pa
.padata_value
);
1986 krb5_crypto_destroy(context
, crypto
);
1988 kdc_log(context
, config
, 0,
1989 "Failed building server referral");
1992 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1994 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
1995 krb5_data_free(&pa
.padata_value
);
1997 kdc_log(context
, config
, 0,
1998 "Add server referral METHOD-DATA failed");
2007 ret
= tgs_make_reply(context
,
2019 server
->entry
.principal
,
2038 krb5_data_free(&rspac
);
2039 krb5_free_keyblock_contents(context
, &sessionkey
);
2041 _kdc_free_ent(context
, krbtgt_out
);
2043 _kdc_free_ent(context
, server
);
2045 _kdc_free_ent(context
, client
);
2046 if(s4u2self_impersonated_client
)
2047 _kdc_free_ent(context
, s4u2self_impersonated_client
);
2050 krb5_free_principal(context
, tp
);
2052 krb5_free_principal(context
, cp
);
2054 krb5_free_principal(context
, dp
);
2056 krb5_free_principal(context
, sp
);
2059 free_METHOD_DATA(&enc_pa_data
);
2061 free_EncTicketPart(&adtkt
);
2071 _kdc_tgs_rep(krb5_context context
,
2072 krb5_kdc_configuration
*config
,
2076 struct sockaddr
*from_addr
,
2079 AuthorizationData
*auth_data
= NULL
;
2080 krb5_error_code ret
;
2082 const PA_DATA
*tgs_req
;
2084 hdb_entry_ex
*krbtgt
= NULL
;
2085 krb5_ticket
*ticket
= NULL
;
2086 const char *e_text
= NULL
;
2087 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2089 krb5_keyblock
*replykey
= NULL
;
2090 int rk_is_subkey
= 0;
2091 time_t *csec
= NULL
;
2094 if(req
->padata
== NULL
){
2095 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2096 kdc_log(context
, config
, 0,
2097 "TGS-REQ from %s without PA-DATA", from
);
2101 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2103 if(tgs_req
== NULL
){
2104 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2106 kdc_log(context
, config
, 0,
2107 "TGS-REQ from %s without PA-TGS-REQ", from
);
2110 ret
= tgs_parse_request(context
, config
,
2111 &req
->req_body
, tgs_req
,
2121 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2122 /* kdc_log() is called in tgs_parse_request() */
2126 kdc_log(context
, config
, 0,
2127 "Failed parsing TGS-REQ from %s", from
);
2131 ret
= tgs_build_reply(context
,
2146 kdc_log(context
, config
, 0,
2147 "Failed building TGS-REP to %s", from
);
2152 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2153 krb5_data_free(data
);
2154 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2155 e_text
= "Reply packet too large";
2160 krb5_free_keyblock(context
, replykey
);
2161 if(ret
&& ret
!= HDB_ERR_NOT_FOUND_HERE
&& data
->data
== NULL
){
2162 krb5_mk_error(context
,
2176 krb5_free_ticket(context
, ticket
);
2178 _kdc_free_ent(context
, krbtgt
);
2181 free_AuthorizationData(auth_data
);