1 /* $NetBSD: krb5tgs.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $ */
4 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * return the realm of a krbtgt-ticket or NULL
43 get_krbtgt_realm(const PrincipalName
*p
)
45 if(p
->name_string
.len
== 2
46 && strcmp(p
->name_string
.val
[0], KRB5_TGS_NAME
) == 0)
47 return p
->name_string
.val
[1];
53 * The KDC might add a signed path to the ticket authorization data
54 * field. This is to avoid server impersonating clients and the
55 * request constrained delegation.
57 * This is done by storing a KRB5_AUTHDATA_IF_RELEVANT with a single
58 * entry of type KRB5SignedPath.
61 static krb5_error_code
62 find_KRB5SignedPath(krb5_context context
,
63 const AuthorizationData
*ad
,
66 AuthorizationData child
;
70 if (ad
== NULL
|| ad
->len
== 0)
71 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
75 if (ad
->val
[pos
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
76 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
78 ret
= decode_AuthorizationData(ad
->val
[pos
].ad_data
.data
,
79 ad
->val
[pos
].ad_data
.length
,
83 krb5_set_error_message(context
, ret
, "Failed to decode "
84 "IF_RELEVANT with %d", ret
);
89 free_AuthorizationData(&child
);
90 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
93 if (child
.val
[0].ad_type
!= KRB5_AUTHDATA_SIGNTICKET
) {
94 free_AuthorizationData(&child
);
95 return KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
99 ret
= der_copy_octet_string(&child
.val
[0].ad_data
, data
);
100 free_AuthorizationData(&child
);
105 _kdc_add_KRB5SignedPath(krb5_context context
,
106 krb5_kdc_configuration
*config
,
107 hdb_entry_ex
*krbtgt
,
108 krb5_enctype enctype
,
109 krb5_principal client
,
110 krb5_const_principal server
,
111 krb5_principals principals
,
117 krb5_crypto crypto
= NULL
;
120 if (server
&& principals
) {
121 ret
= add_Principals(principals
, server
);
127 KRB5SignedPathData spd
;
130 spd
.authtime
= tkt
->authtime
;
131 spd
.delegated
= principals
;
132 spd
.method_data
= NULL
;
134 ASN1_MALLOC_ENCODE(KRB5SignedPathData
, data
.data
, data
.length
,
138 if (data
.length
!= size
)
139 krb5_abortx(context
, "internal asn.1 encoder error");
144 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, enctype
, &key
);
146 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
154 * Fill in KRB5SignedPath
158 sp
.delegated
= principals
;
159 sp
.method_data
= NULL
;
161 ret
= krb5_create_checksum(context
, crypto
, KRB5_KU_KRB5SIGNEDPATH
, 0,
162 data
.data
, data
.length
, &sp
.cksum
);
163 krb5_crypto_destroy(context
, crypto
);
168 ASN1_MALLOC_ENCODE(KRB5SignedPath
, data
.data
, data
.length
, &sp
, &size
, ret
);
169 free_Checksum(&sp
.cksum
);
172 if (data
.length
!= size
)
173 krb5_abortx(context
, "internal asn.1 encoder error");
177 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
178 * authorization data field.
181 ret
= _kdc_tkt_add_if_relevant_ad(context
, tkt
,
182 KRB5_AUTHDATA_SIGNTICKET
, &data
);
183 krb5_data_free(&data
);
188 static krb5_error_code
189 check_KRB5SignedPath(krb5_context context
,
190 krb5_kdc_configuration
*config
,
191 hdb_entry_ex
*krbtgt
,
194 krb5_principals
*delegated
,
199 krb5_crypto crypto
= NULL
;
204 ret
= find_KRB5SignedPath(context
, tkt
->authorization_data
, &data
);
206 KRB5SignedPathData spd
;
210 ret
= decode_KRB5SignedPath(data
.data
, data
.length
, &sp
, NULL
);
211 krb5_data_free(&data
);
216 spd
.authtime
= tkt
->authtime
;
217 spd
.delegated
= sp
.delegated
;
218 spd
.method_data
= sp
.method_data
;
220 ASN1_MALLOC_ENCODE(KRB5SignedPathData
, data
.data
, data
.length
,
223 free_KRB5SignedPath(&sp
);
226 if (data
.length
!= size
)
227 krb5_abortx(context
, "internal asn.1 encoder error");
231 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, sp
.etype
, &key
);
233 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
236 free_KRB5SignedPath(&sp
);
240 ret
= krb5_verify_checksum(context
, crypto
, KRB5_KU_KRB5SIGNEDPATH
,
241 data
.data
, data
.length
,
243 krb5_crypto_destroy(context
, crypto
);
246 free_KRB5SignedPath(&sp
);
247 kdc_log(context
, config
, 5,
248 "KRB5SignedPath not signed correctly, not marking as signed");
252 if (delegated
&& sp
.delegated
) {
254 *delegated
= malloc(sizeof(*sp
.delegated
));
255 if (*delegated
== NULL
) {
256 free_KRB5SignedPath(&sp
);
260 ret
= copy_Principals(*delegated
, sp
.delegated
);
262 free_KRB5SignedPath(&sp
);
268 free_KRB5SignedPath(&sp
);
280 static krb5_error_code
281 check_PAC(krb5_context context
,
282 krb5_kdc_configuration
*config
,
283 const krb5_principal client_principal
,
284 const krb5_principal delegated_proxy_principal
,
285 hdb_entry_ex
*client
,
286 hdb_entry_ex
*server
,
287 hdb_entry_ex
*krbtgt
,
288 const EncryptionKey
*server_check_key
,
289 const EncryptionKey
*krbtgt_check_key
,
290 const EncryptionKey
*server_sign_key
,
291 const EncryptionKey
*krbtgt_sign_key
,
296 AuthorizationData
*ad
= tkt
->authorization_data
;
300 if (ad
== NULL
|| ad
->len
== 0)
303 for (i
= 0; i
< ad
->len
; i
++) {
304 AuthorizationData child
;
306 if (ad
->val
[i
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
309 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
310 ad
->val
[i
].ad_data
.length
,
314 krb5_set_error_message(context
, ret
, "Failed to decode "
315 "IF_RELEVANT with %d", ret
);
318 for (j
= 0; j
< child
.len
; j
++) {
320 if (child
.val
[j
].ad_type
== KRB5_AUTHDATA_WIN2K_PAC
) {
325 ret
= krb5_pac_parse(context
,
326 child
.val
[j
].ad_data
.data
,
327 child
.val
[j
].ad_data
.length
,
329 free_AuthorizationData(&child
);
333 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
,
335 server_check_key
, krbtgt_check_key
);
337 krb5_pac_free(context
, pac
);
341 ret
= _kdc_pac_verify(context
, client_principal
,
342 delegated_proxy_principal
,
343 client
, server
, krbtgt
, &pac
, &signed_pac
);
345 krb5_pac_free(context
, pac
);
350 * Only re-sign PAC if we could verify it with the PAC
351 * function. The no-verify case happens when we get in
352 * a PAC from cross realm from a Windows domain and
353 * that there is no PAC verification function.
357 ret
= _krb5_pac_sign(context
, pac
, tkt
->authtime
,
359 server_sign_key
, krbtgt_sign_key
, rspac
);
361 krb5_pac_free(context
, pac
);
366 free_AuthorizationData(&child
);
375 static krb5_error_code
376 check_tgs_flags(krb5_context context
,
377 krb5_kdc_configuration
*config
,
378 KDC_REQ_BODY
*b
, const EncTicketPart
*tgt
, EncTicketPart
*et
)
380 KDCOptions f
= b
->kdc_options
;
383 if(!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
){
384 kdc_log(context
, config
, 0,
385 "Bad request to validate ticket");
386 return KRB5KDC_ERR_BADOPTION
;
388 if(*tgt
->starttime
> kdc_time
){
389 kdc_log(context
, config
, 0,
390 "Early request to validate ticket");
391 return KRB5KRB_AP_ERR_TKT_NYV
;
394 et
->flags
.invalid
= 0;
395 }else if(tgt
->flags
.invalid
){
396 kdc_log(context
, config
, 0,
397 "Ticket-granting ticket has INVALID flag set");
398 return KRB5KRB_AP_ERR_TKT_INVALID
;
402 if(!tgt
->flags
.forwardable
){
403 kdc_log(context
, config
, 0,
404 "Bad request for forwardable ticket");
405 return KRB5KDC_ERR_BADOPTION
;
407 et
->flags
.forwardable
= 1;
410 if(!tgt
->flags
.forwardable
){
411 kdc_log(context
, config
, 0,
412 "Request to forward non-forwardable ticket");
413 return KRB5KDC_ERR_BADOPTION
;
415 et
->flags
.forwarded
= 1;
416 et
->caddr
= b
->addresses
;
418 if(tgt
->flags
.forwarded
)
419 et
->flags
.forwarded
= 1;
422 if(!tgt
->flags
.proxiable
){
423 kdc_log(context
, config
, 0,
424 "Bad request for proxiable ticket");
425 return KRB5KDC_ERR_BADOPTION
;
427 et
->flags
.proxiable
= 1;
430 if(!tgt
->flags
.proxiable
){
431 kdc_log(context
, config
, 0,
432 "Request to proxy non-proxiable ticket");
433 return KRB5KDC_ERR_BADOPTION
;
436 et
->caddr
= b
->addresses
;
441 if(f
.allow_postdate
){
442 if(!tgt
->flags
.may_postdate
){
443 kdc_log(context
, config
, 0,
444 "Bad request for post-datable ticket");
445 return KRB5KDC_ERR_BADOPTION
;
447 et
->flags
.may_postdate
= 1;
450 if(!tgt
->flags
.may_postdate
){
451 kdc_log(context
, config
, 0,
452 "Bad request for postdated ticket");
453 return KRB5KDC_ERR_BADOPTION
;
456 *et
->starttime
= *b
->from
;
457 et
->flags
.postdated
= 1;
458 et
->flags
.invalid
= 1;
459 }else if(b
->from
&& *b
->from
> kdc_time
+ context
->max_skew
){
460 kdc_log(context
, config
, 0, "Ticket cannot be postdated");
461 return KRB5KDC_ERR_CANNOT_POSTDATE
;
465 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
466 kdc_log(context
, config
, 0,
467 "Bad request for renewable ticket");
468 return KRB5KDC_ERR_BADOPTION
;
470 et
->flags
.renewable
= 1;
471 ALLOC(et
->renew_till
);
472 _kdc_fix_time(&b
->rtime
);
473 *et
->renew_till
= *b
->rtime
;
477 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
478 kdc_log(context
, config
, 0,
479 "Request to renew non-renewable ticket");
480 return KRB5KDC_ERR_BADOPTION
;
482 old_life
= tgt
->endtime
;
484 old_life
-= *tgt
->starttime
;
486 old_life
-= tgt
->authtime
;
487 et
->endtime
= *et
->starttime
+ old_life
;
488 if (et
->renew_till
!= NULL
)
489 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
493 /* checks for excess flags */
494 if(f
.request_anonymous
&& !config
->allow_anonymous
){
495 kdc_log(context
, config
, 0,
496 "Request for anonymous ticket");
497 return KRB5KDC_ERR_BADOPTION
;
504 * Determine if constrained delegation is allowed from this client to this server
507 static krb5_error_code
508 check_constrained_delegation(krb5_context context
,
509 krb5_kdc_configuration
*config
,
511 hdb_entry_ex
*client
,
512 hdb_entry_ex
*server
,
513 krb5_const_principal target
)
515 const HDB_Ext_Constrained_delegation_acl
*acl
;
520 * constrained_delegation (S4U2Proxy) only works within
521 * the same realm. We use the already canonicalized version
522 * of the principals here, while "target" is the principal
523 * provided by the client.
525 if(!krb5_realm_compare(context
, client
->entry
.principal
, server
->entry
.principal
)) {
526 ret
= KRB5KDC_ERR_BADOPTION
;
527 kdc_log(context
, config
, 0,
528 "Bad request for constrained delegation");
532 if (clientdb
->hdb_check_constrained_delegation
) {
533 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, target
);
537 /* if client delegates to itself, that ok */
538 if (krb5_principal_compare(context
, client
->entry
.principal
, server
->entry
.principal
) == TRUE
)
541 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
543 krb5_clear_error_message(context
);
548 for (i
= 0; i
< acl
->len
; i
++) {
549 if (krb5_principal_compare(context
, target
, &acl
->val
[i
]) == TRUE
)
553 ret
= KRB5KDC_ERR_BADOPTION
;
555 kdc_log(context
, config
, 0,
556 "Bad request for constrained delegation");
561 * Determine if s4u2self is allowed from this client to this server
563 * For example, regardless of the principal being impersonated, if the
564 * 'client' and 'server' are the same, then it's safe.
567 static krb5_error_code
568 check_s4u2self(krb5_context context
,
569 krb5_kdc_configuration
*config
,
571 hdb_entry_ex
*client
,
572 krb5_const_principal server
)
576 /* if client does a s4u2self to itself, that ok */
577 if (krb5_principal_compare(context
, client
->entry
.principal
, server
) == TRUE
)
580 if (clientdb
->hdb_check_s4u2self
) {
581 ret
= clientdb
->hdb_check_s4u2self(context
, clientdb
, client
, server
);
585 ret
= KRB5KDC_ERR_BADOPTION
;
594 static krb5_error_code
595 verify_flags (krb5_context context
,
596 krb5_kdc_configuration
*config
,
597 const EncTicketPart
*et
,
600 if(et
->endtime
< kdc_time
){
601 kdc_log(context
, config
, 0, "Ticket expired (%s)", pstr
);
602 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
604 if(et
->flags
.invalid
){
605 kdc_log(context
, config
, 0, "Ticket not valid (%s)", pstr
);
606 return KRB5KRB_AP_ERR_TKT_NYV
;
615 static krb5_error_code
616 fix_transited_encoding(krb5_context context
,
617 krb5_kdc_configuration
*config
,
618 krb5_boolean check_policy
,
619 const TransitedEncoding
*tr
,
621 const char *client_realm
,
622 const char *server_realm
,
623 const char *tgt_realm
)
625 krb5_error_code ret
= 0;
626 char **realms
, **tmp
;
627 unsigned int num_realms
;
630 switch (tr
->tr_type
) {
631 case DOMAIN_X500_COMPRESS
:
635 * Allow empty content of type 0 because that is was Microsoft
636 * generates in their TGT.
638 if (tr
->contents
.length
== 0)
640 kdc_log(context
, config
, 0,
641 "Transited type 0 with non empty content");
642 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
644 kdc_log(context
, config
, 0,
645 "Unknown transited type: %u", tr
->tr_type
);
646 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
649 ret
= krb5_domain_x500_decode(context
,
656 krb5_warn(context
, ret
,
657 "Decoding transited encoding");
660 if(strcmp(client_realm
, tgt_realm
) && strcmp(server_realm
, tgt_realm
)) {
661 /* not us, so add the previous realm to transited set */
662 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
666 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
672 realms
[num_realms
] = strdup(tgt_realm
);
673 if(realms
[num_realms
] == NULL
){
679 if(num_realms
== 0) {
680 if(strcmp(client_realm
, server_realm
))
681 kdc_log(context
, config
, 0,
682 "cross-realm %s -> %s", client_realm
, server_realm
);
686 for(i
= 0; i
< num_realms
; i
++)
687 l
+= strlen(realms
[i
]) + 2;
691 for(i
= 0; i
< num_realms
; i
++) {
693 strlcat(rs
, ", ", l
);
694 strlcat(rs
, realms
[i
], l
);
696 kdc_log(context
, config
, 0,
697 "cross-realm %s -> %s via [%s]",
698 client_realm
, server_realm
, rs
);
703 ret
= krb5_check_transited(context
, client_realm
,
705 realms
, num_realms
, NULL
);
707 krb5_warn(context
, ret
, "cross-realm %s -> %s",
708 client_realm
, server_realm
);
711 et
->flags
.transited_policy_checked
= 1;
713 et
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
714 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
716 krb5_warn(context
, ret
, "Encoding transited encoding");
718 for(i
= 0; i
< num_realms
; i
++)
725 static krb5_error_code
726 tgs_make_reply(krb5_context context
,
727 krb5_kdc_configuration
*config
,
729 krb5_const_principal tgt_name
,
730 const EncTicketPart
*tgt
,
731 const krb5_keyblock
*replykey
,
733 const EncryptionKey
*serverkey
,
734 const krb5_keyblock
*sessionkey
,
736 AuthorizationData
*auth_data
,
737 hdb_entry_ex
*server
,
738 krb5_principal server_principal
,
739 const char *server_name
,
740 hdb_entry_ex
*client
,
741 krb5_principal client_principal
,
742 hdb_entry_ex
*krbtgt
,
743 krb5_enctype krbtgt_etype
,
745 const krb5_data
*rspac
,
746 const METHOD_DATA
*enc_pa_data
,
753 KDCOptions f
= b
->kdc_options
;
757 memset(&rep
, 0, sizeof(rep
));
758 memset(&et
, 0, sizeof(et
));
759 memset(&ek
, 0, sizeof(ek
));
762 rep
.msg_type
= krb_tgs_rep
;
764 et
.authtime
= tgt
->authtime
;
765 _kdc_fix_time(&b
->till
);
766 et
.endtime
= min(tgt
->endtime
, *b
->till
);
768 *et
.starttime
= kdc_time
;
770 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
774 /* We should check the transited encoding if:
775 1) the request doesn't ask not to be checked
776 2) globally enforcing a check
777 3) principal requires checking
778 4) we allow non-check per-principal, but principal isn't marked as allowing this
779 5) we don't globally allow this
782 #define GLOBAL_FORCE_TRANSITED_CHECK \
783 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
784 #define GLOBAL_ALLOW_PER_PRINCIPAL \
785 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
786 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
787 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
789 /* these will consult the database in future release */
790 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
791 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
793 ret
= fix_transited_encoding(context
, config
,
794 !f
.disable_transited_check
||
795 GLOBAL_FORCE_TRANSITED_CHECK
||
796 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
797 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
798 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
799 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
800 &tgt
->transited
, &et
,
801 krb5_principal_get_realm(context
, client_principal
),
802 krb5_principal_get_realm(context
, server
->entry
.principal
),
803 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
));
807 copy_Realm(&server_principal
->realm
, &rep
.ticket
.realm
);
808 _krb5_principal2principalname(&rep
.ticket
.sname
, server_principal
);
809 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
811 if (f.request_anonymous)
812 _kdc_make_anonymous_principalname (&rep.cname);
815 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
816 rep
.ticket
.tkt_vno
= 5;
820 et
.caddr
= tgt
->caddr
;
824 life
= et
.endtime
- *et
.starttime
;
825 if(client
&& client
->entry
.max_life
)
826 life
= min(life
, *client
->entry
.max_life
);
827 if(server
->entry
.max_life
)
828 life
= min(life
, *server
->entry
.max_life
);
829 et
.endtime
= *et
.starttime
+ life
;
831 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
832 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
&&
833 tgt
->renew_till
!= NULL
)
835 et
.flags
.renewable
= 1;
836 ALLOC(et
.renew_till
);
837 *et
.renew_till
= *b
->till
;
841 renew
= *et
.renew_till
- *et
.starttime
;
842 if(client
&& client
->entry
.max_renew
)
843 renew
= min(renew
, *client
->entry
.max_renew
);
844 if(server
->entry
.max_renew
)
845 renew
= min(renew
, *server
->entry
.max_renew
);
846 *et
.renew_till
= *et
.starttime
+ renew
;
850 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
851 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
852 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
855 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
857 if(*et
.starttime
== et
.endtime
){
858 ret
= KRB5KDC_ERR_NEVER_VALID
;
861 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
863 et
.renew_till
= NULL
;
864 et
.flags
.renewable
= 0;
867 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
868 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
869 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
870 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
874 * No not need to filter out the any PAC from the
875 * auth_data since it's signed by the KDC.
877 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
878 KRB5_AUTHDATA_WIN2K_PAC
, rspac
);
886 /* XXX check authdata */
888 if (et
.authorization_data
== NULL
) {
889 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
890 if (et
.authorization_data
== NULL
) {
892 krb5_set_error_message(context
, ret
, "malloc: out of memory");
896 for(i
= 0; i
< auth_data
->len
; i
++) {
897 ret
= add_AuthorizationData(et
.authorization_data
, &auth_data
->val
[i
]);
899 krb5_set_error_message(context
, ret
, "malloc: out of memory");
904 /* Filter out type KRB5SignedPath */
905 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
907 if (et
.authorization_data
->len
== 1) {
908 free_AuthorizationData(et
.authorization_data
);
909 free(et
.authorization_data
);
910 et
.authorization_data
= NULL
;
912 AuthorizationData
*ad
= et
.authorization_data
;
913 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
919 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
922 et
.crealm
= tgt_name
->realm
;
923 et
.cname
= tgt_name
->name
;
926 /* MIT must have at least one last_req */
928 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
929 if (ek
.last_req
.val
== NULL
) {
935 ek
.authtime
= et
.authtime
;
936 ek
.starttime
= et
.starttime
;
937 ek
.endtime
= et
.endtime
;
938 ek
.renew_till
= et
.renew_till
;
939 ek
.srealm
= rep
.ticket
.realm
;
940 ek
.sname
= rep
.ticket
.sname
;
942 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
943 et
.endtime
, et
.renew_till
);
945 /* Don't sign cross realm tickets, they can't be checked anyway */
947 char *r
= get_krbtgt_realm(&ek
.sname
);
949 if (r
== NULL
|| strcmp(r
, ek
.srealm
) == 0) {
950 ret
= _kdc_add_KRB5SignedPath(context
,
963 if (enc_pa_data
->len
) {
964 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
965 if (rep
.padata
== NULL
) {
969 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
974 if (krb5_enctype_valid(context
, serverkey
->keytype
) != 0
975 && _kdc_is_weak_exception(server
->entry
.principal
, serverkey
->keytype
))
977 krb5_enctype_enable(context
, serverkey
->keytype
);
982 /* It is somewhat unclear where the etype in the following
983 encryption should come from. What we have is a session
984 key in the passed tgt, and a list of preferred etypes
985 *for the new ticket*. Should we pick the best possible
986 etype, given the keytype in the tgt, or should we look
987 at the etype list here as well? What if the tgt
988 session key is DES3 and we want a ticket with a (say)
989 CAST session key. Should the DES3 etype be added to the
990 etype list, even if we don't want a session key with
992 ret
= _kdc_encode_reply(context
, config
,
993 &rep
, &et
, &ek
, serverkey
->keytype
,
995 serverkey
, 0, replykey
, rk_is_subkey
,
998 krb5_enctype_disable(context
, serverkey
->keytype
);
1002 free_TransitedEncoding(&et
.transited
);
1006 free(et
.renew_till
);
1007 if(et
.authorization_data
) {
1008 free_AuthorizationData(et
.authorization_data
);
1009 free(et
.authorization_data
);
1011 free_LastReq(&ek
.last_req
);
1012 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
1013 free_EncryptionKey(&et
.key
);
1017 static krb5_error_code
1018 tgs_check_authenticator(krb5_context context
,
1019 krb5_kdc_configuration
*config
,
1020 krb5_auth_context ac
,
1022 const char **e_text
,
1025 krb5_authenticator auth
;
1029 krb5_error_code ret
;
1032 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1033 if(auth
->cksum
== NULL
){
1034 kdc_log(context
, config
, 0, "No authenticator in request");
1035 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
1039 * according to RFC1510 it doesn't need to be keyed,
1040 * but according to the latest draft it needs to.
1044 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
1047 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
1048 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
1049 auth
->cksum
->cksumtype
);
1050 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
1054 /* XXX should not re-encode this */
1055 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
1057 const char *msg
= krb5_get_error_message(context
, ret
);
1058 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s", msg
);
1059 krb5_free_error_message(context
, msg
);
1062 if(buf_size
!= len
) {
1064 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
1065 *e_text
= "KDC internal error";
1066 ret
= KRB5KRB_ERR_GENERIC
;
1069 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
1071 const char *msg
= krb5_get_error_message(context
, ret
);
1073 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1074 krb5_free_error_message(context
, msg
);
1077 ret
= krb5_verify_checksum(context
,
1079 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
1084 krb5_crypto_destroy(context
, crypto
);
1086 const char *msg
= krb5_get_error_message(context
, ret
);
1087 kdc_log(context
, config
, 0,
1088 "Failed to verify authenticator checksum: %s", msg
);
1089 krb5_free_error_message(context
, msg
);
1092 free_Authenticator(auth
);
1102 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1104 const char *new_realm
= krb5_config_get_string(context
,
1115 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1116 const KDCOptions
* const options
, krb5_principal server
,
1117 krb5_realm
**realms
)
1121 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
1124 if (server
->name
.name_string
.len
== 1)
1125 name
= server
->name
.name_string
.val
[0];
1126 else if (server
->name
.name_string
.len
> 1)
1127 name
= server
->name
.name_string
.val
[1];
1131 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
1133 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
1136 static krb5_error_code
1137 tgs_parse_request(krb5_context context
,
1138 krb5_kdc_configuration
*config
,
1140 const PA_DATA
*tgs_req
,
1141 hdb_entry_ex
**krbtgt
,
1142 krb5_enctype
*krbtgt_etype
,
1143 krb5_ticket
**ticket
,
1144 const char **e_text
,
1146 const struct sockaddr
*from_addr
,
1149 AuthorizationData
**auth_data
,
1150 krb5_keyblock
**replykey
,
1153 static char failed
[] = "<unparse_name failed>";
1155 krb5_error_code ret
;
1156 krb5_principal princ
;
1157 krb5_auth_context ac
= NULL
;
1158 krb5_flags ap_req_options
;
1159 krb5_flags verify_ap_req_flags
;
1162 krb5_keyblock
*subkey
= NULL
;
1170 memset(&ap_req
, 0, sizeof(ap_req
));
1171 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
1173 const char *msg
= krb5_get_error_message(context
, ret
);
1174 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s", msg
);
1175 krb5_free_error_message(context
, msg
);
1179 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1180 /* XXX check for ticket.sname == req.sname */
1181 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
1182 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1186 _krb5_principalname2krb5_principal(context
,
1188 ap_req
.ticket
.sname
,
1189 ap_req
.ticket
.realm
);
1191 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, ap_req
.ticket
.enc_part
.kvno
, NULL
, krbtgt
);
1193 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
1195 ret
= krb5_unparse_name(context
, princ
, &p
);
1198 krb5_free_principal(context
, princ
);
1199 kdc_log(context
, config
, 5, "Ticket-granting ticket account %s does not have secrets at this KDC, need to proxy", p
);
1202 ret
= HDB_ERR_NOT_FOUND_HERE
;
1205 const char *msg
= krb5_get_error_message(context
, ret
);
1207 ret
= krb5_unparse_name(context
, princ
, &p
);
1210 krb5_free_principal(context
, princ
);
1211 kdc_log(context
, config
, 0,
1212 "Ticket-granting ticket not found in database: %s", msg
);
1213 krb5_free_error_message(context
, msg
);
1216 ret
= KRB5KRB_AP_ERR_NOT_US
;
1220 if(ap_req
.ticket
.enc_part
.kvno
&&
1221 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
1224 ret
= krb5_unparse_name (context
, princ
, &p
);
1225 krb5_free_principal(context
, princ
);
1228 kdc_log(context
, config
, 0,
1229 "Ticket kvno = %d, DB kvno = %d (%s)",
1230 *ap_req
.ticket
.enc_part
.kvno
,
1231 (*krbtgt
)->entry
.kvno
,
1235 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1239 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1241 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1242 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1244 char *str
= NULL
, *p
= NULL
;
1246 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1247 krb5_unparse_name(context
, princ
, &p
);
1248 kdc_log(context
, config
, 0,
1249 "No server key with enctype %s found for %s",
1250 str
? str
: "<unknown enctype>",
1251 p
? p
: "<unparse_name failed>");
1254 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1258 if (b
->kdc_options
.validate
)
1259 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1261 verify_ap_req_flags
= 0;
1263 ret
= krb5_verify_ap_req2(context
,
1268 verify_ap_req_flags
,
1271 KRB5_KU_TGS_REQ_AUTH
);
1273 krb5_free_principal(context
, princ
);
1275 const char *msg
= krb5_get_error_message(context
, ret
);
1276 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s", msg
);
1277 krb5_free_error_message(context
, msg
);
1282 krb5_authenticator auth
;
1284 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1286 *csec
= malloc(sizeof(**csec
));
1287 if (*csec
== NULL
) {
1288 krb5_free_authenticator(context
, &auth
);
1289 kdc_log(context
, config
, 0, "malloc failed");
1292 **csec
= auth
->ctime
;
1293 *cusec
= malloc(sizeof(**cusec
));
1294 if (*cusec
== NULL
) {
1295 krb5_free_authenticator(context
, &auth
);
1296 kdc_log(context
, config
, 0, "malloc failed");
1299 **cusec
= auth
->cusec
;
1300 krb5_free_authenticator(context
, &auth
);
1304 ret
= tgs_check_authenticator(context
, config
,
1305 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1307 krb5_auth_con_free(context
, ac
);
1311 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1314 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
1316 const char *msg
= krb5_get_error_message(context
, ret
);
1317 krb5_auth_con_free(context
, ac
);
1318 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s", msg
);
1319 krb5_free_error_message(context
, msg
);
1323 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1326 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1328 const char *msg
= krb5_get_error_message(context
, ret
);
1329 krb5_auth_con_free(context
, ac
);
1330 kdc_log(context
, config
, 0, "Failed to get session key: %s", msg
);
1331 krb5_free_error_message(context
, msg
);
1336 krb5_auth_con_free(context
, ac
);
1337 kdc_log(context
, config
, 0,
1338 "Failed to get key for enc-authorization-data");
1339 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1345 if (b
->enc_authorization_data
) {
1348 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1350 const char *msg
= krb5_get_error_message(context
, ret
);
1351 krb5_auth_con_free(context
, ac
);
1352 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1353 krb5_free_error_message(context
, msg
);
1356 ret
= krb5_decrypt_EncryptedData (context
,
1359 b
->enc_authorization_data
,
1361 krb5_crypto_destroy(context
, crypto
);
1363 krb5_auth_con_free(context
, ac
);
1364 kdc_log(context
, config
, 0,
1365 "Failed to decrypt enc-authorization-data");
1366 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1370 if (*auth_data
== NULL
) {
1371 krb5_auth_con_free(context
, ac
);
1372 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1375 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1377 krb5_auth_con_free(context
, ac
);
1380 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1381 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1386 krb5_auth_con_free(context
, ac
);
1389 free_AP_REQ(&ap_req
);
1394 static krb5_error_code
1395 build_server_referral(krb5_context context
,
1396 krb5_kdc_configuration
*config
,
1397 krb5_crypto session
,
1398 krb5_const_realm referred_realm
,
1399 const PrincipalName
*true_principal_name
,
1400 const PrincipalName
*requested_principal
,
1403 PA_ServerReferralData ref
;
1404 krb5_error_code ret
;
1409 memset(&ref
, 0, sizeof(ref
));
1411 if (referred_realm
) {
1412 ALLOC(ref
.referred_realm
);
1413 if (ref
.referred_realm
== NULL
)
1415 *ref
.referred_realm
= strdup(referred_realm
);
1416 if (*ref
.referred_realm
== NULL
)
1419 if (true_principal_name
) {
1420 ALLOC(ref
.true_principal_name
);
1421 if (ref
.true_principal_name
== NULL
)
1423 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1427 if (requested_principal
) {
1428 ALLOC(ref
.requested_principal_name
);
1429 if (ref
.requested_principal_name
== NULL
)
1431 ret
= copy_PrincipalName(requested_principal
,
1432 ref
.requested_principal_name
);
1437 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1438 data
.data
, data
.length
,
1440 free_PA_ServerReferralData(&ref
);
1443 if (data
.length
!= size
)
1444 krb5_abortx(context
, "internal asn.1 encoder error");
1446 ret
= krb5_encrypt_EncryptedData(context
, session
,
1447 KRB5_KU_PA_SERVER_REFERRAL
,
1448 data
.data
, data
.length
,
1454 ASN1_MALLOC_ENCODE(EncryptedData
,
1455 outdata
->data
, outdata
->length
,
1457 free_EncryptedData(&ed
);
1460 if (outdata
->length
!= size
)
1461 krb5_abortx(context
, "internal asn.1 encoder error");
1465 free_PA_ServerReferralData(&ref
);
1466 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1470 static krb5_error_code
1471 tgs_build_reply(krb5_context context
,
1472 krb5_kdc_configuration
*config
,
1475 hdb_entry_ex
*krbtgt
,
1476 krb5_enctype krbtgt_etype
,
1477 const krb5_keyblock
*replykey
,
1479 krb5_ticket
*ticket
,
1482 const char **e_text
,
1483 AuthorizationData
**auth_data
,
1484 const struct sockaddr
*from_addr
)
1486 krb5_error_code ret
;
1487 krb5_principal cp
= NULL
, sp
= NULL
, rsp
= NULL
, tp
= NULL
, dp
= NULL
;
1488 krb5_principal krbtgt_principal
= NULL
;
1489 char *spn
= NULL
, *cpn
= NULL
, *tpn
= NULL
, *dpn
= NULL
;
1490 hdb_entry_ex
*server
= NULL
, *client
= NULL
, *s4u2self_impersonated_client
= NULL
;
1491 HDB
*clientdb
, *s4u2self_impersonated_clientdb
;
1492 krb5_realm ref_realm
= NULL
;
1493 EncTicketPart
*tgt
= &ticket
->ticket
;
1494 krb5_principals spp
= NULL
;
1495 const EncryptionKey
*ekey
;
1496 krb5_keyblock sessionkey
;
1500 hdb_entry_ex
*krbtgt_out
= NULL
;
1502 METHOD_DATA enc_pa_data
;
1507 EncTicketPart adtkt
;
1513 int flags
= HDB_F_FOR_TGS_REQ
;
1515 memset(&sessionkey
, 0, sizeof(sessionkey
));
1516 memset(&adtkt
, 0, sizeof(adtkt
));
1517 krb5_data_zero(&rspac
);
1518 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1524 * Always to do CANON, see comment below about returned server principal (rsp).
1526 flags
|= HDB_F_CANON
;
1528 if(b
->kdc_options
.enc_tkt_in_skey
){
1534 if(b
->additional_tickets
== NULL
||
1535 b
->additional_tickets
->len
== 0){
1536 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1537 kdc_log(context
, config
, 0,
1538 "No second ticket present in request");
1541 t
= &b
->additional_tickets
->val
[0];
1542 if(!get_krbtgt_realm(&t
->sname
)){
1543 kdc_log(context
, config
, 0,
1544 "Additional ticket is not a ticket-granting ticket");
1545 ret
= KRB5KDC_ERR_POLICY
;
1548 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1549 ret
= _kdc_db_fetch(context
, config
, p
,
1550 HDB_F_GET_KRBTGT
, t
->enc_part
.kvno
,
1552 krb5_free_principal(context
, p
);
1554 if (ret
== HDB_ERR_NOENTRY
)
1555 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1558 ret
= hdb_enctype2key(context
, &uu
->entry
,
1559 t
->enc_part
.etype
, &uukey
);
1561 _kdc_free_ent(context
, uu
);
1562 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1565 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1566 _kdc_free_ent(context
, uu
);
1570 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1578 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1579 ret
= krb5_unparse_name(context
, sp
, &spn
);
1582 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1583 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1586 unparse_flags (KDCOptions2int(b
->kdc_options
),
1587 asn1_KDCOptions_units(),
1588 opt_str
, sizeof(opt_str
));
1590 kdc_log(context
, config
, 0,
1591 "TGS-REQ %s from %s for %s [%s]",
1592 cpn
, from
, spn
, opt_str
);
1594 kdc_log(context
, config
, 0,
1595 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1602 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
| flags
,
1603 NULL
, NULL
, &server
);
1605 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
1606 kdc_log(context
, config
, 5, "target %s does not have secrets at this KDC, need to proxy", sp
);
1609 const char *new_rlm
, *msg
;
1613 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1615 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1617 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1618 "not found, trying %s",
1620 krb5_free_principal(context
, sp
);
1622 krb5_make_principal(context
, &sp
, r
,
1623 KRB5_TGS_NAME
, new_rlm
, NULL
);
1624 ret
= krb5_unparse_name(context
, sp
, &spn
);
1630 ref_realm
= strdup(new_rlm
);
1634 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1635 if (strcmp(realms
[0], sp
->realm
) != 0) {
1636 kdc_log(context
, config
, 5,
1637 "Returning a referral to realm %s for "
1638 "server %s that was not found",
1640 krb5_free_principal(context
, sp
);
1642 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1644 ret
= krb5_unparse_name(context
, sp
, &spn
);
1650 ref_realm
= strdup(realms
[0]);
1652 krb5_free_host_realm(context
, realms
);
1655 krb5_free_host_realm(context
, realms
);
1657 msg
= krb5_get_error_message(context
, ret
);
1658 kdc_log(context
, config
, 0,
1659 "Server not found in database: %s: %s", spn
, msg
);
1660 krb5_free_error_message(context
, msg
);
1661 if (ret
== HDB_ERR_NOENTRY
)
1662 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1666 /* the name returned to the client depend on what was asked for,
1667 * return canonical name if kdc_options.canonicalize was set, the
1668 * client wants the true name of the principal, if not it just
1669 * wants the name its asked for.
1672 if (b
->kdc_options
.canonicalize
)
1673 rsp
= server
->entry
.principal
;
1679 * Select enctype, return key and kvno.
1685 if(b
->kdc_options
.enc_tkt_in_skey
) {
1688 for(i
= 0; i
< b
->etype
.len
; i
++)
1689 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1691 if(i
== b
->etype
.len
) {
1692 kdc_log(context
, config
, 0,
1693 "Addition ticket have not matching etypes");
1694 krb5_clear_error_message(context
);
1695 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1698 etype
= b
->etype
.val
[i
];
1703 ret
= _kdc_find_etype(context
,
1704 krb5_principal_is_krbtgt(context
, sp
) ?
1705 config
->tgt_use_strongest_session_key
:
1706 config
->svc_use_strongest_session_key
, FALSE
,
1707 server
, b
->etype
.val
, b
->etype
.len
, &etype
,
1710 kdc_log(context
, config
, 0,
1711 "Server (%s) has no support for etypes", spn
);
1714 ret
= _kdc_get_preferred_key(context
, config
, server
, spn
,
1717 kdc_log(context
, config
, 0,
1718 "Server (%s) has no supported etypes", spn
);
1722 kvno
= server
->entry
.kvno
;
1725 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1731 * Check that service is in the same realm as the krbtgt. If it's
1732 * not the same, it's someone that is using a uni-directional trust
1737 * Validate authoriation data
1740 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1741 krbtgt_etype
, &tkey_check
);
1743 kdc_log(context
, config
, 0,
1744 "Failed to find key for krbtgt PAC check");
1748 /* Now refetch the primary krbtgt, and get the current kvno (the
1749 * sign check may have been on an old kvno, and the server may
1750 * have been an incoming trust) */
1751 ret
= krb5_make_principal(context
, &krbtgt_principal
,
1752 krb5_principal_get_comp_string(context
,
1753 krbtgt
->entry
.principal
,
1756 krb5_principal_get_comp_string(context
,
1757 krbtgt
->entry
.principal
,
1760 kdc_log(context
, config
, 0,
1761 "Failed to generate krbtgt principal");
1765 ret
= _kdc_db_fetch(context
, config
, krbtgt_principal
, HDB_F_GET_KRBTGT
, NULL
, NULL
, &krbtgt_out
);
1766 krb5_free_principal(context
, krbtgt_principal
);
1768 krb5_error_code ret2
;
1770 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &ktpn
);
1771 ret2
= krb5_unparse_name(context
, krbtgt_principal
, &ktpn2
);
1772 kdc_log(context
, config
, 0,
1773 "Request with wrong krbtgt: %s, %s not found in our database",
1774 (ret
== 0) ? ktpn
: "<unknown>", (ret2
== 0) ? ktpn2
: "<unknown>");
1779 ret
= KRB5KRB_AP_ERR_NOT_US
;
1783 /* The first realm is the realm of the service, the second is
1784 * krbtgt/<this>/@REALM component of the krbtgt DN the request was
1785 * encrypted to. The redirection via the krbtgt_out entry allows
1786 * the DB to possibly correct the case of the realm (Samba4 does
1787 * this) before the strcmp() */
1788 if (strcmp(krb5_principal_get_realm(context
, server
->entry
.principal
),
1789 krb5_principal_get_realm(context
, krbtgt_out
->entry
.principal
)) != 0) {
1791 ret
= krb5_unparse_name(context
, krbtgt_out
->entry
.principal
, &ktpn
);
1792 kdc_log(context
, config
, 0,
1793 "Request with wrong krbtgt: %s",
1794 (ret
== 0) ? ktpn
: "<unknown>");
1797 ret
= KRB5KRB_AP_ERR_NOT_US
;
1800 ret
= hdb_enctype2key(context
, &krbtgt_out
->entry
,
1801 krbtgt_etype
, &tkey_sign
);
1803 kdc_log(context
, config
, 0,
1804 "Failed to find key for krbtgt PAC signature");
1808 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| flags
,
1809 NULL
, &clientdb
, &client
);
1810 if(ret
== HDB_ERR_NOT_FOUND_HERE
) {
1811 /* This is OK, we are just trying to find out if they have
1812 * been disabled or deleted in the meantime, missing secrets
1815 const char *krbtgt_realm
, *msg
;
1818 * If the client belongs to the same realm as our krbtgt, it
1819 * should exist in the local database.
1823 krbtgt_realm
= krb5_principal_get_realm(context
, krbtgt_out
->entry
.principal
);
1825 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1826 if (ret
== HDB_ERR_NOENTRY
)
1827 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1828 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1833 msg
= krb5_get_error_message(context
, ret
);
1834 kdc_log(context
, config
, 1, "Client not found in database: %s", msg
);
1835 krb5_free_error_message(context
, msg
);
1838 ret
= check_PAC(context
, config
, cp
, NULL
,
1839 client
, server
, krbtgt
,
1840 &tkey_check
->key
, &tkey_check
->key
,
1841 ekey
, &tkey_sign
->key
,
1842 tgt
, &rspac
, &signedpath
);
1844 const char *msg
= krb5_get_error_message(context
, ret
);
1845 kdc_log(context
, config
, 0,
1846 "Verify PAC failed for %s (%s) from %s with %s",
1847 spn
, cpn
, from
, msg
);
1848 krb5_free_error_message(context
, msg
);
1852 /* also check the krbtgt for signature */
1853 ret
= check_KRB5SignedPath(context
,
1861 const char *msg
= krb5_get_error_message(context
, ret
);
1862 kdc_log(context
, config
, 0,
1863 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1864 spn
, cpn
, from
, msg
);
1865 krb5_free_error_message(context
, msg
);
1873 /* by default the tgt principal matches the client principal */
1878 const PA_DATA
*sdata
;
1881 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1888 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1889 sdata
->padata_value
.length
,
1892 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1896 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1900 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1902 const char *msg
= krb5_get_error_message(context
, ret
);
1903 free_PA_S4U2Self(&self
);
1904 krb5_data_free(&datack
);
1905 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s", msg
);
1906 krb5_free_error_message(context
, msg
);
1910 ret
= krb5_verify_checksum(context
,
1912 KRB5_KU_OTHER_CKSUM
,
1916 krb5_data_free(&datack
);
1917 krb5_crypto_destroy(context
, crypto
);
1919 const char *msg
= krb5_get_error_message(context
, ret
);
1920 free_PA_S4U2Self(&self
);
1921 kdc_log(context
, config
, 0,
1922 "krb5_verify_checksum failed for S4U2Self: %s", msg
);
1923 krb5_free_error_message(context
, msg
);
1927 ret
= _krb5_principalname2krb5_principal(context
,
1931 free_PA_S4U2Self(&self
);
1935 ret
= krb5_unparse_name(context
, tp
, &tpn
);
1939 /* If we were about to put a PAC into the ticket, we better fix it to be the right PAC */
1942 krb5_data_free(&rspac
);
1943 ret
= _kdc_db_fetch(context
, config
, tp
, HDB_F_GET_CLIENT
| flags
,
1944 NULL
, &s4u2self_impersonated_clientdb
, &s4u2self_impersonated_client
);
1949 * If the client belongs to the same realm as our krbtgt, it
1950 * should exist in the local database.
1954 if (ret
== HDB_ERR_NOENTRY
)
1955 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1956 msg
= krb5_get_error_message(context
, ret
);
1957 kdc_log(context
, config
, 1,
1958 "S2U4Self principal to impersonate %s not found in database: %s",
1960 krb5_free_error_message(context
, msg
);
1963 ret
= _kdc_pac_generate(context
, s4u2self_impersonated_client
, &p
);
1965 kdc_log(context
, config
, 0, "PAC generation failed for -- %s",
1970 ret
= _krb5_pac_sign(context
, p
, ticket
->ticket
.authtime
,
1971 s4u2self_impersonated_client
->entry
.principal
,
1972 ekey
, &tkey_sign
->key
,
1974 krb5_pac_free(context
, p
);
1976 kdc_log(context
, config
, 0, "PAC signing failed for -- %s",
1984 * Check that service doing the impersonating is
1985 * requesting a ticket to it-self.
1987 ret
= check_s4u2self(context
, config
, clientdb
, client
, sp
);
1989 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1990 "to impersonate to service "
1991 "(tried for user %s to service %s)",
1997 * If the service isn't trusted for authentication to
1998 * delegation, remove the forward flag.
2001 if (client
->entry
.flags
.trusted_for_delegation
) {
2002 str
= "[forwardable]";
2004 b
->kdc_options
.forwardable
= 0;
2007 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
2008 "service %s %s", cpn
, tpn
, spn
, str
);
2013 * Constrained delegation
2017 && b
->additional_tickets
!= NULL
2018 && b
->additional_tickets
->len
!= 0
2019 && b
->kdc_options
.enc_tkt_in_skey
== 0)
2021 int ad_signedpath
= 0;
2026 * Require that the KDC have issued the service's krbtgt (not
2027 * self-issued ticket with kimpersonate(1).
2030 ret
= KRB5KDC_ERR_BADOPTION
;
2031 kdc_log(context
, config
, 0,
2032 "Constrained delegation done on service ticket %s/%s",
2037 t
= &b
->additional_tickets
->val
[0];
2039 ret
= hdb_enctype2key(context
, &client
->entry
,
2040 t
->enc_part
.etype
, &clientkey
);
2042 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
2046 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
2048 kdc_log(context
, config
, 0,
2049 "failed to decrypt ticket for "
2050 "constrained delegation from %s to %s ", cpn
, spn
);
2054 ret
= _krb5_principalname2krb5_principal(context
,
2061 ret
= krb5_unparse_name(context
, tp
, &tpn
);
2065 ret
= _krb5_principalname2krb5_principal(context
,
2072 ret
= krb5_unparse_name(context
, dp
, &dpn
);
2076 /* check that ticket is valid */
2077 if (adtkt
.flags
.forwardable
== 0) {
2078 kdc_log(context
, config
, 0,
2079 "Missing forwardable flag on ticket for "
2080 "constrained delegation from %s (%s) as %s to %s ",
2081 cpn
, dpn
, tpn
, spn
);
2082 ret
= KRB5KDC_ERR_BADOPTION
;
2086 ret
= check_constrained_delegation(context
, config
, clientdb
,
2087 client
, server
, sp
);
2089 kdc_log(context
, config
, 0,
2090 "constrained delegation from %s (%s) as %s to %s not allowed",
2091 cpn
, dpn
, tpn
, spn
);
2095 ret
= verify_flags(context
, config
, &adtkt
, tpn
);
2100 krb5_data_free(&rspac
);
2103 * generate the PAC for the user.
2105 * TODO: pass in t->sname and t->realm and build
2106 * a S4U_DELEGATION_INFO blob to the PAC.
2108 ret
= check_PAC(context
, config
, tp
, dp
,
2109 client
, server
, krbtgt
,
2110 &clientkey
->key
, &tkey_check
->key
,
2111 ekey
, &tkey_sign
->key
,
2112 &adtkt
, &rspac
, &ad_signedpath
);
2114 const char *msg
= krb5_get_error_message(context
, ret
);
2115 kdc_log(context
, config
, 0,
2116 "Verify delegated PAC failed to %s for client"
2117 "%s (%s) as %s from %s with %s",
2118 spn
, cpn
, dpn
, tpn
, from
, msg
);
2119 krb5_free_error_message(context
, msg
);
2124 * Check that the KDC issued the user's ticket.
2126 ret
= check_KRB5SignedPath(context
,
2134 const char *msg
= krb5_get_error_message(context
, ret
);
2135 kdc_log(context
, config
, 0,
2136 "KRB5SignedPath check from service %s failed "
2137 "for delegation to %s for client %s (%s)"
2138 "from %s failed with %s",
2139 spn
, tpn
, dpn
, cpn
, from
, msg
);
2140 krb5_free_error_message(context
, msg
);
2144 if (!ad_signedpath
) {
2145 ret
= KRB5KDC_ERR_BADOPTION
;
2146 kdc_log(context
, config
, 0,
2147 "Ticket not signed with PAC nor SignedPath service %s failed "
2148 "for delegation to %s for client %s (%s)"
2150 spn
, tpn
, dpn
, cpn
, from
);
2154 kdc_log(context
, config
, 0, "constrained delegation for %s "
2155 "from %s (%s) to %s", tpn
, cpn
, dpn
, spn
);
2162 ret
= kdc_check_flags(context
, config
,
2169 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
2170 !krb5_principal_compare(context
,
2171 krbtgt
->entry
.principal
,
2172 server
->entry
.principal
)){
2173 kdc_log(context
, config
, 0, "Inconsistent request.");
2174 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
2178 /* check for valid set of addresses */
2179 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
2180 ret
= KRB5KRB_AP_ERR_BADADDR
;
2181 kdc_log(context
, config
, 0, "Request from wrong address");
2186 * If this is an referral, add server referral data to the
2193 kdc_log(context
, config
, 0,
2194 "Adding server referral to %s", ref_realm
);
2196 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
2200 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
2201 NULL
, s
, &pa
.padata_value
);
2202 krb5_crypto_destroy(context
, crypto
);
2204 kdc_log(context
, config
, 0,
2205 "Failed building server referral");
2208 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
2210 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
2211 krb5_data_free(&pa
.padata_value
);
2213 kdc_log(context
, config
, 0,
2214 "Add server referral METHOD-DATA failed");
2223 ret
= tgs_make_reply(context
,
2255 krb5_data_free(&rspac
);
2256 krb5_free_keyblock_contents(context
, &sessionkey
);
2258 _kdc_free_ent(context
, krbtgt_out
);
2260 _kdc_free_ent(context
, server
);
2262 _kdc_free_ent(context
, client
);
2263 if(s4u2self_impersonated_client
)
2264 _kdc_free_ent(context
, s4u2self_impersonated_client
);
2267 krb5_free_principal(context
, tp
);
2269 krb5_free_principal(context
, cp
);
2271 krb5_free_principal(context
, dp
);
2273 krb5_free_principal(context
, sp
);
2276 free_METHOD_DATA(&enc_pa_data
);
2278 free_EncTicketPart(&adtkt
);
2288 _kdc_tgs_rep(krb5_context context
,
2289 krb5_kdc_configuration
*config
,
2293 struct sockaddr
*from_addr
,
2296 AuthorizationData
*auth_data
= NULL
;
2297 krb5_error_code ret
;
2299 const PA_DATA
*tgs_req
;
2301 hdb_entry_ex
*krbtgt
= NULL
;
2302 krb5_ticket
*ticket
= NULL
;
2303 const char *e_text
= NULL
;
2304 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2306 krb5_keyblock
*replykey
= NULL
;
2307 int rk_is_subkey
= 0;
2308 time_t *csec
= NULL
;
2311 if(req
->padata
== NULL
){
2312 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2313 kdc_log(context
, config
, 0,
2314 "TGS-REQ from %s without PA-DATA", from
);
2318 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2320 if(tgs_req
== NULL
){
2321 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2323 kdc_log(context
, config
, 0,
2324 "TGS-REQ from %s without PA-TGS-REQ", from
);
2327 ret
= tgs_parse_request(context
, config
,
2328 &req
->req_body
, tgs_req
,
2338 if (ret
== HDB_ERR_NOT_FOUND_HERE
) {
2339 /* kdc_log() is called in tgs_parse_request() */
2343 kdc_log(context
, config
, 0,
2344 "Failed parsing TGS-REQ from %s", from
);
2348 ret
= tgs_build_reply(context
,
2363 kdc_log(context
, config
, 0,
2364 "Failed building TGS-REP to %s", from
);
2369 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2370 krb5_data_free(data
);
2371 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2372 e_text
= "Reply packet too large";
2377 krb5_free_keyblock(context
, replykey
);
2378 if(ret
&& ret
!= HDB_ERR_NOT_FOUND_HERE
&& data
->data
== NULL
){
2379 krb5_mk_error(context
,
2393 krb5_free_ticket(context
, ticket
);
2395 _kdc_free_ent(context
, krbtgt
);
2398 free_AuthorizationData(auth_data
);