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
,
496 hdb_entry_ex
*client
,
497 krb5_const_principal server
)
499 const HDB_Ext_Constrained_delegation_acl
*acl
;
503 if (clientdb
->hdb_check_constrained_delegation
) {
504 ret
= clientdb
->hdb_check_constrained_delegation(context
, clientdb
, client
, server
);
508 ret
= hdb_entry_get_ConstrainedDelegACL(&client
->entry
, &acl
);
510 krb5_clear_error_message(context
);
515 for (i
= 0; i
< acl
->len
; i
++) {
516 if (krb5_principal_compare(context
, server
, &acl
->val
[i
]) == TRUE
)
520 ret
= KRB5KDC_ERR_BADOPTION
;
522 kdc_log(context
, config
, 0,
523 "Bad request for constrained delegation");
531 static krb5_error_code
532 verify_flags (krb5_context context
,
533 krb5_kdc_configuration
*config
,
534 const EncTicketPart
*et
,
537 if(et
->endtime
< kdc_time
){
538 kdc_log(context
, config
, 0, "Ticket expired (%s)", pstr
);
539 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
541 if(et
->flags
.invalid
){
542 kdc_log(context
, config
, 0, "Ticket not valid (%s)", pstr
);
543 return KRB5KRB_AP_ERR_TKT_NYV
;
552 static krb5_error_code
553 fix_transited_encoding(krb5_context context
,
554 krb5_kdc_configuration
*config
,
555 krb5_boolean check_policy
,
556 const TransitedEncoding
*tr
,
558 const char *client_realm
,
559 const char *server_realm
,
560 const char *tgt_realm
)
562 krb5_error_code ret
= 0;
563 char **realms
, **tmp
;
564 unsigned int num_realms
;
567 switch (tr
->tr_type
) {
568 case DOMAIN_X500_COMPRESS
:
572 * Allow empty content of type 0 because that is was Microsoft
573 * generates in their TGT.
575 if (tr
->contents
.length
== 0)
577 kdc_log(context
, config
, 0,
578 "Transited type 0 with non empty content");
579 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
581 kdc_log(context
, config
, 0,
582 "Unknown transited type: %u", tr
->tr_type
);
583 return KRB5KDC_ERR_TRTYPE_NOSUPP
;
586 ret
= krb5_domain_x500_decode(context
,
593 krb5_warn(context
, ret
,
594 "Decoding transited encoding");
597 if(strcmp(client_realm
, tgt_realm
) && strcmp(server_realm
, tgt_realm
)) {
598 /* not us, so add the previous realm to transited set */
599 if (num_realms
+ 1 > UINT_MAX
/sizeof(*realms
)) {
603 tmp
= realloc(realms
, (num_realms
+ 1) * sizeof(*realms
));
609 realms
[num_realms
] = strdup(tgt_realm
);
610 if(realms
[num_realms
] == NULL
){
616 if(num_realms
== 0) {
617 if(strcmp(client_realm
, server_realm
))
618 kdc_log(context
, config
, 0,
619 "cross-realm %s -> %s", client_realm
, server_realm
);
623 for(i
= 0; i
< num_realms
; i
++)
624 l
+= strlen(realms
[i
]) + 2;
628 for(i
= 0; i
< num_realms
; i
++) {
630 strlcat(rs
, ", ", l
);
631 strlcat(rs
, realms
[i
], l
);
633 kdc_log(context
, config
, 0,
634 "cross-realm %s -> %s via [%s]",
635 client_realm
, server_realm
, rs
);
640 ret
= krb5_check_transited(context
, client_realm
,
642 realms
, num_realms
, NULL
);
644 krb5_warn(context
, ret
, "cross-realm %s -> %s",
645 client_realm
, server_realm
);
648 et
->flags
.transited_policy_checked
= 1;
650 et
->transited
.tr_type
= DOMAIN_X500_COMPRESS
;
651 ret
= krb5_domain_x500_encode(realms
, num_realms
, &et
->transited
.contents
);
653 krb5_warn(context
, ret
, "Encoding transited encoding");
655 for(i
= 0; i
< num_realms
; i
++)
662 static krb5_error_code
663 tgs_make_reply(krb5_context context
,
664 krb5_kdc_configuration
*config
,
666 krb5_const_principal tgt_name
,
667 const EncTicketPart
*tgt
,
668 const EncryptionKey
*serverkey
,
669 const krb5_keyblock
*sessionkey
,
671 AuthorizationData
*auth_data
,
672 hdb_entry_ex
*server
,
673 krb5_principal server_principal
,
674 const char *server_name
,
675 hdb_entry_ex
*client
,
676 krb5_principal client_principal
,
677 hdb_entry_ex
*krbtgt
,
678 krb5_enctype krbtgt_etype
,
680 const krb5_data
*rspac
,
681 const METHOD_DATA
*enc_pa_data
,
688 KDCOptions f
= b
->kdc_options
;
692 memset(&rep
, 0, sizeof(rep
));
693 memset(&et
, 0, sizeof(et
));
694 memset(&ek
, 0, sizeof(ek
));
697 rep
.msg_type
= krb_tgs_rep
;
699 et
.authtime
= tgt
->authtime
;
700 _kdc_fix_time(&b
->till
);
701 et
.endtime
= min(tgt
->endtime
, *b
->till
);
703 *et
.starttime
= kdc_time
;
705 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
709 /* We should check the transited encoding if:
710 1) the request doesn't ask not to be checked
711 2) globally enforcing a check
712 3) principal requires checking
713 4) we allow non-check per-principal, but principal isn't marked as allowing this
714 5) we don't globally allow this
717 #define GLOBAL_FORCE_TRANSITED_CHECK \
718 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
719 #define GLOBAL_ALLOW_PER_PRINCIPAL \
720 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
721 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
722 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
724 /* these will consult the database in future release */
725 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
726 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
728 ret
= fix_transited_encoding(context
, config
,
729 !f
.disable_transited_check
||
730 GLOBAL_FORCE_TRANSITED_CHECK
||
731 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
732 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
733 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
734 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
735 &tgt
->transited
, &et
,
736 krb5_principal_get_realm(context
, client_principal
),
737 krb5_principal_get_realm(context
, server
->entry
.principal
),
738 krb5_principal_get_realm(context
, krbtgt
->entry
.principal
));
742 copy_Realm(&server_principal
->realm
, &rep
.ticket
.realm
);
743 _krb5_principal2principalname(&rep
.ticket
.sname
, server_principal
);
744 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
746 if (f.request_anonymous)
747 _kdc_make_anonymous_principalname (&rep.cname);
750 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
751 rep
.ticket
.tkt_vno
= 5;
755 et
.caddr
= tgt
->caddr
;
759 life
= et
.endtime
- *et
.starttime
;
760 if(client
&& client
->entry
.max_life
)
761 life
= min(life
, *client
->entry
.max_life
);
762 if(server
->entry
.max_life
)
763 life
= min(life
, *server
->entry
.max_life
);
764 et
.endtime
= *et
.starttime
+ life
;
766 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
767 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
){
768 et
.flags
.renewable
= 1;
769 ALLOC(et
.renew_till
);
770 *et
.renew_till
= *b
->till
;
774 renew
= *et
.renew_till
- et
.authtime
;
775 if(client
&& client
->entry
.max_renew
)
776 renew
= min(renew
, *client
->entry
.max_renew
);
777 if(server
->entry
.max_renew
)
778 renew
= min(renew
, *server
->entry
.max_renew
);
779 *et
.renew_till
= et
.authtime
+ renew
;
783 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
784 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
785 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
788 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
790 if(*et
.starttime
== et
.endtime
){
791 ret
= KRB5KDC_ERR_NEVER_VALID
;
794 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
796 et
.renew_till
= NULL
;
797 et
.flags
.renewable
= 0;
800 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
801 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
802 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
803 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
806 /* XXX Check enc-authorization-data */
807 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
808 if (et
.authorization_data
== NULL
) {
812 ret
= copy_AuthorizationData(auth_data
, et
.authorization_data
);
816 /* Filter out type KRB5SignedPath */
817 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
819 if (et
.authorization_data
->len
== 1) {
820 free_AuthorizationData(et
.authorization_data
);
821 free(et
.authorization_data
);
822 et
.authorization_data
= NULL
;
824 AuthorizationData
*ad
= et
.authorization_data
;
825 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
833 * No not need to filter out the any PAC from the
834 * auth_data since it's signed by the KDC.
836 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
837 KRB5_AUTHDATA_WIN2K_PAC
,
843 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
846 et
.crealm
= tgt
->crealm
;
847 et
.cname
= tgt_name
->name
;
850 /* MIT must have at least one last_req */
852 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
853 if (ek
.last_req
.val
== NULL
) {
859 ek
.authtime
= et
.authtime
;
860 ek
.starttime
= et
.starttime
;
861 ek
.endtime
= et
.endtime
;
862 ek
.renew_till
= et
.renew_till
;
863 ek
.srealm
= rep
.ticket
.realm
;
864 ek
.sname
= rep
.ticket
.sname
;
866 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
867 et
.endtime
, et
.renew_till
);
869 /* Don't sign cross realm tickets, they can't be checked anyway */
871 char *r
= get_krbtgt_realm(&ek
.sname
);
873 if (r
== NULL
|| strcmp(r
, ek
.srealm
) == 0) {
874 ret
= _kdc_add_KRB5SignedPath(context
,
886 if (enc_pa_data
->len
) {
887 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
888 if (rep
.padata
== NULL
) {
892 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
897 if (krb5_enctype_valid(context
, et
.key
.keytype
) != 0
898 && _kdc_is_weak_exception(server
->entry
.principal
, et
.key
.keytype
))
900 krb5_enctype_enable(context
, et
.key
.keytype
);
905 /* It is somewhat unclear where the etype in the following
906 encryption should come from. What we have is a session
907 key in the passed tgt, and a list of preferred etypes
908 *for the new ticket*. Should we pick the best possible
909 etype, given the keytype in the tgt, or should we look
910 at the etype list here as well? What if the tgt
911 session key is DES3 and we want a ticket with a (say)
912 CAST session key. Should the DES3 etype be added to the
913 etype list, even if we don't want a session key with
915 ret
= _kdc_encode_reply(context
, config
,
916 &rep
, &et
, &ek
, et
.key
.keytype
,
918 serverkey
, 0, &tgt
->key
, e_text
, reply
);
920 krb5_enctype_disable(context
, et
.key
.keytype
);
924 free_TransitedEncoding(&et
.transited
);
929 if(et
.authorization_data
) {
930 free_AuthorizationData(et
.authorization_data
);
931 free(et
.authorization_data
);
933 free_LastReq(&ek
.last_req
);
934 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
935 free_EncryptionKey(&et
.key
);
939 static krb5_error_code
940 tgs_check_authenticator(krb5_context context
,
941 krb5_kdc_configuration
*config
,
942 krb5_auth_context ac
,
947 krb5_authenticator auth
;
954 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
955 if(auth
->cksum
== NULL
){
956 kdc_log(context
, config
, 0, "No authenticator in request");
957 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
961 * according to RFC1510 it doesn't need to be keyed,
962 * but according to the latest draft it needs to.
966 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
969 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
970 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
971 auth
->cksum
->cksumtype
);
972 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
976 /* XXX should not re-encode this */
977 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
979 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s",
980 krb5_get_err_text(context
, ret
));
983 if(buf_size
!= len
) {
985 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
986 *e_text
= "KDC internal error";
987 ret
= KRB5KRB_ERR_GENERIC
;
990 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
993 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
994 krb5_get_err_text(context
, ret
));
997 ret
= krb5_verify_checksum(context
,
999 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
1004 krb5_crypto_destroy(context
, crypto
);
1006 kdc_log(context
, config
, 0,
1007 "Failed to verify authenticator checksum: %s",
1008 krb5_get_err_text(context
, ret
));
1011 free_Authenticator(auth
);
1021 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1023 const char *new_realm
= krb5_config_get_string(context
,
1034 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1035 const KDCOptions
* const options
, krb5_principal server
,
1036 krb5_realm
**realms
)
1040 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
1043 if (server
->name
.name_string
.len
== 1)
1044 name
= server
->name
.name_string
.val
[0];
1045 else if (server
->name
.name_string
.len
> 1)
1046 name
= server
->name
.name_string
.val
[1];
1050 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
1052 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
1055 static krb5_error_code
1056 tgs_parse_request(krb5_context context
,
1057 krb5_kdc_configuration
*config
,
1059 const PA_DATA
*tgs_req
,
1060 hdb_entry_ex
**krbtgt
,
1061 krb5_enctype
*krbtgt_etype
,
1062 krb5_ticket
**ticket
,
1063 const char **e_text
,
1065 const struct sockaddr
*from_addr
,
1068 AuthorizationData
**auth_data
)
1071 krb5_error_code ret
;
1072 krb5_principal princ
;
1073 krb5_auth_context ac
= NULL
;
1074 krb5_flags ap_req_options
;
1075 krb5_flags verify_ap_req_flags
;
1083 memset(&ap_req
, 0, sizeof(ap_req
));
1084 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
1086 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s",
1087 krb5_get_err_text(context
, ret
));
1091 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1092 /* XXX check for ticket.sname == req.sname */
1093 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
1094 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1098 _krb5_principalname2krb5_principal(context
,
1100 ap_req
.ticket
.sname
,
1101 ap_req
.ticket
.realm
);
1103 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, NULL
, krbtgt
);
1107 ret
= krb5_unparse_name(context
, princ
, &p
);
1109 p
= "<unparse_name failed>";
1110 krb5_free_principal(context
, princ
);
1111 kdc_log(context
, config
, 0,
1112 "Ticket-granting ticket not found in database: %s: %s",
1113 p
, krb5_get_err_text(context
, ret
));
1116 ret
= KRB5KRB_AP_ERR_NOT_US
;
1120 if(ap_req
.ticket
.enc_part
.kvno
&&
1121 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
1124 ret
= krb5_unparse_name (context
, princ
, &p
);
1125 krb5_free_principal(context
, princ
);
1127 p
= "<unparse_name failed>";
1128 kdc_log(context
, config
, 0,
1129 "Ticket kvno = %d, DB kvno = %d (%s)",
1130 *ap_req
.ticket
.enc_part
.kvno
,
1131 (*krbtgt
)->entry
.kvno
,
1135 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1139 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1141 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1142 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1144 char *str
= NULL
, *p
= NULL
;
1146 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1147 krb5_unparse_name(context
, princ
, &p
);
1148 kdc_log(context
, config
, 0,
1149 "No server key with enctype %s found for %s",
1150 str
? str
: "<unknown enctype>",
1151 p
? p
: "<unparse_name failed>");
1154 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1158 if (b
->kdc_options
.validate
)
1159 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1161 verify_ap_req_flags
= 0;
1163 ret
= krb5_verify_ap_req2(context
,
1168 verify_ap_req_flags
,
1171 KRB5_KU_TGS_REQ_AUTH
);
1173 krb5_free_principal(context
, princ
);
1175 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s",
1176 krb5_get_err_text(context
, ret
));
1181 krb5_authenticator auth
;
1183 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1185 *csec
= malloc(sizeof(**csec
));
1186 if (*csec
== NULL
) {
1187 krb5_free_authenticator(context
, &auth
);
1188 kdc_log(context
, config
, 0, "malloc failed");
1191 **csec
= auth
->ctime
;
1192 *cusec
= malloc(sizeof(**cusec
));
1193 if (*cusec
== NULL
) {
1194 krb5_free_authenticator(context
, &auth
);
1195 kdc_log(context
, config
, 0, "malloc failed");
1198 **cusec
= auth
->cusec
;
1199 krb5_free_authenticator(context
, &auth
);
1203 ret
= tgs_check_authenticator(context
, config
,
1204 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1206 krb5_auth_con_free(context
, ac
);
1210 if (b
->enc_authorization_data
) {
1211 unsigned usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1212 krb5_keyblock
*subkey
;
1215 ret
= krb5_auth_con_getremotesubkey(context
, ac
, &subkey
);
1217 krb5_auth_con_free(context
, ac
);
1218 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s",
1219 krb5_get_err_text(context
, ret
));
1223 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1224 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1226 krb5_auth_con_free(context
, ac
);
1227 kdc_log(context
, config
, 0, "Failed to get session key: %s",
1228 krb5_get_err_text(context
, ret
));
1233 krb5_auth_con_free(context
, ac
);
1234 kdc_log(context
, config
, 0,
1235 "Failed to get key for enc-authorization-data");
1236 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1239 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1240 krb5_free_keyblock(context
, subkey
);
1242 krb5_auth_con_free(context
, ac
);
1243 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1244 krb5_get_err_text(context
, ret
));
1247 ret
= krb5_decrypt_EncryptedData (context
,
1250 b
->enc_authorization_data
,
1252 krb5_crypto_destroy(context
, crypto
);
1254 krb5_auth_con_free(context
, ac
);
1255 kdc_log(context
, config
, 0,
1256 "Failed to decrypt enc-authorization-data");
1257 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1261 if (*auth_data
== NULL
) {
1262 krb5_auth_con_free(context
, ac
);
1263 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1266 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1268 krb5_auth_con_free(context
, ac
);
1271 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1272 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1277 krb5_auth_con_free(context
, ac
);
1280 free_AP_REQ(&ap_req
);
1285 static krb5_error_code
1286 build_server_referral(krb5_context context
,
1287 krb5_kdc_configuration
*config
,
1288 krb5_crypto session
,
1289 krb5_const_realm referred_realm
,
1290 const PrincipalName
*true_principal_name
,
1291 const PrincipalName
*requested_principal
,
1294 PA_ServerReferralData ref
;
1295 krb5_error_code ret
;
1300 memset(&ref
, 0, sizeof(ref
));
1302 if (referred_realm
) {
1303 ALLOC(ref
.referred_realm
);
1304 if (ref
.referred_realm
== NULL
)
1306 *ref
.referred_realm
= strdup(referred_realm
);
1307 if (*ref
.referred_realm
== NULL
)
1310 if (true_principal_name
) {
1311 ALLOC(ref
.true_principal_name
);
1312 if (ref
.true_principal_name
== NULL
)
1314 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1318 if (requested_principal
) {
1319 ALLOC(ref
.requested_principal_name
);
1320 if (ref
.requested_principal_name
== NULL
)
1322 ret
= copy_PrincipalName(requested_principal
,
1323 ref
.requested_principal_name
);
1328 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1329 data
.data
, data
.length
,
1331 free_PA_ServerReferralData(&ref
);
1334 if (data
.length
!= size
)
1335 krb5_abortx(context
, "internal asn.1 encoder error");
1337 ret
= krb5_encrypt_EncryptedData(context
, session
,
1338 KRB5_KU_PA_SERVER_REFERRAL
,
1339 data
.data
, data
.length
,
1345 ASN1_MALLOC_ENCODE(EncryptedData
,
1346 outdata
->data
, outdata
->length
,
1348 free_EncryptedData(&ed
);
1351 if (outdata
->length
!= size
)
1352 krb5_abortx(context
, "internal asn.1 encoder error");
1356 free_PA_ServerReferralData(&ref
);
1357 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
1361 static krb5_error_code
1362 tgs_build_reply(krb5_context context
,
1363 krb5_kdc_configuration
*config
,
1366 hdb_entry_ex
*krbtgt
,
1367 krb5_enctype krbtgt_etype
,
1368 krb5_ticket
*ticket
,
1371 const char **e_text
,
1372 AuthorizationData
**auth_data
,
1373 const struct sockaddr
*from_addr
)
1375 krb5_error_code ret
;
1376 krb5_principal cp
= NULL
, sp
= NULL
;
1377 krb5_principal client_principal
= NULL
;
1378 char *spn
= NULL
, *cpn
= NULL
;
1379 hdb_entry_ex
*server
= NULL
, *client
= NULL
;
1381 krb5_realm ref_realm
= NULL
;
1382 EncTicketPart
*tgt
= &ticket
->ticket
;
1383 krb5_principals spp
= NULL
;
1384 const EncryptionKey
*ekey
;
1385 krb5_keyblock sessionkey
;
1389 METHOD_DATA enc_pa_data
;
1394 EncTicketPart adtkt
;
1400 memset(&sessionkey
, 0, sizeof(sessionkey
));
1401 memset(&adtkt
, 0, sizeof(adtkt
));
1402 krb5_data_zero(&rspac
);
1403 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1408 if(b
->kdc_options
.enc_tkt_in_skey
){
1414 if(b
->additional_tickets
== NULL
||
1415 b
->additional_tickets
->len
== 0){
1416 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1417 kdc_log(context
, config
, 0,
1418 "No second ticket present in request");
1421 t
= &b
->additional_tickets
->val
[0];
1422 if(!get_krbtgt_realm(&t
->sname
)){
1423 kdc_log(context
, config
, 0,
1424 "Additional ticket is not a ticket-granting ticket");
1425 ret
= KRB5KDC_ERR_POLICY
;
1428 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1429 ret
= _kdc_db_fetch(context
, config
, p
,
1430 HDB_F_GET_CLIENT
|HDB_F_GET_SERVER
,
1432 krb5_free_principal(context
, p
);
1434 if (ret
== HDB_ERR_NOENTRY
)
1435 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1438 ret
= hdb_enctype2key(context
, &uu
->entry
,
1439 t
->enc_part
.etype
, &uukey
);
1441 _kdc_free_ent(context
, uu
);
1442 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1445 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1446 _kdc_free_ent(context
, uu
);
1450 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1458 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1459 ret
= krb5_unparse_name(context
, sp
, &spn
);
1462 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1463 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1466 unparse_flags (KDCOptions2int(b
->kdc_options
),
1467 asn1_KDCOptions_units(),
1468 opt_str
, sizeof(opt_str
));
1470 kdc_log(context
, config
, 0,
1471 "TGS-REQ %s from %s for %s [%s]",
1472 cpn
, from
, spn
, opt_str
);
1474 kdc_log(context
, config
, 0,
1475 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1482 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
| HDB_F_CANON
,
1486 const char *new_rlm
;
1490 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1492 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1494 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1495 "not found, trying %s",
1497 krb5_free_principal(context
, sp
);
1499 krb5_make_principal(context
, &sp
, r
,
1500 KRB5_TGS_NAME
, new_rlm
, NULL
);
1501 ret
= krb5_unparse_name(context
, sp
, &spn
);
1507 ref_realm
= strdup(new_rlm
);
1511 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1512 if (strcmp(realms
[0], sp
->realm
) != 0) {
1513 kdc_log(context
, config
, 5,
1514 "Returning a referral to realm %s for "
1515 "server %s that was not found",
1517 krb5_free_principal(context
, sp
);
1519 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1521 ret
= krb5_unparse_name(context
, sp
, &spn
);
1527 ref_realm
= strdup(realms
[0]);
1529 krb5_free_host_realm(context
, realms
);
1532 krb5_free_host_realm(context
, realms
);
1534 kdc_log(context
, config
, 0,
1535 "Server not found in database: %s: %s", spn
,
1536 krb5_get_err_text(context
, ret
));
1537 if (ret
== HDB_ERR_NOENTRY
)
1538 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1542 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
| HDB_F_CANON
,
1543 &clientdb
, &client
);
1545 const char *krbtgt_realm
;
1548 * If the client belongs to the same realm as our krbtgt, it
1549 * should exist in the local database.
1554 krb5_principal_get_comp_string(context
,
1555 krbtgt
->entry
.principal
, 1);
1557 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1558 if (ret
== HDB_ERR_NOENTRY
)
1559 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1560 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1565 kdc_log(context
, config
, 1, "Client not found in database: %s: %s",
1566 cpn
, krb5_get_err_text(context
, ret
));
1570 * Select enctype, return key and kvno.
1576 if(b
->kdc_options
.enc_tkt_in_skey
) {
1579 for(i
= 0; i
< b
->etype
.len
; i
++)
1580 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1582 if(i
== b
->etype
.len
) {
1583 kdc_log(context
, config
, 0,
1584 "Addition ticket have not matching etypes");
1585 krb5_clear_error_message(context
);
1586 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
;
1589 etype
= b
->etype
.val
[i
];
1594 ret
= _kdc_find_etype(context
, server
, b
->etype
.val
, b
->etype
.len
,
1597 kdc_log(context
, config
, 0,
1598 "Server (%s) has no support for etypes", spn
);
1602 kvno
= server
->entry
.kvno
;
1605 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1611 * Check that service is in the same realm as the krbtgt. If it's
1612 * not the same, it's someone that is using a uni-directional trust
1616 if (strcmp(krb5_principal_get_realm(context
, sp
),
1617 krb5_principal_get_comp_string(context
,
1618 krbtgt
->entry
.principal
,
1621 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &tpn
);
1622 kdc_log(context
, config
, 0,
1623 "Request with wrong krbtgt: %s",
1624 (ret
== 0) ? tpn
: "<unknown>");
1627 ret
= KRB5KRB_AP_ERR_NOT_US
;
1632 * Validate authoriation data
1635 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1636 krbtgt_etype
, &tkey
);
1638 kdc_log(context
, config
, 0,
1639 "Failed to find key for krbtgt PAC check");
1643 ret
= check_PAC(context
, config
, cp
,
1644 client
, server
, ekey
, &tkey
->key
,
1645 tgt
, &rspac
, &signedpath
);
1647 kdc_log(context
, config
, 0,
1648 "Verify PAC failed for %s (%s) from %s with %s",
1649 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1653 /* also check the krbtgt for signature */
1654 ret
= check_KRB5SignedPath(context
,
1661 kdc_log(context
, config
, 0,
1662 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1663 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1671 client_principal
= cp
;
1674 const PA_DATA
*sdata
;
1677 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_FOR_USER
);
1682 char *selfcpn
= NULL
;
1685 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1686 sdata
->padata_value
.length
,
1689 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1693 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1697 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1699 free_PA_S4U2Self(&self
);
1700 krb5_data_free(&datack
);
1701 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1702 krb5_get_err_text(context
, ret
));
1706 ret
= krb5_verify_checksum(context
,
1708 KRB5_KU_OTHER_CKSUM
,
1712 krb5_data_free(&datack
);
1713 krb5_crypto_destroy(context
, crypto
);
1715 free_PA_S4U2Self(&self
);
1716 kdc_log(context
, config
, 0,
1717 "krb5_verify_checksum failed for S4U2Self: %s",
1718 krb5_get_err_text(context
, ret
));
1722 ret
= _krb5_principalname2krb5_principal(context
,
1726 free_PA_S4U2Self(&self
);
1730 ret
= krb5_unparse_name(context
, client_principal
, &selfcpn
);
1735 * Check that service doing the impersonating is
1736 * requesting a ticket to it-self.
1738 if (krb5_principal_compare(context
, cp
, sp
) != TRUE
) {
1739 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1740 "to impersonate some other user "
1741 "(tried for user %s to service %s)",
1744 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1749 * If the service isn't trusted for authentication to
1750 * delegation, remove the forward flag.
1753 if (client
->entry
.flags
.trusted_for_delegation
) {
1754 str
= "[forwardable]";
1756 b
->kdc_options
.forwardable
= 0;
1759 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
1760 "service %s %s", cpn
, selfcpn
, spn
, str
);
1766 * Constrained delegation
1770 && b
->additional_tickets
!= NULL
1771 && b
->additional_tickets
->len
!= 0
1772 && b
->kdc_options
.enc_tkt_in_skey
== 0)
1774 int ad_signedpath
= 0;
1780 * Require that the KDC have issued the service's krbtgt (not
1781 * self-issued ticket with kimpersonate(1).
1784 ret
= KRB5KDC_ERR_BADOPTION
;
1785 kdc_log(context
, config
, 0,
1786 "Constrained delegation done on service ticket %s/%s",
1791 t
= &b
->additional_tickets
->val
[0];
1793 ret
= hdb_enctype2key(context
, &client
->entry
,
1794 t
->enc_part
.etype
, &clientkey
);
1796 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1800 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
1802 kdc_log(context
, config
, 0,
1803 "failed to decrypt ticket for "
1804 "constrained delegation from %s to %s ", cpn
, spn
);
1808 /* check that ticket is valid */
1809 if (adtkt
.flags
.forwardable
== 0) {
1810 kdc_log(context
, config
, 0,
1811 "Missing forwardable flag on ticket for "
1812 "constrained delegation from %s to %s ", cpn
, spn
);
1813 ret
= KRB5KDC_ERR_BADOPTION
;
1817 ret
= check_constrained_delegation(context
, config
, clientdb
,
1820 kdc_log(context
, config
, 0,
1821 "constrained delegation from %s to %s not allowed",
1826 ret
= _krb5_principalname2krb5_principal(context
,
1833 ret
= krb5_unparse_name(context
, client_principal
, &str
);
1837 ret
= verify_flags(context
, config
, &adtkt
, str
);
1844 * Check that the KDC issued the user's ticket.
1846 ret
= check_KRB5SignedPath(context
,
1852 if (ret
== 0 && !ad_signedpath
)
1853 ret
= KRB5KDC_ERR_BADOPTION
;
1855 kdc_log(context
, config
, 0,
1856 "KRB5SignedPath check from service %s failed "
1857 "for delegation to %s for client %s "
1858 "from %s failed with %s",
1859 spn
, str
, cpn
, from
, krb5_get_err_text(context
, ret
));
1864 kdc_log(context
, config
, 0, "constrained delegation for %s "
1865 "from %s to %s", str
, cpn
, spn
);
1873 ret
= kdc_check_flags(context
, config
,
1880 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1881 !krb5_principal_compare(context
,
1882 krbtgt
->entry
.principal
,
1883 server
->entry
.principal
)){
1884 kdc_log(context
, config
, 0, "Inconsistent request.");
1885 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1889 /* check for valid set of addresses */
1890 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
1891 ret
= KRB5KRB_AP_ERR_BADADDR
;
1892 kdc_log(context
, config
, 0, "Request from wrong address");
1897 * If this is an referral, add server referral data to the
1904 kdc_log(context
, config
, 0,
1905 "Adding server referral to %s", ref_realm
);
1907 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1911 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1912 NULL
, s
, &pa
.padata_value
);
1913 krb5_crypto_destroy(context
, crypto
);
1915 kdc_log(context
, config
, 0,
1916 "Failed building server referral");
1919 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1921 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
1922 krb5_data_free(&pa
.padata_value
);
1924 kdc_log(context
, config
, 0,
1925 "Add server referral METHOD-DATA failed");
1934 ret
= tgs_make_reply(context
,
1960 krb5_data_free(&rspac
);
1961 krb5_free_keyblock_contents(context
, &sessionkey
);
1963 _kdc_free_ent(context
, server
);
1965 _kdc_free_ent(context
, client
);
1967 if (client_principal
&& client_principal
!= cp
)
1968 krb5_free_principal(context
, client_principal
);
1970 krb5_free_principal(context
, cp
);
1972 krb5_free_principal(context
, sp
);
1975 free_METHOD_DATA(&enc_pa_data
);
1977 free_EncTicketPart(&adtkt
);
1987 _kdc_tgs_rep(krb5_context context
,
1988 krb5_kdc_configuration
*config
,
1992 struct sockaddr
*from_addr
,
1995 AuthorizationData
*auth_data
= NULL
;
1996 krb5_error_code ret
;
1998 const PA_DATA
*tgs_req
;
2000 hdb_entry_ex
*krbtgt
= NULL
;
2001 krb5_ticket
*ticket
= NULL
;
2002 const char *e_text
= NULL
;
2003 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
2005 time_t *csec
= NULL
;
2008 if(req
->padata
== NULL
){
2009 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
2010 kdc_log(context
, config
, 0,
2011 "TGS-REQ from %s without PA-DATA", from
);
2015 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2017 if(tgs_req
== NULL
){
2018 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2020 kdc_log(context
, config
, 0,
2021 "TGS-REQ from %s without PA-TGS-REQ", from
);
2024 ret
= tgs_parse_request(context
, config
,
2025 &req
->req_body
, tgs_req
,
2034 kdc_log(context
, config
, 0,
2035 "Failed parsing TGS-REQ from %s", from
);
2039 ret
= tgs_build_reply(context
,
2052 kdc_log(context
, config
, 0,
2053 "Failed building TGS-REP to %s", from
);
2058 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2059 krb5_data_free(data
);
2060 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2061 e_text
= "Reply packet too large";
2065 if(ret
&& data
->data
== NULL
){
2066 krb5_mk_error(context
,
2079 krb5_free_ticket(context
, ticket
);
2081 _kdc_free_ent(context
, krbtgt
);
2084 free_AuthorizationData(auth_data
);