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
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_const_principal server
,
110 krb5_principals principals
,
116 krb5_crypto crypto
= NULL
;
119 if (server
&& principals
) {
120 ret
= add_Principals(principals
, server
);
126 KRB5SignedPathData spd
;
128 spd
.encticket
= *tkt
;
129 spd
.delegated
= principals
;
131 ASN1_MALLOC_ENCODE(KRB5SignedPathData
, data
.data
, data
.length
,
135 if (data
.length
!= size
)
136 krb5_abortx(context
, "internal asn.1 encoder error");
141 ret
= hdb_enctype2key(context
, &krbtgt
->entry
, enctype
, &key
);
143 ret
= krb5_crypto_init(context
, &key
->key
, 0, &crypto
);
151 * Fill in KRB5SignedPath
155 sp
.delegated
= principals
;
157 ret
= krb5_create_checksum(context
, crypto
, KRB5_KU_KRB5SIGNEDPATH
, 0,
158 data
.data
, data
.length
, &sp
.cksum
);
159 krb5_crypto_destroy(context
, crypto
);
164 ASN1_MALLOC_ENCODE(KRB5SignedPath
, data
.data
, data
.length
, &sp
, &size
, ret
);
165 free_Checksum(&sp
.cksum
);
168 if (data
.length
!= size
)
169 krb5_abortx(context
, "internal asn.1 encoder error");
173 * Add IF-RELEVANT(KRB5SignedPath) to the last slot in
174 * authorization data field.
177 ret
= _kdc_tkt_add_if_relevant_ad(context
, tkt
,
178 KRB5_AUTHDATA_SIGNTICKET
, &data
);
179 krb5_data_free(&data
);
184 static krb5_error_code
185 check_KRB5SignedPath(krb5_context context
,
186 krb5_kdc_configuration
*config
,
187 hdb_entry_ex
*krbtgt
,
189 krb5_principals
*delegated
,
194 krb5_crypto crypto
= NULL
;
199 ret
= find_KRB5SignedPath(context
, tkt
->authorization_data
, &data
);
201 KRB5SignedPathData spd
;
203 AuthorizationData
*ad
;
206 ret
= decode_KRB5SignedPath(data
.data
, data
.length
, &sp
, NULL
);
207 krb5_data_free(&data
);
211 spd
.encticket
= *tkt
;
212 /* the KRB5SignedPath is the last entry */
213 ad
= spd
.encticket
.authorization_data
;
215 spd
.encticket
.authorization_data
= NULL
;
216 spd
.delegated
= sp
.delegated
;
218 ASN1_MALLOC_ENCODE(KRB5SignedPathData
, data
.data
, data
.length
,
221 spd
.encticket
.authorization_data
= ad
;
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
);
250 if (delegated
&& sp
.delegated
) {
252 *delegated
= malloc(sizeof(*sp
.delegated
));
253 if (*delegated
== NULL
) {
254 free_KRB5SignedPath(&sp
);
258 ret
= copy_Principals(*delegated
, sp
.delegated
);
260 free_KRB5SignedPath(&sp
);
266 free_KRB5SignedPath(&sp
);
278 static krb5_error_code
279 check_PAC(krb5_context context
,
280 krb5_kdc_configuration
*config
,
281 const krb5_principal client_principal
,
282 hdb_entry_ex
*client
,
283 hdb_entry_ex
*server
,
284 const EncryptionKey
*server_key
,
285 const EncryptionKey
*krbtgt_key
,
290 AuthorizationData
*ad
= tkt
->authorization_data
;
294 if (ad
== NULL
|| ad
->len
== 0)
297 for (i
= 0; i
< ad
->len
; i
++) {
298 AuthorizationData child
;
300 if (ad
->val
[i
].ad_type
!= KRB5_AUTHDATA_IF_RELEVANT
)
303 ret
= decode_AuthorizationData(ad
->val
[i
].ad_data
.data
,
304 ad
->val
[i
].ad_data
.length
,
308 krb5_set_error_message(context
, ret
, "Failed to decode "
309 "IF_RELEVANT with %d", ret
);
312 for (j
= 0; j
< child
.len
; j
++) {
314 if (child
.val
[j
].ad_type
== KRB5_AUTHDATA_WIN2K_PAC
) {
318 ret
= krb5_pac_parse(context
,
319 child
.val
[j
].ad_data
.data
,
320 child
.val
[j
].ad_data
.length
,
322 free_AuthorizationData(&child
);
326 ret
= krb5_pac_verify(context
, pac
, tkt
->authtime
,
330 krb5_pac_free(context
, pac
);
334 ret
= _kdc_pac_verify(context
, client_principal
,
335 client
, server
, &pac
);
337 krb5_pac_free(context
, pac
);
342 ret
= _krb5_pac_sign(context
, pac
, tkt
->authtime
,
344 server_key
, krbtgt_key
, rspac
);
346 krb5_pac_free(context
, pac
);
351 free_AuthorizationData(&child
);
360 static krb5_error_code
361 check_tgs_flags(krb5_context context
,
362 krb5_kdc_configuration
*config
,
363 KDC_REQ_BODY
*b
, const EncTicketPart
*tgt
, EncTicketPart
*et
)
365 KDCOptions f
= b
->kdc_options
;
368 if(!tgt
->flags
.invalid
|| tgt
->starttime
== NULL
){
369 kdc_log(context
, config
, 0,
370 "Bad request to validate ticket");
371 return KRB5KDC_ERR_BADOPTION
;
373 if(*tgt
->starttime
> kdc_time
){
374 kdc_log(context
, config
, 0,
375 "Early request to validate ticket");
376 return KRB5KRB_AP_ERR_TKT_NYV
;
379 et
->flags
.invalid
= 0;
380 }else if(tgt
->flags
.invalid
){
381 kdc_log(context
, config
, 0,
382 "Ticket-granting ticket has INVALID flag set");
383 return KRB5KRB_AP_ERR_TKT_INVALID
;
387 if(!tgt
->flags
.forwardable
){
388 kdc_log(context
, config
, 0,
389 "Bad request for forwardable ticket");
390 return KRB5KDC_ERR_BADOPTION
;
392 et
->flags
.forwardable
= 1;
395 if(!tgt
->flags
.forwardable
){
396 kdc_log(context
, config
, 0,
397 "Request to forward non-forwardable ticket");
398 return KRB5KDC_ERR_BADOPTION
;
400 et
->flags
.forwarded
= 1;
401 et
->caddr
= b
->addresses
;
403 if(tgt
->flags
.forwarded
)
404 et
->flags
.forwarded
= 1;
407 if(!tgt
->flags
.proxiable
){
408 kdc_log(context
, config
, 0,
409 "Bad request for proxiable ticket");
410 return KRB5KDC_ERR_BADOPTION
;
412 et
->flags
.proxiable
= 1;
415 if(!tgt
->flags
.proxiable
){
416 kdc_log(context
, config
, 0,
417 "Request to proxy non-proxiable ticket");
418 return KRB5KDC_ERR_BADOPTION
;
421 et
->caddr
= b
->addresses
;
426 if(f
.allow_postdate
){
427 if(!tgt
->flags
.may_postdate
){
428 kdc_log(context
, config
, 0,
429 "Bad request for post-datable ticket");
430 return KRB5KDC_ERR_BADOPTION
;
432 et
->flags
.may_postdate
= 1;
435 if(!tgt
->flags
.may_postdate
){
436 kdc_log(context
, config
, 0,
437 "Bad request for postdated ticket");
438 return KRB5KDC_ERR_BADOPTION
;
441 *et
->starttime
= *b
->from
;
442 et
->flags
.postdated
= 1;
443 et
->flags
.invalid
= 1;
444 }else if(b
->from
&& *b
->from
> kdc_time
+ context
->max_skew
){
445 kdc_log(context
, config
, 0, "Ticket cannot be postdated");
446 return KRB5KDC_ERR_CANNOT_POSTDATE
;
450 if(!tgt
->flags
.renewable
){
451 kdc_log(context
, config
, 0,
452 "Bad request for renewable ticket");
453 return KRB5KDC_ERR_BADOPTION
;
455 et
->flags
.renewable
= 1;
456 ALLOC(et
->renew_till
);
457 _kdc_fix_time(&b
->rtime
);
458 *et
->renew_till
= *b
->rtime
;
462 if(!tgt
->flags
.renewable
|| tgt
->renew_till
== NULL
){
463 kdc_log(context
, config
, 0,
464 "Request to renew non-renewable ticket");
465 return KRB5KDC_ERR_BADOPTION
;
467 old_life
= tgt
->endtime
;
469 old_life
-= *tgt
->starttime
;
471 old_life
-= tgt
->authtime
;
472 et
->endtime
= *et
->starttime
+ old_life
;
473 if (et
->renew_till
!= NULL
)
474 et
->endtime
= min(*et
->renew_till
, et
->endtime
);
478 /* checks for excess flags */
479 if(f
.request_anonymous
&& !config
->allow_anonymous
){
480 kdc_log(context
, config
, 0,
481 "Request for anonymous ticket");
482 return KRB5KDC_ERR_BADOPTION
;
492 static krb5_error_code
493 check_constrained_delegation(krb5_context context
,
494 krb5_kdc_configuration
*config
,
495 hdb_entry_ex
*client
,
496 krb5_const_principal server
)
498 const HDB_Ext_Constrained_delegation_acl
*acl
;
502 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
504 krb5_clear_error_message(context
);
509 for (i
= 0; i
< acl
->len
; i
++) {
510 if (krb5_principal_compare(context
, server
, &acl
->val
[i
]) == TRUE
)
514 kdc_log(context
, config
, 0,
515 "Bad request for constrained delegation");
516 return KRB5KDC_ERR_BADOPTION
;
523 static krb5_error_code
524 verify_flags (krb5_context context
,
525 krb5_kdc_configuration
*config
,
526 const EncTicketPart
*et
,
529 if(et
->endtime
< kdc_time
){
530 kdc_log(context
, config
, 0, "Ticket expired (%s)", pstr
);
531 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
533 if(et
->flags
.invalid
){
534 kdc_log(context
, config
, 0, "Ticket not valid (%s)", pstr
);
535 return KRB5KRB_AP_ERR_TKT_NYV
;
544 static krb5_error_code
545 fix_transited_encoding(krb5_context context
,
546 krb5_kdc_configuration
*config
,
547 krb5_boolean check_policy
,
548 const TransitedEncoding
*tr
,
550 const char *client_realm
,
551 const char *server_realm
,
552 const char *tgt_realm
)
554 krb5_error_code ret
= 0;
555 char **realms
, **tmp
;
556 unsigned int num_realms
;
559 switch (tr
->tr_type
) {
560 case DOMAIN_X500_COMPRESS
:
564 * Allow empty content of type 0 because that is was Microsoft
565 * generates in their TGT.
567 if (tr
->contents
.length
== 0)
569 kdc_log(context
, config
, 0,
570 "Transited type 0 with non empty content");
571 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
573 kdc_log(context
, config
, 0,
574 "Unknown transited type: %u", tr
->tr_type
);
575 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
578 ret
= krb5_domain_x500_decode(context
,
585 krb5_warn(context
, ret
,
586 "Decoding transited encoding");
589 if(strcmp(client_realm
, tgt_realm
) && strcmp(server_realm
, tgt_realm
)) {
590 /* not us, so add the previous realm to transited set */
591 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
595 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
601 realms
[num_realms
] = strdup(tgt_realm
);
602 if(realms
[num_realms
] == NULL
){
608 if(num_realms
== 0) {
609 if(strcmp(client_realm
, server_realm
))
610 kdc_log(context
, config
, 0,
611 "cross-realm %s -> %s", client_realm
, server_realm
);
615 for(i
= 0; i
< num_realms
; i
++)
616 l
+= strlen(realms
[i
]) + 2;
620 for(i
= 0; i
< num_realms
; i
++) {
622 strlcat(rs
, ", ", l
);
623 strlcat(rs
, realms
[i
], l
);
625 kdc_log(context
, config
, 0,
626 "cross-realm %s -> %s via [%s]",
627 client_realm
, server_realm
, rs
);
632 ret
= krb5_check_transited(context
, client_realm
,
634 realms
, num_realms
, NULL
);
636 krb5_warn(context
, ret
, "cross-realm %s -> %s",
637 client_realm
, server_realm
);
640 et
->flags
.transited_policy_checked
= 1;
642 et
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
643 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
645 krb5_warn(context
, ret
, "Encoding transited encoding");
647 for(i
= 0; i
< num_realms
; i
++)
654 static krb5_error_code
655 tgs_make_reply(krb5_context context
,
656 krb5_kdc_configuration
*config
,
658 krb5_const_principal tgt_name
,
659 const EncTicketPart
*tgt
,
660 const EncryptionKey
*serverkey
,
661 const krb5_keyblock
*sessionkey
,
663 AuthorizationData
*auth_data
,
664 hdb_entry_ex
*server
,
665 krb5_principal server_principal
,
666 const char *server_name
,
667 hdb_entry_ex
*client
,
668 krb5_principal client_principal
,
669 hdb_entry_ex
*krbtgt
,
670 krb5_enctype krbtgt_etype
,
672 const krb5_data
*rspac
,
673 const METHOD_DATA
*enc_pa_data
,
680 KDCOptions f
= b
->kdc_options
;
684 memset(&rep
, 0, sizeof(rep
));
685 memset(&et
, 0, sizeof(et
));
686 memset(&ek
, 0, sizeof(ek
));
689 rep
.msg_type
= krb_tgs_rep
;
691 et
.authtime
= tgt
->authtime
;
692 _kdc_fix_time(&b
->till
);
693 et
.endtime
= min(tgt
->endtime
, *b
->till
);
695 *et
.starttime
= kdc_time
;
697 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
701 /* We should check the transited encoding if:
702 1) the request doesn't ask not to be checked
703 2) globally enforcing a check
704 3) principal requires checking
705 4) we allow non-check per-principal, but principal isn't marked as allowing this
706 5) we don't globally allow this
709 #define GLOBAL_FORCE_TRANSITED_CHECK \
710 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
711 #define GLOBAL_ALLOW_PER_PRINCIPAL \
712 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
713 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
714 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
716 /* these will consult the database in future release */
717 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
718 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
720 ret
= fix_transited_encoding(context
, config
,
721 !f
.disable_transited_check
||
722 GLOBAL_FORCE_TRANSITED_CHECK
||
723 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
724 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
725 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
726 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
727 &tgt
->transited
, &et
,
728 krb5_principal_get_realm(context
, client_principal
),
729 krb5_principal_get_realm(context
, server
->entry
.principal
),
730 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
));
734 copy_Realm(&server_principal
->realm
, &rep
.ticket
.realm
);
735 _krb5_principal2principalname(&rep
.ticket
.sname
, server_principal
);
736 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
738 if (f.request_anonymous)
739 _kdc_make_anonymous_principalname (&rep.cname);
742 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
743 rep
.ticket
.tkt_vno
= 5;
747 et
.caddr
= tgt
->caddr
;
751 life
= et
.endtime
- *et
.starttime
;
752 if(client
&& client
->entry
.max_life
)
753 life
= min(life
, *client
->entry
.max_life
);
754 if(server
->entry
.max_life
)
755 life
= min(life
, *server
->entry
.max_life
);
756 et
.endtime
= *et
.starttime
+ life
;
758 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
759 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
){
760 et
.flags
.renewable
= 1;
761 ALLOC(et
.renew_till
);
762 *et
.renew_till
= *b
->till
;
766 renew
= *et
.renew_till
- et
.authtime
;
767 if(client
&& client
->entry
.max_renew
)
768 renew
= min(renew
, *client
->entry
.max_renew
);
769 if(server
->entry
.max_renew
)
770 renew
= min(renew
, *server
->entry
.max_renew
);
771 *et
.renew_till
= et
.authtime
+ renew
;
775 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
776 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
777 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
780 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
782 if(*et
.starttime
== et
.endtime
){
783 ret
= KRB5KDC_ERR_NEVER_VALID
;
786 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
788 et
.renew_till
= NULL
;
789 et
.flags
.renewable
= 0;
792 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
793 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
794 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
795 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
798 /* XXX Check enc-authorization-data */
799 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
800 if (et
.authorization_data
== NULL
) {
804 ret
= copy_AuthorizationData(auth_data
, et
.authorization_data
);
808 /* Filter out type KRB5SignedPath */
809 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
811 if (et
.authorization_data
->len
== 1) {
812 free_AuthorizationData(et
.authorization_data
);
813 free(et
.authorization_data
);
814 et
.authorization_data
= NULL
;
816 AuthorizationData
*ad
= et
.authorization_data
;
817 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
825 * No not need to filter out the any PAC from the
826 * auth_data since it's signed by the KDC.
828 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
829 KRB5_AUTHDATA_WIN2K_PAC
,
835 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
838 et
.crealm
= tgt
->crealm
;
839 et
.cname
= tgt_name
->name
;
842 /* MIT must have at least one last_req */
844 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
845 if (ek
.last_req
.val
== NULL
) {
851 ek
.authtime
= et
.authtime
;
852 ek
.starttime
= et
.starttime
;
853 ek
.endtime
= et
.endtime
;
854 ek
.renew_till
= et
.renew_till
;
855 ek
.srealm
= rep
.ticket
.realm
;
856 ek
.sname
= rep
.ticket
.sname
;
858 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
859 et
.endtime
, et
.renew_till
);
861 /* Don't sign cross realm tickets, they can't be checked anyway */
863 char *r
= get_krbtgt_realm(&ek
.sname
);
865 if (r
== NULL
|| strcmp(r
, ek
.srealm
) == 0) {
866 ret
= _kdc_add_KRB5SignedPath(context
,
878 if (enc_pa_data
->len
) {
879 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
880 if (rep
.padata
== NULL
) {
884 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
889 if (krb5_enctype_valid(context
, et
.key
.keytype
) != 0
890 && _kdc_is_weak_exception(server
->entry
.principal
, et
.key
.keytype
))
892 krb5_enctype_enable(context
, et
.key
.keytype
);
897 /* It is somewhat unclear where the etype in the following
898 encryption should come from. What we have is a session
899 key in the passed tgt, and a list of preferred etypes
900 *for the new ticket*. Should we pick the best possible
901 etype, given the keytype in the tgt, or should we look
902 at the etype list here as well? What if the tgt
903 session key is DES3 and we want a ticket with a (say)
904 CAST session key. Should the DES3 etype be added to the
905 etype list, even if we don't want a session key with
907 ret
= _kdc_encode_reply(context
, config
,
908 &rep
, &et
, &ek
, et
.key
.keytype
,
910 serverkey
, 0, &tgt
->key
, e_text
, reply
);
912 krb5_enctype_disable(context
, et
.key
.keytype
);
916 free_TransitedEncoding(&et
.transited
);
921 if(et
.authorization_data
) {
922 free_AuthorizationData(et
.authorization_data
);
923 free(et
.authorization_data
);
925 free_LastReq(&ek
.last_req
);
926 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
927 free_EncryptionKey(&et
.key
);
931 static krb5_error_code
932 tgs_check_authenticator(krb5_context context
,
933 krb5_kdc_configuration
*config
,
934 krb5_auth_context ac
,
939 krb5_authenticator auth
;
946 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
947 if(auth
->cksum
== NULL
){
948 kdc_log(context
, config
, 0, "No authenticator in request");
949 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
953 * according to RFC1510 it doesn't need to be keyed,
954 * but according to the latest draft it needs to.
958 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
961 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
962 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
963 auth
->cksum
->cksumtype
);
964 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
968 /* XXX should not re-encode this */
969 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
971 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s",
972 krb5_get_err_text(context
, ret
));
975 if(buf_size
!= len
) {
977 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
978 *e_text
= "KDC internal error";
979 ret
= KRB5KRB_ERR_GENERIC
;
982 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
985 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
986 krb5_get_err_text(context
, ret
));
989 ret
= krb5_verify_checksum(context
,
991 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
996 krb5_crypto_destroy(context
, crypto
);
998 kdc_log(context
, config
, 0,
999 "Failed to verify authenticator checksum: %s",
1000 krb5_get_err_text(context
, ret
));
1003 free_Authenticator(auth
);
1013 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1015 const char *new_realm
= krb5_config_get_string(context
,
1026 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1027 const KDCOptions
* const options
, krb5_principal server
,
1028 krb5_realm
**realms
)
1032 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
1035 if (server
->name
.name_string
.len
== 1)
1036 name
= server
->name
.name_string
.val
[0];
1037 if (server
->name
.name_string
.len
> 1)
1038 name
= server
->name
.name_string
.val
[1];
1042 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
1044 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
1047 static krb5_error_code
1048 tgs_parse_request(krb5_context context
,
1049 krb5_kdc_configuration
*config
,
1051 const PA_DATA
*tgs_req
,
1052 hdb_entry_ex
**krbtgt
,
1053 krb5_enctype
*krbtgt_etype
,
1054 krb5_ticket
**ticket
,
1055 const char **e_text
,
1057 const struct sockaddr
*from_addr
,
1060 AuthorizationData
**auth_data
)
1063 krb5_error_code ret
;
1064 krb5_principal princ
;
1065 krb5_auth_context ac
= NULL
;
1066 krb5_flags ap_req_options
;
1067 krb5_flags verify_ap_req_flags
;
1075 memset(&ap_req
, 0, sizeof(ap_req
));
1076 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
1078 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s",
1079 krb5_get_err_text(context
, ret
));
1083 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1084 /* XXX check for ticket.sname == req.sname */
1085 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
1086 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1090 _krb5_principalname2krb5_principal(context
,
1092 ap_req
.ticket
.sname
,
1093 ap_req
.ticket
.realm
);
1095 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, NULL
, krbtgt
);
1099 ret
= krb5_unparse_name(context
, princ
, &p
);
1101 p
= "<unparse_name failed>";
1102 krb5_free_principal(context
, princ
);
1103 kdc_log(context
, config
, 0,
1104 "Ticket-granting ticket not found in database: %s: %s",
1105 p
, krb5_get_err_text(context
, ret
));
1108 ret
= KRB5KRB_AP_ERR_NOT_US
;
1112 if(ap_req
.ticket
.enc_part
.kvno
&&
1113 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
1116 ret
= krb5_unparse_name (context
, princ
, &p
);
1117 krb5_free_principal(context
, princ
);
1119 p
= "<unparse_name failed>";
1120 kdc_log(context
, config
, 0,
1121 "Ticket kvno = %d, DB kvno = %d (%s)",
1122 *ap_req
.ticket
.enc_part
.kvno
,
1123 (*krbtgt
)->entry
.kvno
,
1127 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1131 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1133 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1134 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1136 char *str
= NULL
, *p
= NULL
;
1138 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1139 krb5_unparse_name(context
, princ
, &p
);
1140 kdc_log(context
, config
, 0,
1141 "No server key with enctype %s found for %s",
1142 str
? str
: "<unknown enctype>",
1143 p
? p
: "<unparse_name failed>");
1146 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1150 if (b
->kdc_options
.validate
)
1151 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1153 verify_ap_req_flags
= 0;
1155 ret
= krb5_verify_ap_req2(context
,
1160 verify_ap_req_flags
,
1163 KRB5_KU_TGS_REQ_AUTH
);
1165 krb5_free_principal(context
, princ
);
1167 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s",
1168 krb5_get_err_text(context
, ret
));
1173 krb5_authenticator auth
;
1175 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1177 *csec
= malloc(sizeof(**csec
));
1178 if (*csec
== NULL
) {
1179 krb5_free_authenticator(context
, &auth
);
1180 kdc_log(context
, config
, 0, "malloc failed");
1183 **csec
= auth
->ctime
;
1184 *cusec
= malloc(sizeof(**cusec
));
1185 if (*cusec
== NULL
) {
1186 krb5_free_authenticator(context
, &auth
);
1187 kdc_log(context
, config
, 0, "malloc failed");
1190 **cusec
= auth
->cusec
;
1191 krb5_free_authenticator(context
, &auth
);
1195 ret
= tgs_check_authenticator(context
, config
,
1196 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1198 krb5_auth_con_free(context
, ac
);
1202 if (b
->enc_authorization_data
) {
1203 unsigned usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1204 krb5_keyblock
*subkey
;
1207 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
1209 krb5_auth_con_free(context
, ac
);
1210 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s",
1211 krb5_get_err_text(context
, ret
));
1215 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1216 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1218 krb5_auth_con_free(context
, ac
);
1219 kdc_log(context
, config
, 0, "Failed to get session key: %s",
1220 krb5_get_err_text(context
, ret
));
1225 krb5_auth_con_free(context
, ac
);
1226 kdc_log(context
, config
, 0,
1227 "Failed to get key for enc-authorization-data");
1228 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1231 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1232 krb5_free_keyblock(context
, subkey
);
1234 krb5_auth_con_free(context
, ac
);
1235 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1236 krb5_get_err_text(context
, ret
));
1239 ret
= krb5_decrypt_EncryptedData (context
,
1242 b
->enc_authorization_data
,
1244 krb5_crypto_destroy(context
, crypto
);
1246 krb5_auth_con_free(context
, ac
);
1247 kdc_log(context
, config
, 0,
1248 "Failed to decrypt enc-authorization-data");
1249 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1253 if (*auth_data
== NULL
) {
1254 krb5_auth_con_free(context
, ac
);
1255 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1258 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1260 krb5_auth_con_free(context
, ac
);
1263 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1264 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1269 krb5_auth_con_free(context
, ac
);
1272 free_AP_REQ(&ap_req
);
1277 static krb5_error_code
1278 build_server_referral(krb5_context context
,
1279 krb5_kdc_configuration
*config
,
1280 krb5_crypto session
,
1281 krb5_const_realm referred_realm
,
1282 const PrincipalName
*true_principal_name
,
1283 const PrincipalName
*requested_principal
,
1286 PA_ServerReferralData ref
;
1287 krb5_error_code ret
;
1292 memset(&ref
, 0, sizeof(ref
));
1294 if (referred_realm
) {
1295 ALLOC(ref
.referred_realm
);
1296 if (ref
.referred_realm
== NULL
)
1298 *ref
.referred_realm
= strdup(referred_realm
);
1299 if (*ref
.referred_realm
== NULL
)
1302 if (true_principal_name
) {
1303 ALLOC(ref
.true_principal_name
);
1304 if (ref
.true_principal_name
== NULL
)
1306 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1310 if (requested_principal
) {
1311 ALLOC(ref
.requested_principal_name
);
1312 if (ref
.requested_principal_name
== NULL
)
1314 ret
= copy_PrincipalName(requested_principal
,
1315 ref
.requested_principal_name
);
1320 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1321 data
.data
, data
.length
,
1323 free_PA_ServerReferralData(&ref
);
1326 if (data
.length
!= size
)
1327 krb5_abortx(context
, "internal asn.1 encoder error");
1329 ret
= krb5_encrypt_EncryptedData(context
, session
,
1330 KRB5_KU_PA_SERVER_REFERRAL
,
1331 data
.data
, data
.length
,
1337 ASN1_MALLOC_ENCODE(EncryptedData
,
1338 outdata
->data
, outdata
->length
,
1340 free_EncryptedData(&ed
);
1343 if (outdata
->length
!= size
)
1344 krb5_abortx(context
, "internal asn.1 encoder error");
1348 free_PA_ServerReferralData(&ref
);
1349 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1353 static krb5_error_code
1354 tgs_build_reply(krb5_context context
,
1355 krb5_kdc_configuration
*config
,
1358 hdb_entry_ex
*krbtgt
,
1359 krb5_enctype krbtgt_etype
,
1360 krb5_ticket
*ticket
,
1363 const char **e_text
,
1364 AuthorizationData
**auth_data
,
1365 const struct sockaddr
*from_addr
)
1367 krb5_error_code ret
;
1368 krb5_principal cp
= NULL
, sp
= NULL
;
1369 krb5_principal client_principal
= NULL
;
1370 char *spn
= NULL
, *cpn
= NULL
;
1371 hdb_entry_ex
*server
= NULL
, *client
= NULL
;
1372 krb5_realm ref_realm
= NULL
;
1373 EncTicketPart
*tgt
= &ticket
->ticket
;
1374 krb5_principals spp
= NULL
;
1375 const EncryptionKey
*ekey
;
1376 krb5_keyblock sessionkey
;
1380 METHOD_DATA enc_pa_data
;
1385 EncTicketPart adtkt
;
1391 memset(&sessionkey
, 0, sizeof(sessionkey
));
1392 memset(&adtkt
, 0, sizeof(adtkt
));
1393 krb5_data_zero(&rspac
);
1394 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1399 if(b
->kdc_options
.enc_tkt_in_skey
){
1405 if(b
->additional_tickets
== NULL
||
1406 b
->additional_tickets
->len
== 0){
1407 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1408 kdc_log(context
, config
, 0,
1409 "No second ticket present in request");
1412 t
= &b
->additional_tickets
->val
[0];
1413 if(!get_krbtgt_realm(&t
->sname
)){
1414 kdc_log(context
, config
, 0,
1415 "Additional ticket is not a ticket-granting ticket");
1416 ret
= KRB5KDC_ERR_POLICY
;
1419 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1420 ret
= _kdc_db_fetch(context
, config
, p
,
1421 HDB_F_GET_CLIENT
|HDB_F_GET_SERVER
,
1423 krb5_free_principal(context
, p
);
1425 if (ret
== HDB_ERR_NOENTRY
)
1426 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1429 ret
= hdb_enctype2key(context
, &uu
->entry
,
1430 t
->enc_part
.etype
, &uukey
);
1432 _kdc_free_ent(context
, uu
);
1433 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1436 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1437 _kdc_free_ent(context
, uu
);
1441 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1449 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1450 ret
= krb5_unparse_name(context
, sp
, &spn
);
1453 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1454 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1457 unparse_flags (KDCOptions2int(b
->kdc_options
),
1458 asn1_KDCOptions_units(),
1459 opt_str
, sizeof(opt_str
));
1461 kdc_log(context
, config
, 0,
1462 "TGS-REQ %s from %s for %s [%s]",
1463 cpn
, from
, spn
, opt_str
);
1465 kdc_log(context
, config
, 0,
1466 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1473 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
| HDB_F_CANON
,
1477 const char *new_rlm
;
1481 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1483 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1485 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1486 "not found, trying %s",
1488 krb5_free_principal(context
, sp
);
1490 krb5_make_principal(context
, &sp
, r
,
1491 KRB5_TGS_NAME
, new_rlm
, NULL
);
1492 ret
= krb5_unparse_name(context
, sp
, &spn
);
1498 ref_realm
= strdup(new_rlm
);
1502 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1503 if (strcmp(realms
[0], sp
->realm
) != 0) {
1504 kdc_log(context
, config
, 5,
1505 "Returning a referral to realm %s for "
1506 "server %s that was not found",
1508 krb5_free_principal(context
, sp
);
1510 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1512 ret
= krb5_unparse_name(context
, sp
, &spn
);
1518 ref_realm
= strdup(realms
[0]);
1520 krb5_free_host_realm(context
, realms
);
1523 krb5_free_host_realm(context
, realms
);
1525 kdc_log(context
, config
, 0,
1526 "Server not found in database: %s: %s", spn
,
1527 krb5_get_err_text(context
, ret
));
1528 if (ret
== HDB_ERR_NOENTRY
)
1529 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1533 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| HDB_F_CANON
,
1536 const char *krbtgt_realm
;
1539 * If the client belongs to the same realm as our krbtgt, it
1540 * should exist in the local database.
1545 krb5_principal_get_comp_string(context
,
1546 krbtgt
->entry
.principal
, 1);
1548 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1549 if (ret
== HDB_ERR_NOENTRY
)
1550 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1551 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1556 kdc_log(context
, config
, 1, "Client not found in database: %s: %s",
1557 cpn
, krb5_get_err_text(context
, ret
));
1561 * Select enctype, return key and kvno.
1567 if(b
->kdc_options
.enc_tkt_in_skey
) {
1570 for(i
= 0; i
< b
->etype
.len
; i
++)
1571 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1573 if(i
== b
->etype
.len
) {
1574 kdc_log(context
, config
, 0,
1575 "Addition ticket have not matching etypes");
1576 krb5_clear_error_message(context
);
1577 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1580 etype
= b
->etype
.val
[i
];
1585 ret
= _kdc_find_etype(context
, server
, b
->etype
.val
, b
->etype
.len
,
1588 kdc_log(context
, config
, 0,
1589 "Server (%s) has no support for etypes", spn
);
1593 kvno
= server
->entry
.kvno
;
1596 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1602 * Check that service is in the same realm as the krbtgt. If it's
1603 * not the same, it's someone that is using a uni-directional trust
1607 if (strcmp(krb5_principal_get_realm(context
, sp
),
1608 krb5_principal_get_comp_string(context
,
1609 krbtgt
->entry
.principal
,
1612 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &tpn
);
1613 kdc_log(context
, config
, 0,
1614 "Request with wrong krbtgt: %s",
1615 (ret
== 0) ? tpn
: "<unknown>");
1618 ret
= KRB5KRB_AP_ERR_NOT_US
;
1623 * Validate authoriation data
1626 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1627 krbtgt_etype
, &tkey
);
1629 kdc_log(context
, config
, 0,
1630 "Failed to find key for krbtgt PAC check");
1634 ret
= check_PAC(context
, config
, cp
,
1635 client
, server
, ekey
, &tkey
->key
,
1636 tgt
, &rspac
, &signedpath
);
1638 kdc_log(context
, config
, 0,
1639 "Verify PAC failed for %s (%s) from %s with %s",
1640 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1644 /* also check the krbtgt for signature */
1645 ret
= check_KRB5SignedPath(context
,
1652 kdc_log(context
, config
, 0,
1653 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1654 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1662 client_principal
= cp
;
1665 const PA_DATA
*sdata
;
1668 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1673 char *selfcpn
= NULL
;
1676 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1677 sdata
->padata_value
.length
,
1680 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1684 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1688 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1690 free_PA_S4U2Self(&self
);
1691 krb5_data_free(&datack
);
1692 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1693 krb5_get_err_text(context
, ret
));
1697 ret
= krb5_verify_checksum(context
,
1699 KRB5_KU_OTHER_CKSUM
,
1703 krb5_data_free(&datack
);
1704 krb5_crypto_destroy(context
, crypto
);
1706 free_PA_S4U2Self(&self
);
1707 kdc_log(context
, config
, 0,
1708 "krb5_verify_checksum failed for S4U2Self: %s",
1709 krb5_get_err_text(context
, ret
));
1713 ret
= _krb5_principalname2krb5_principal(context
,
1717 free_PA_S4U2Self(&self
);
1721 ret
= krb5_unparse_name(context
, client_principal
, &selfcpn
);
1726 * Check that service doing the impersonating is
1727 * requesting a ticket to it-self.
1729 if (krb5_principal_compare(context
, cp
, sp
) != TRUE
) {
1730 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1731 "to impersonate some other user "
1732 "(tried for user %s to service %s)",
1735 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1740 * If the service isn't trusted for authentication to
1741 * delegation, remove the forward flag.
1744 if (client
->entry
.flags
.trusted_for_delegation
) {
1745 str
= "[forwardable]";
1747 b
->kdc_options
.forwardable
= 0;
1750 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
1751 "service %s %s", cpn
, selfcpn
, spn
, str
);
1757 * Constrained delegation
1761 && b
->additional_tickets
!= NULL
1762 && b
->additional_tickets
->len
!= 0
1763 && b
->kdc_options
.enc_tkt_in_skey
== 0)
1765 int ad_signedpath
= 0;
1771 * Require that the KDC have issued the service's krbtgt (not
1772 * self-issued ticket with kimpersonate(1).
1775 ret
= KRB5KDC_ERR_BADOPTION
;
1776 kdc_log(context
, config
, 0,
1777 "Constrained delegation done on service ticket %s/%s",
1782 t
= &b
->additional_tickets
->val
[0];
1784 ret
= hdb_enctype2key(context
, &client
->entry
,
1785 t
->enc_part
.etype
, &clientkey
);
1787 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1791 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
1793 kdc_log(context
, config
, 0,
1794 "failed to decrypt ticket for "
1795 "constrained delegation from %s to %s ", spn
, cpn
);
1799 /* check that ticket is valid */
1800 if (adtkt
.flags
.forwardable
== 0) {
1801 kdc_log(context
, config
, 0,
1802 "Missing forwardable flag on ticket for "
1803 "constrained delegation from %s to %s ", spn
, cpn
);
1804 ret
= KRB5KDC_ERR_BADOPTION
;
1808 ret
= check_constrained_delegation(context
, config
, client
, sp
);
1810 kdc_log(context
, config
, 0,
1811 "constrained delegation from %s to %s not allowed",
1816 ret
= _krb5_principalname2krb5_principal(context
,
1823 ret
= krb5_unparse_name(context
, client_principal
, &str
);
1827 ret
= verify_flags(context
, config
, &adtkt
, str
);
1834 * Check that the KDC issued the user's ticket.
1836 ret
= check_KRB5SignedPath(context
,
1842 if (ret
== 0 && !ad_signedpath
)
1843 ret
= KRB5KDC_ERR_BADOPTION
;
1845 kdc_log(context
, config
, 0,
1846 "KRB5SignedPath check from service %s failed "
1847 "for delegation to %s for client %s "
1848 "from %s failed with %s",
1849 spn
, str
, cpn
, from
, krb5_get_err_text(context
, ret
));
1854 kdc_log(context
, config
, 0, "constrained delegation for %s "
1855 "from %s to %s", str
, cpn
, spn
);
1863 ret
= _kdc_check_flags(context
, config
,
1870 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1871 !krb5_principal_compare(context
,
1872 krbtgt
->entry
.principal
,
1873 server
->entry
.principal
)){
1874 kdc_log(context
, config
, 0, "Inconsistent request.");
1875 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1879 /* check for valid set of addresses */
1880 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
1881 ret
= KRB5KRB_AP_ERR_BADADDR
;
1882 kdc_log(context
, config
, 0, "Request from wrong address");
1887 * If this is an referral, add server referral data to the
1894 kdc_log(context
, config
, 0,
1895 "Adding server referral to %s", ref_realm
);
1897 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1901 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1902 NULL
, s
, &pa
.padata_value
);
1903 krb5_crypto_destroy(context
, crypto
);
1905 kdc_log(context
, config
, 0,
1906 "Failed building server referral");
1909 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1911 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
1912 krb5_data_free(&pa
.padata_value
);
1914 kdc_log(context
, config
, 0,
1915 "Add server referral METHOD-DATA failed");
1924 ret
= tgs_make_reply(context
,
1950 krb5_data_free(&rspac
);
1951 krb5_free_keyblock_contents(context
, &sessionkey
);
1953 _kdc_free_ent(context
, server
);
1955 _kdc_free_ent(context
, client
);
1957 if (client_principal
&& client_principal
!= cp
)
1958 krb5_free_principal(context
, client_principal
);
1960 krb5_free_principal(context
, cp
);
1962 krb5_free_principal(context
, sp
);
1965 free_METHOD_DATA(&enc_pa_data
);
1967 free_EncTicketPart(&adtkt
);
1977 _kdc_tgs_rep(krb5_context context
,
1978 krb5_kdc_configuration
*config
,
1982 struct sockaddr
*from_addr
,
1985 AuthorizationData
*auth_data
= NULL
;
1986 krb5_error_code ret
;
1988 const PA_DATA
*tgs_req
;
1990 hdb_entry_ex
*krbtgt
= NULL
;
1991 krb5_ticket
*ticket
= NULL
;
1992 const char *e_text
= NULL
;
1993 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
1995 time_t *csec
= NULL
;
1998 if(req
->padata
== NULL
){
1999 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2000 kdc_log(context
, config
, 0,
2001 "TGS-REQ from %s without PA-DATA", from
);
2005 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2007 if(tgs_req
== NULL
){
2008 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2010 kdc_log(context
, config
, 0,
2011 "TGS-REQ from %s without PA-TGS-REQ", from
);
2014 ret
= tgs_parse_request(context
, config
,
2015 &req
->req_body
, tgs_req
,
2024 kdc_log(context
, config
, 0,
2025 "Failed parsing TGS-REQ from %s", from
);
2029 ret
= tgs_build_reply(context
,
2042 kdc_log(context
, config
, 0,
2043 "Failed building TGS-REP to %s", from
);
2048 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2049 krb5_data_free(data
);
2050 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2051 e_text
= "Reply packet too large";
2055 if(ret
&& data
->data
== NULL
){
2056 krb5_mk_error(context
,
2069 krb5_free_ticket(context
, ticket
);
2071 _kdc_free_ent(context
, krbtgt
);
2074 free_AuthorizationData(auth_data
);