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_string(context
, "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 KRB5SignedPathPrincipals
*principals
,
116 krb5_crypto crypto
= NULL
;
119 if (server
&& principals
) {
120 ret
= add_KRB5SignedPathPrincipals(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 KRB5SignedPathPrincipals
**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_KRB5SignedPathPrincipals(*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_string(context
, "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_string(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 const char *server_name
,
666 hdb_entry_ex
*client
,
667 krb5_principal client_principal
,
668 hdb_entry_ex
*krbtgt
,
669 krb5_enctype krbtgt_etype
,
670 KRB5SignedPathPrincipals
*spp
,
671 const krb5_data
*rspac
,
672 const METHOD_DATA
*enc_pa_data
,
679 KDCOptions f
= b
->kdc_options
;
682 memset(&rep
, 0, sizeof(rep
));
683 memset(&et
, 0, sizeof(et
));
684 memset(&ek
, 0, sizeof(ek
));
687 rep
.msg_type
= krb_tgs_rep
;
689 et
.authtime
= tgt
->authtime
;
690 _kdc_fix_time(&b
->till
);
691 et
.endtime
= min(tgt
->endtime
, *b
->till
);
693 *et
.starttime
= kdc_time
;
695 ret
= check_tgs_flags(context
, config
, b
, tgt
, &et
);
699 /* We should check the transited encoding if:
700 1) the request doesn't ask not to be checked
701 2) globally enforcing a check
702 3) principal requires checking
703 4) we allow non-check per-principal, but principal isn't marked as allowing this
704 5) we don't globally allow this
707 #define GLOBAL_FORCE_TRANSITED_CHECK \
708 (config->trpolicy == TRPOLICY_ALWAYS_CHECK)
709 #define GLOBAL_ALLOW_PER_PRINCIPAL \
710 (config->trpolicy == TRPOLICY_ALLOW_PER_PRINCIPAL)
711 #define GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK \
712 (config->trpolicy == TRPOLICY_ALWAYS_HONOUR_REQUEST)
714 /* these will consult the database in future release */
715 #define PRINCIPAL_FORCE_TRANSITED_CHECK(P) 0
716 #define PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(P) 0
718 ret
= fix_transited_encoding(context
, config
,
719 !f
.disable_transited_check
||
720 GLOBAL_FORCE_TRANSITED_CHECK
||
721 PRINCIPAL_FORCE_TRANSITED_CHECK(server
) ||
722 !((GLOBAL_ALLOW_PER_PRINCIPAL
&&
723 PRINCIPAL_ALLOW_DISABLE_TRANSITED_CHECK(server
)) ||
724 GLOBAL_ALLOW_DISABLE_TRANSITED_CHECK
),
725 &tgt
->transited
, &et
,
726 *krb5_princ_realm(context
, client_principal
),
727 *krb5_princ_realm(context
, server
->entry
.principal
),
728 *krb5_princ_realm(context
, krbtgt
->entry
.principal
));
732 copy_Realm(krb5_princ_realm(context
, server
->entry
.principal
),
734 _krb5_principal2principalname(&rep
.ticket
.sname
, server
->entry
.principal
);
735 copy_Realm(&tgt_name
->realm
, &rep
.crealm
);
737 if (f.request_anonymous)
738 _kdc_make_anonymous_principalname (&rep.cname);
741 copy_PrincipalName(&tgt_name
->name
, &rep
.cname
);
742 rep
.ticket
.tkt_vno
= 5;
746 et
.caddr
= tgt
->caddr
;
750 life
= et
.endtime
- *et
.starttime
;
751 if(client
&& client
->entry
.max_life
)
752 life
= min(life
, *client
->entry
.max_life
);
753 if(server
->entry
.max_life
)
754 life
= min(life
, *server
->entry
.max_life
);
755 et
.endtime
= *et
.starttime
+ life
;
757 if(f
.renewable_ok
&& tgt
->flags
.renewable
&&
758 et
.renew_till
== NULL
&& et
.endtime
< *b
->till
){
759 et
.flags
.renewable
= 1;
760 ALLOC(et
.renew_till
);
761 *et
.renew_till
= *b
->till
;
765 renew
= *et
.renew_till
- et
.authtime
;
766 if(client
&& client
->entry
.max_renew
)
767 renew
= min(renew
, *client
->entry
.max_renew
);
768 if(server
->entry
.max_renew
)
769 renew
= min(renew
, *server
->entry
.max_renew
);
770 *et
.renew_till
= et
.authtime
+ renew
;
774 *et
.renew_till
= min(*et
.renew_till
, *tgt
->renew_till
);
775 *et
.starttime
= min(*et
.starttime
, *et
.renew_till
);
776 et
.endtime
= min(et
.endtime
, *et
.renew_till
);
779 *et
.starttime
= min(*et
.starttime
, et
.endtime
);
781 if(*et
.starttime
== et
.endtime
){
782 ret
= KRB5KDC_ERR_NEVER_VALID
;
785 if(et
.renew_till
&& et
.endtime
== *et
.renew_till
){
787 et
.renew_till
= NULL
;
788 et
.flags
.renewable
= 0;
791 et
.flags
.pre_authent
= tgt
->flags
.pre_authent
;
792 et
.flags
.hw_authent
= tgt
->flags
.hw_authent
;
793 et
.flags
.anonymous
= tgt
->flags
.anonymous
;
794 et
.flags
.ok_as_delegate
= server
->entry
.flags
.ok_as_delegate
;
797 /* XXX Check enc-authorization-data */
798 et
.authorization_data
= calloc(1, sizeof(*et
.authorization_data
));
799 if (et
.authorization_data
== NULL
) {
803 ret
= copy_AuthorizationData(auth_data
, et
.authorization_data
);
807 /* Filter out type KRB5SignedPath */
808 ret
= find_KRB5SignedPath(context
, et
.authorization_data
, NULL
);
810 if (et
.authorization_data
->len
== 1) {
811 free_AuthorizationData(et
.authorization_data
);
812 free(et
.authorization_data
);
813 et
.authorization_data
= NULL
;
815 AuthorizationData
*ad
= et
.authorization_data
;
816 free_AuthorizationDataElement(&ad
->val
[ad
->len
- 1]);
824 * No not need to filter out the any PAC from the
825 * auth_data since it's signed by the KDC.
827 ret
= _kdc_tkt_add_if_relevant_ad(context
, &et
,
828 KRB5_AUTHDATA_WIN2K_PAC
,
834 ret
= krb5_copy_keyblock_contents(context
, sessionkey
, &et
.key
);
837 et
.crealm
= tgt
->crealm
;
838 et
.cname
= tgt_name
->name
;
841 /* MIT must have at least one last_req */
843 ek
.last_req
.val
= calloc(1, sizeof(*ek
.last_req
.val
));
844 if (ek
.last_req
.val
== NULL
) {
850 ek
.authtime
= et
.authtime
;
851 ek
.starttime
= et
.starttime
;
852 ek
.endtime
= et
.endtime
;
853 ek
.renew_till
= et
.renew_till
;
854 ek
.srealm
= rep
.ticket
.realm
;
855 ek
.sname
= rep
.ticket
.sname
;
857 _kdc_log_timestamp(context
, config
, "TGS-REQ", et
.authtime
, et
.starttime
,
858 et
.endtime
, et
.renew_till
);
860 /* Don't sign cross realm tickets, they can't be checked anyway */
862 char *r
= get_krbtgt_realm(&ek
.sname
);
864 if (r
== NULL
|| strcmp(r
, ek
.srealm
) == 0) {
865 ret
= _kdc_add_KRB5SignedPath(context
,
877 if (enc_pa_data
->len
) {
878 rep
.padata
= calloc(1, sizeof(*rep
.padata
));
879 if (rep
.padata
== NULL
) {
883 ret
= copy_METHOD_DATA(enc_pa_data
, rep
.padata
);
888 /* It is somewhat unclear where the etype in the following
889 encryption should come from. What we have is a session
890 key in the passed tgt, and a list of preferred etypes
891 *for the new ticket*. Should we pick the best possible
892 etype, given the keytype in the tgt, or should we look
893 at the etype list here as well? What if the tgt
894 session key is DES3 and we want a ticket with a (say)
895 CAST session key. Should the DES3 etype be added to the
896 etype list, even if we don't want a session key with
898 ret
= _kdc_encode_reply(context
, config
,
899 &rep
, &et
, &ek
, et
.key
.keytype
,
901 serverkey
, 0, &tgt
->key
, e_text
, reply
);
904 free_TransitedEncoding(&et
.transited
);
909 if(et
.authorization_data
) {
910 free_AuthorizationData(et
.authorization_data
);
911 free(et
.authorization_data
);
913 free_LastReq(&ek
.last_req
);
914 memset(et
.key
.keyvalue
.data
, 0, et
.key
.keyvalue
.length
);
915 free_EncryptionKey(&et
.key
);
919 static krb5_error_code
920 tgs_check_authenticator(krb5_context context
,
921 krb5_kdc_configuration
*config
,
922 krb5_auth_context ac
,
927 krb5_authenticator auth
;
934 krb5_auth_con_getauthenticator(context
, ac
, &auth
);
935 if(auth
->cksum
== NULL
){
936 kdc_log(context
, config
, 0, "No authenticator in request");
937 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
941 * according to RFC1510 it doesn't need to be keyed,
942 * but according to the latest draft it needs to.
946 !krb5_checksum_is_keyed(context
, auth
->cksum
->cksumtype
)
949 !krb5_checksum_is_collision_proof(context
, auth
->cksum
->cksumtype
)) {
950 kdc_log(context
, config
, 0, "Bad checksum type in authenticator: %d",
951 auth
->cksum
->cksumtype
);
952 ret
= KRB5KRB_AP_ERR_INAPP_CKSUM
;
956 /* XXX should not re-encode this */
957 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, b
, &len
, ret
);
959 kdc_log(context
, config
, 0, "Failed to encode KDC-REQ-BODY: %s",
960 krb5_get_err_text(context
, ret
));
963 if(buf_size
!= len
) {
965 kdc_log(context
, config
, 0, "Internal error in ASN.1 encoder");
966 *e_text
= "KDC internal error";
967 ret
= KRB5KRB_ERR_GENERIC
;
970 ret
= krb5_crypto_init(context
, key
, 0, &crypto
);
973 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
974 krb5_get_err_text(context
, ret
));
977 ret
= krb5_verify_checksum(context
,
979 KRB5_KU_TGS_REQ_AUTH_CKSUM
,
984 krb5_crypto_destroy(context
, crypto
);
986 kdc_log(context
, config
, 0,
987 "Failed to verify authenticator checksum: %s",
988 krb5_get_err_text(context
, ret
));
991 free_Authenticator(auth
);
1001 find_rpath(krb5_context context
, Realm crealm
, Realm srealm
)
1003 const char *new_realm
= krb5_config_get_string(context
,
1014 need_referral(krb5_context context
, krb5_kdc_configuration
*config
,
1015 const KDCOptions
* const options
, krb5_principal server
,
1016 krb5_realm
**realms
)
1020 if(!options
->canonicalize
&& server
->name
.name_type
!= KRB5_NT_SRV_INST
)
1023 if (server
->name
.name_string
.len
== 1)
1024 name
= server
->name
.name_string
.val
[0];
1025 if (server
->name
.name_string
.len
> 1)
1026 name
= server
->name
.name_string
.val
[1];
1030 kdc_log(context
, config
, 0, "Searching referral for %s", name
);
1032 return _krb5_get_host_realm_int(context
, name
, FALSE
, realms
) == 0;
1035 static krb5_error_code
1036 tgs_parse_request(krb5_context context
,
1037 krb5_kdc_configuration
*config
,
1039 const PA_DATA
*tgs_req
,
1040 hdb_entry_ex
**krbtgt
,
1041 krb5_enctype
*krbtgt_etype
,
1042 krb5_ticket
**ticket
,
1043 const char **e_text
,
1045 const struct sockaddr
*from_addr
,
1048 AuthorizationData
**auth_data
)
1051 krb5_error_code ret
;
1052 krb5_principal princ
;
1053 krb5_auth_context ac
= NULL
;
1054 krb5_flags ap_req_options
;
1055 krb5_flags verify_ap_req_flags
;
1063 memset(&ap_req
, 0, sizeof(ap_req
));
1064 ret
= krb5_decode_ap_req(context
, &tgs_req
->padata_value
, &ap_req
);
1066 kdc_log(context
, config
, 0, "Failed to decode AP-REQ: %s",
1067 krb5_get_err_text(context
, ret
));
1071 if(!get_krbtgt_realm(&ap_req
.ticket
.sname
)){
1072 /* XXX check for ticket.sname == req.sname */
1073 kdc_log(context
, config
, 0, "PA-DATA is not a ticket-granting ticket");
1074 ret
= KRB5KDC_ERR_POLICY
; /* ? */
1078 _krb5_principalname2krb5_principal(context
,
1080 ap_req
.ticket
.sname
,
1081 ap_req
.ticket
.realm
);
1083 ret
= _kdc_db_fetch(context
, config
, princ
, HDB_F_GET_KRBTGT
, NULL
, krbtgt
);
1087 ret
= krb5_unparse_name(context
, princ
, &p
);
1089 p
= "<unparse_name failed>";
1090 krb5_free_principal(context
, princ
);
1091 kdc_log(context
, config
, 0,
1092 "Ticket-granting ticket not found in database: %s: %s",
1093 p
, krb5_get_err_text(context
, ret
));
1096 ret
= KRB5KRB_AP_ERR_NOT_US
;
1100 if(ap_req
.ticket
.enc_part
.kvno
&&
1101 *ap_req
.ticket
.enc_part
.kvno
!= (*krbtgt
)->entry
.kvno
){
1104 ret
= krb5_unparse_name (context
, princ
, &p
);
1105 krb5_free_principal(context
, princ
);
1107 p
= "<unparse_name failed>";
1108 kdc_log(context
, config
, 0,
1109 "Ticket kvno = %d, DB kvno = %d (%s)",
1110 *ap_req
.ticket
.enc_part
.kvno
,
1111 (*krbtgt
)->entry
.kvno
,
1115 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1119 *krbtgt_etype
= ap_req
.ticket
.enc_part
.etype
;
1121 ret
= hdb_enctype2key(context
, &(*krbtgt
)->entry
,
1122 ap_req
.ticket
.enc_part
.etype
, &tkey
);
1124 char *str
= NULL
, *p
= NULL
;
1126 krb5_enctype_to_string(context
, ap_req
.ticket
.enc_part
.etype
, &str
);
1127 krb5_unparse_name(context
, princ
, &p
);
1128 kdc_log(context
, config
, 0,
1129 "No server key with enctype %s found for %s",
1130 str
? str
: "<unknown enctype>",
1131 p
? p
: "<unparse_name failed>");
1134 ret
= KRB5KRB_AP_ERR_BADKEYVER
;
1138 if (b
->kdc_options
.validate
)
1139 verify_ap_req_flags
= KRB5_VERIFY_AP_REQ_IGNORE_INVALID
;
1141 verify_ap_req_flags
= 0;
1143 ret
= krb5_verify_ap_req2(context
,
1148 verify_ap_req_flags
,
1151 KRB5_KU_TGS_REQ_AUTH
);
1153 krb5_free_principal(context
, princ
);
1155 kdc_log(context
, config
, 0, "Failed to verify AP-REQ: %s",
1156 krb5_get_err_text(context
, ret
));
1161 krb5_authenticator auth
;
1163 ret
= krb5_auth_con_getauthenticator(context
, ac
, &auth
);
1165 *csec
= malloc(sizeof(**csec
));
1166 if (*csec
== NULL
) {
1167 krb5_free_authenticator(context
, &auth
);
1168 kdc_log(context
, config
, 0, "malloc failed");
1171 **csec
= auth
->ctime
;
1172 *cusec
= malloc(sizeof(**cusec
));
1173 if (*cusec
== NULL
) {
1174 krb5_free_authenticator(context
, &auth
);
1175 kdc_log(context
, config
, 0, "malloc failed");
1178 **cusec
= auth
->cusec
;
1179 krb5_free_authenticator(context
, &auth
);
1183 ret
= tgs_check_authenticator(context
, config
,
1184 ac
, b
, e_text
, &(*ticket
)->ticket
.key
);
1186 krb5_auth_con_free(context
, ac
);
1190 if (b
->enc_authorization_data
) {
1191 unsigned usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY
;
1192 krb5_keyblock
*subkey
;
1195 ret
= krb5_auth_con_getremotesubkey(context
,
1199 krb5_auth_con_free(context
, ac
);
1200 kdc_log(context
, config
, 0, "Failed to get remote subkey: %s",
1201 krb5_get_err_text(context
, ret
));
1205 usage
= KRB5_KU_TGS_REQ_AUTH_DAT_SESSION
;
1206 ret
= krb5_auth_con_getkey(context
, ac
, &subkey
);
1208 krb5_auth_con_free(context
, ac
);
1209 kdc_log(context
, config
, 0, "Failed to get session key: %s",
1210 krb5_get_err_text(context
, ret
));
1215 krb5_auth_con_free(context
, ac
);
1216 kdc_log(context
, config
, 0,
1217 "Failed to get key for enc-authorization-data");
1218 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1221 ret
= krb5_crypto_init(context
, subkey
, 0, &crypto
);
1223 krb5_auth_con_free(context
, ac
);
1224 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1225 krb5_get_err_text(context
, ret
));
1228 ret
= krb5_decrypt_EncryptedData (context
,
1231 b
->enc_authorization_data
,
1233 krb5_crypto_destroy(context
, crypto
);
1235 krb5_auth_con_free(context
, ac
);
1236 kdc_log(context
, config
, 0,
1237 "Failed to decrypt enc-authorization-data");
1238 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1241 krb5_free_keyblock(context
, subkey
);
1243 if (*auth_data
== NULL
) {
1244 krb5_auth_con_free(context
, ac
);
1245 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1248 ret
= decode_AuthorizationData(ad
.data
, ad
.length
, *auth_data
, NULL
);
1250 krb5_auth_con_free(context
, ac
);
1253 kdc_log(context
, config
, 0, "Failed to decode authorization data");
1254 ret
= KRB5KRB_AP_ERR_BAD_INTEGRITY
; /* ? */
1259 krb5_auth_con_free(context
, ac
);
1262 free_AP_REQ(&ap_req
);
1267 static krb5_error_code
1268 build_server_referral(krb5_context context
,
1269 krb5_kdc_configuration
*config
,
1270 krb5_crypto session
,
1271 krb5_const_realm referred_realm
,
1272 const PrincipalName
*true_principal_name
,
1273 const PrincipalName
*requested_principal
,
1276 PA_ServerReferralData ref
;
1277 krb5_error_code ret
;
1282 memset(&ref
, 0, sizeof(ref
));
1284 if (referred_realm
) {
1285 ref
.referred_realm
= malloc(sizeof(ref
.referred_realm
));
1286 if (ref
.referred_realm
== NULL
)
1288 *ref
.referred_realm
= strdup(referred_realm
);
1289 if (*ref
.referred_realm
== NULL
)
1292 if (true_principal_name
) {
1293 ref
.true_principal_name
=
1294 malloc(sizeof(ref
.true_principal_name
));
1295 if (ref
.true_principal_name
== NULL
)
1297 ret
= copy_PrincipalName(true_principal_name
, ref
.true_principal_name
);
1301 if (requested_principal
) {
1302 ref
.requested_principal_name
=
1303 malloc(sizeof(ref
.requested_principal_name
));
1304 if (ref
.requested_principal_name
== NULL
)
1306 ret
= copy_PrincipalName(requested_principal
,
1307 ref
.requested_principal_name
);
1312 ASN1_MALLOC_ENCODE(PA_ServerReferralData
,
1313 data
.data
, data
.length
,
1315 free_PA_ServerReferralData(&ref
);
1318 if (data
.length
!= size
)
1319 krb5_abortx(context
, "internal asn.1 encoder error");
1321 ret
= krb5_encrypt_EncryptedData(context
, session
,
1322 KRB5_KU_PA_SERVER_REFERRAL
,
1323 data
.data
, data
.length
,
1329 ASN1_MALLOC_ENCODE(EncryptedData
,
1330 outdata
->data
, outdata
->length
,
1332 free_EncryptedData(&ed
);
1335 if (outdata
->length
!= size
)
1336 krb5_abortx(context
, "internal asn.1 encoder error");
1340 free_PA_ServerReferralData(&ref
);
1341 krb5_set_error_string(context
, "out of memory");
1345 static krb5_error_code
1346 tgs_build_reply(krb5_context context
,
1347 krb5_kdc_configuration
*config
,
1350 hdb_entry_ex
*krbtgt
,
1351 krb5_enctype krbtgt_etype
,
1352 krb5_ticket
*ticket
,
1355 const char **e_text
,
1356 AuthorizationData
**auth_data
,
1357 const struct sockaddr
*from_addr
,
1360 krb5_error_code ret
;
1361 krb5_principal cp
= NULL
, sp
= NULL
;
1362 krb5_principal client_principal
= NULL
;
1363 char *spn
= NULL
, *cpn
= NULL
;
1364 hdb_entry_ex
*server
= NULL
, *client
= NULL
;
1365 krb5_realm ref_realm
= NULL
;
1366 EncTicketPart
*tgt
= &ticket
->ticket
;
1367 KRB5SignedPathPrincipals
*spp
= NULL
;
1368 const EncryptionKey
*ekey
;
1369 krb5_keyblock sessionkey
;
1372 int cross_realm
= 0;
1374 METHOD_DATA enc_pa_data
;
1379 EncTicketPart adtkt
;
1383 memset(&sessionkey
, 0, sizeof(sessionkey
));
1384 memset(&adtkt
, 0, sizeof(adtkt
));
1385 krb5_data_zero(&rspac
);
1386 memset(&enc_pa_data
, 0, sizeof(enc_pa_data
));
1391 if(b
->kdc_options
.enc_tkt_in_skey
){
1397 if(b
->additional_tickets
== NULL
||
1398 b
->additional_tickets
->len
== 0){
1399 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1400 kdc_log(context
, config
, 0,
1401 "No second ticket present in request");
1404 t
= &b
->additional_tickets
->val
[0];
1405 if(!get_krbtgt_realm(&t
->sname
)){
1406 kdc_log(context
, config
, 0,
1407 "Additional ticket is not a ticket-granting ticket");
1408 ret
= KRB5KDC_ERR_POLICY
;
1411 _krb5_principalname2krb5_principal(context
, &p
, t
->sname
, t
->realm
);
1412 ret
= _kdc_db_fetch(context
, config
, p
,
1413 HDB_F_GET_CLIENT
|HDB_F_GET_SERVER
,
1415 krb5_free_principal(context
, p
);
1417 if (ret
== HDB_ERR_NOENTRY
)
1418 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1421 ret
= hdb_enctype2key(context
, &uu
->entry
,
1422 t
->enc_part
.etype
, &uukey
);
1424 _kdc_free_ent(context
, uu
);
1425 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1428 ret
= krb5_decrypt_ticket(context
, t
, &uukey
->key
, &adtkt
, 0);
1429 _kdc_free_ent(context
, uu
);
1433 ret
= verify_flags(context
, config
, &adtkt
, spn
);
1441 _krb5_principalname2krb5_principal(context
, &sp
, *s
, r
);
1442 ret
= krb5_unparse_name(context
, sp
, &spn
);
1445 _krb5_principalname2krb5_principal(context
, &cp
, tgt
->cname
, tgt
->crealm
);
1446 ret
= krb5_unparse_name(context
, cp
, &cpn
);
1449 unparse_flags (KDCOptions2int(b
->kdc_options
),
1450 asn1_KDCOptions_units(),
1451 opt_str
, sizeof(opt_str
));
1453 kdc_log(context
, config
, 0,
1454 "TGS-REQ %s from %s for %s [%s]",
1455 cpn
, from
, spn
, opt_str
);
1457 kdc_log(context
, config
, 0,
1458 "TGS-REQ %s from %s for %s", cpn
, from
, spn
);
1465 ret
= _kdc_db_fetch(context
, config
, sp
, HDB_F_GET_SERVER
, NULL
, &server
);
1468 const char *new_rlm
;
1472 if ((req_rlm
= get_krbtgt_realm(&sp
->name
)) != NULL
) {
1474 new_rlm
= find_rpath(context
, tgt
->crealm
, req_rlm
);
1476 kdc_log(context
, config
, 5, "krbtgt for realm %s "
1477 "not found, trying %s",
1479 krb5_free_principal(context
, sp
);
1481 krb5_make_principal(context
, &sp
, r
,
1482 KRB5_TGS_NAME
, new_rlm
, NULL
);
1483 ret
= krb5_unparse_name(context
, sp
, &spn
);
1489 ref_realm
= strdup(new_rlm
);
1493 } else if(need_referral(context
, config
, &b
->kdc_options
, sp
, &realms
)) {
1494 if (strcmp(realms
[0], sp
->realm
) != 0) {
1495 kdc_log(context
, config
, 5,
1496 "Returning a referral to realm %s for "
1497 "server %s that was not found",
1499 krb5_free_principal(context
, sp
);
1501 krb5_make_principal(context
, &sp
, r
, KRB5_TGS_NAME
,
1503 ret
= krb5_unparse_name(context
, sp
, &spn
);
1509 ref_realm
= strdup(realms
[0]);
1511 krb5_free_host_realm(context
, realms
);
1514 krb5_free_host_realm(context
, realms
);
1516 kdc_log(context
, config
, 0,
1517 "Server not found in database: %s: %s", spn
,
1518 krb5_get_err_text(context
, ret
));
1519 if (ret
== HDB_ERR_NOENTRY
)
1520 ret
= KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
;
1524 ret
= _kdc_db_fetch(context
, config
, cp
, HDB_F_GET_CLIENT
, NULL
, &client
);
1526 const char *krbtgt_realm
;
1529 * If the client belongs to the same realm as our krbtgt, it
1530 * should exist in the local database.
1535 krb5_principal_get_comp_string(context
,
1536 krbtgt
->entry
.principal
, 1);
1538 if(strcmp(krb5_principal_get_realm(context
, cp
), krbtgt_realm
) == 0) {
1539 if (ret
== HDB_ERR_NOENTRY
)
1540 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1541 kdc_log(context
, config
, 1, "Client no longer in database: %s",
1546 kdc_log(context
, config
, 1, "Client not found in database: %s: %s",
1547 cpn
, krb5_get_err_text(context
, ret
));
1553 * Select enctype, return key and kvno.
1559 if(b
->kdc_options
.enc_tkt_in_skey
) {
1562 for(i
= 0; i
< b
->etype
.len
; i
++)
1563 if (b
->etype
.val
[i
] == adtkt
.key
.keytype
)
1565 if(i
== b
->etype
.len
) {
1566 kdc_log(context
, config
, 0,
1567 "Addition ticket have not matching etypes", spp
);
1568 krb5_clear_error_string(context
);
1569 return KRB5KDC_ERR_ETYPE_NOSUPP
;
1571 etype
= b
->etype
.val
[i
];
1576 ret
= _kdc_find_etype(context
, server
, b
->etype
.val
, b
->etype
.len
,
1579 kdc_log(context
, config
, 0,
1580 "Server (%s) has no support for etypes", spn
);
1584 kvno
= server
->entry
.kvno
;
1587 ret
= krb5_generate_random_keyblock(context
, etype
, &sessionkey
);
1593 * Validate authoriation data
1597 * Check that service is in the same realm as the krbtgt. If it's
1598 * not the same, it's someone that is using a uni-directional trust
1602 if (strcmp(krb5_principal_get_realm(context
, sp
),
1603 krb5_principal_get_comp_string(context
,
1604 krbtgt
->entry
.principal
,
1607 ret
= krb5_unparse_name(context
, krbtgt
->entry
.principal
, &tpn
);
1608 kdc_log(context
, config
, 0,
1609 "Request with wrong krbtgt: %s",
1610 (ret
== 0) ? tpn
: "<unknown>");
1613 ret
= KRB5KRB_AP_ERR_NOT_US
;
1617 /* check PAC if not cross realm and if there is one */
1621 ret
= hdb_enctype2key(context
, &krbtgt
->entry
,
1622 krbtgt_etype
, &tkey
);
1624 kdc_log(context
, config
, 0,
1625 "Failed to find key for krbtgt PAC check");
1629 ret
= check_PAC(context
, config
, cp
,
1630 client
, server
, ekey
, &tkey
->key
,
1631 tgt
, &rspac
, &signedpath
);
1633 kdc_log(context
, config
, 0,
1634 "Verify PAC failed for %s (%s) from %s with %s",
1635 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1640 /* also check the krbtgt for signature */
1641 ret
= check_KRB5SignedPath(context
,
1648 kdc_log(context
, config
, 0,
1649 "KRB5SignedPath check failed for %s (%s) from %s with %s",
1650 spn
, cpn
, from
, krb5_get_err_text(context
, ret
));
1658 client_principal
= cp
;
1661 const PA_DATA
*sdata
;
1664 sdata
= _kdc_find_padata(req
, &i
, KRB5_PADATA_S4U2SELF
);
1669 char *selfcpn
= NULL
;
1672 ret
= decode_PA_S4U2Self(sdata
->padata_value
.data
,
1673 sdata
->padata_value
.length
,
1676 kdc_log(context
, config
, 0, "Failed to decode PA-S4U2Self");
1680 ret
= _krb5_s4u2self_to_checksumdata(context
, &self
, &datack
);
1684 ret
= krb5_crypto_init(context
, &tgt
->key
, 0, &crypto
);
1686 free_PA_S4U2Self(&self
);
1687 krb5_data_free(&datack
);
1688 kdc_log(context
, config
, 0, "krb5_crypto_init failed: %s",
1689 krb5_get_err_text(context
, ret
));
1693 ret
= krb5_verify_checksum(context
,
1695 KRB5_KU_OTHER_CKSUM
,
1699 krb5_data_free(&datack
);
1700 krb5_crypto_destroy(context
, crypto
);
1702 free_PA_S4U2Self(&self
);
1703 kdc_log(context
, config
, 0,
1704 "krb5_verify_checksum failed for S4U2Self: %s",
1705 krb5_get_err_text(context
, ret
));
1709 ret
= _krb5_principalname2krb5_principal(context
,
1713 free_PA_S4U2Self(&self
);
1717 ret
= krb5_unparse_name(context
, client_principal
, &selfcpn
);
1722 * Check that service doing the impersonating is
1723 * requesting a ticket to it-self.
1725 if (krb5_principal_compare(context
, cp
, sp
) != TRUE
) {
1726 kdc_log(context
, config
, 0, "S4U2Self: %s is not allowed "
1727 "to impersonate some other user "
1728 "(tried for user %s to service %s)",
1731 ret
= KRB5KDC_ERR_BADOPTION
; /* ? */
1736 * If the service isn't trusted for authentication to
1737 * delegation, remove the forward flag.
1740 if (client
->entry
.flags
.trusted_for_delegation
) {
1741 str
= "[forwardable]";
1743 b
->kdc_options
.forwardable
= 0;
1746 kdc_log(context
, config
, 0, "s4u2self %s impersonating %s to "
1747 "service %s %s", cpn
, selfcpn
, spn
, str
);
1753 * Constrained delegation
1757 && b
->additional_tickets
!= NULL
1758 && b
->additional_tickets
->len
!= 0
1759 && b
->kdc_options
.enc_tkt_in_skey
== 0)
1761 int ad_signedpath
= 0;
1767 * Require that the KDC have issued the service's krbtgt (not
1768 * self-issued ticket with kimpersonate(1).
1771 ret
= KRB5KDC_ERR_BADOPTION
;
1772 kdc_log(context
, config
, 0,
1773 "Constrained delegation done on service ticket %s/%s",
1778 t
= &b
->additional_tickets
->val
[0];
1780 ret
= hdb_enctype2key(context
, &client
->entry
,
1781 t
->enc_part
.etype
, &clientkey
);
1783 ret
= KRB5KDC_ERR_ETYPE_NOSUPP
; /* XXX */
1787 ret
= krb5_decrypt_ticket(context
, t
, &clientkey
->key
, &adtkt
, 0);
1789 kdc_log(context
, config
, 0,
1790 "failed to decrypt ticket for "
1791 "constrained delegation from %s to %s ", spn
, cpn
);
1795 /* check that ticket is valid */
1796 if (adtkt
.flags
.forwardable
== 0) {
1797 kdc_log(context
, config
, 0,
1798 "Missing forwardable flag on ticket for "
1799 "constrained delegation from %s to %s ", spn
, cpn
);
1800 ret
= KRB5KDC_ERR_BADOPTION
;
1804 ret
= check_constrained_delegation(context
, config
, client
, sp
);
1806 kdc_log(context
, config
, 0,
1807 "constrained delegation from %s to %s not allowed",
1812 ret
= _krb5_principalname2krb5_principal(context
,
1819 ret
= krb5_unparse_name(context
, client_principal
, &str
);
1823 ret
= verify_flags(context
, config
, &adtkt
, str
);
1830 * Check that the KDC issued the user's ticket.
1832 ret
= check_KRB5SignedPath(context
,
1838 if (ret
== 0 && !ad_signedpath
)
1839 ret
= KRB5KDC_ERR_BADOPTION
;
1841 kdc_log(context
, config
, 0,
1842 "KRB5SignedPath check from service %s failed "
1843 "for delegation to %s for client %s "
1844 "from %s failed with %s",
1845 spn
, str
, cpn
, from
, krb5_get_err_text(context
, ret
));
1850 kdc_log(context
, config
, 0, "constrained delegation for %s "
1851 "from %s to %s", str
, cpn
, spn
);
1859 ret
= _kdc_check_flags(context
, config
,
1866 if((b
->kdc_options
.validate
|| b
->kdc_options
.renew
) &&
1867 !krb5_principal_compare(context
,
1868 krbtgt
->entry
.principal
,
1869 server
->entry
.principal
)){
1870 kdc_log(context
, config
, 0, "Inconsistent request.");
1871 ret
= KRB5KDC_ERR_SERVER_NOMATCH
;
1875 /* check for valid set of addresses */
1876 if(!_kdc_check_addresses(context
, config
, tgt
->caddr
, from_addr
)) {
1877 ret
= KRB5KRB_AP_ERR_BADADDR
;
1878 kdc_log(context
, config
, 0, "Request from wrong address");
1883 * If this is an referral, add server referral data to the
1890 kdc_log(context
, config
, 0,
1891 "Adding server referral to %s", ref_realm
);
1893 ret
= krb5_crypto_init(context
, &sessionkey
, 0, &crypto
);
1897 ret
= build_server_referral(context
, config
, crypto
, ref_realm
,
1898 NULL
, s
, &pa
.padata_value
);
1899 krb5_crypto_destroy(context
, crypto
);
1901 kdc_log(context
, config
, 0,
1902 "Failed building server referral");
1905 pa
.padata_type
= KRB5_PADATA_SERVER_REFERRAL
;
1907 ret
= add_METHOD_DATA(&enc_pa_data
, &pa
);
1908 krb5_data_free(&pa
.padata_value
);
1910 kdc_log(context
, config
, 0,
1911 "Add server referral METHOD-DATA failed");
1920 ret
= tgs_make_reply(context
,
1945 krb5_data_free(&rspac
);
1946 krb5_free_keyblock_contents(context
, &sessionkey
);
1948 _kdc_free_ent(context
, server
);
1950 _kdc_free_ent(context
, client
);
1952 if (client_principal
&& client_principal
!= cp
)
1953 krb5_free_principal(context
, client_principal
);
1955 krb5_free_principal(context
, cp
);
1957 krb5_free_principal(context
, sp
);
1960 free_METHOD_DATA(&enc_pa_data
);
1962 free_EncTicketPart(&adtkt
);
1972 _kdc_tgs_rep(krb5_context context
,
1973 krb5_kdc_configuration
*config
,
1977 struct sockaddr
*from_addr
,
1980 AuthorizationData
*auth_data
= NULL
;
1981 krb5_error_code ret
;
1983 const PA_DATA
*tgs_req
;
1985 hdb_entry_ex
*krbtgt
= NULL
;
1986 krb5_ticket
*ticket
= NULL
;
1987 const char *e_text
= NULL
;
1988 krb5_enctype krbtgt_etype
= ETYPE_NULL
;
1990 time_t *csec
= NULL
;
1993 if(req
->padata
== NULL
){
1994 ret
= KRB5KDC_ERR_PREAUTH_REQUIRED
; /* XXX ??? */
1995 kdc_log(context
, config
, 0,
1996 "TGS-REQ from %s without PA-DATA", from
);
2000 tgs_req
= _kdc_find_padata(req
, &i
, KRB5_PADATA_TGS_REQ
);
2002 if(tgs_req
== NULL
){
2003 ret
= KRB5KDC_ERR_PADATA_TYPE_NOSUPP
;
2005 kdc_log(context
, config
, 0,
2006 "TGS-REQ from %s without PA-TGS-REQ", from
);
2009 ret
= tgs_parse_request(context
, config
,
2010 &req
->req_body
, tgs_req
,
2019 kdc_log(context
, config
, 0,
2020 "Failed parsing TGS-REQ from %s", from
);
2024 ret
= tgs_build_reply(context
,
2038 kdc_log(context
, config
, 0,
2039 "Failed building TGS-REP to %s", from
);
2044 if (datagram_reply
&& data
->length
> config
->max_datagram_reply_length
) {
2045 krb5_data_free(data
);
2046 ret
= KRB5KRB_ERR_RESPONSE_TOO_BIG
;
2047 e_text
= "Reply packet too large";
2051 if(ret
&& data
->data
== NULL
){
2052 krb5_mk_error(context
,
2065 krb5_free_ticket(context
, ticket
);
2067 _kdc_free_ent(context
, krbtgt
);
2070 free_AuthorizationData(auth_data
);