2 Unix SMB/CIFS implementation.
4 PAC Glue between Samba and the KDC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 Copyright (C) Simo Sorce <idra@samba.org> 2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "lib/replace/replace.h"
25 #include "lib/replace/system/kerberos.h"
26 #include "lib/replace/system/filesys.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/samba_util.h"
29 #include "lib/util/talloc_stack.h"
31 #include "auth/auth_sam_reply.h"
32 #include "auth/kerberos/kerberos.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "auth/authn_policy.h"
35 #include "libcli/security/security.h"
36 #include "libds/common/flags.h"
37 #include "librpc/gen_ndr/ndr_krb5pac.h"
38 #include "param/param.h"
39 #include "source4/auth/auth.h"
40 #include "source4/dsdb/common/util.h"
41 #include "source4/dsdb/samdb/samdb.h"
42 #include "source4/kdc/authn_policy_util.h"
43 #include "source4/kdc/samba_kdc.h"
44 #include "source4/kdc/pac-glue.h"
45 #include "source4/kdc/ad_claims.h"
46 #include "source4/kdc/pac-blobs.h"
51 #define DBGC_CLASS DBGC_KERBEROS
54 NTSTATUS
samba_get_logon_info_pac_blob(TALLOC_CTX
*mem_ctx
,
55 const struct auth_user_info_dc
*info
,
56 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*override_resource_groups
,
57 const enum auth_group_inclusion group_inclusion
,
60 struct netr_SamInfo3
*info3
= NULL
;
61 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
62 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
63 union PAC_INFO pac_info
= {};
64 enum ndr_err_code ndr_err
;
67 *pac_data
= data_blob_null
;
69 if (override_resource_groups
== NULL
) {
70 resource_groups
= &_resource_groups
;
71 } else if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
73 * It doesn't make sense to override resource groups if we claim
74 * to want resource groups from user_info_dc.
76 DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
78 return NT_STATUS_INVALID_PARAMETER
;
81 nt_status
= auth_convert_user_info_dc_saminfo3(mem_ctx
, info
,
85 if (!NT_STATUS_IS_OK(nt_status
)) {
86 DBG_WARNING("Getting Samba info failed: %s\n",
87 nt_errstr(nt_status
));
91 pac_info
.logon_info
.info
= talloc_zero(mem_ctx
, struct PAC_LOGON_INFO
);
92 if (!pac_info
.logon_info
.info
) {
93 return NT_STATUS_NO_MEMORY
;
96 pac_info
.logon_info
.info
->info3
= *info3
;
97 if (_resource_groups
!= NULL
) {
98 pac_info
.logon_info
.info
->resource_groups
= *_resource_groups
;
101 if (override_resource_groups
!= NULL
) {
102 pac_info
.logon_info
.info
->resource_groups
= *override_resource_groups
;
105 if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
107 * Set the resource groups flag based on whether any groups are
108 * present. Otherwise, the flag is propagated from the
111 if (pac_info
.logon_info
.info
->resource_groups
.groups
.count
> 0) {
112 pac_info
.logon_info
.info
->info3
.base
.user_flags
|= NETLOGON_RESOURCE_GROUPS
;
114 pac_info
.logon_info
.info
->info3
.base
.user_flags
&= ~NETLOGON_RESOURCE_GROUPS
;
118 ndr_err
= ndr_push_union_blob(pac_data
, mem_ctx
, &pac_info
,
120 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
121 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
122 nt_status
= ndr_map_error2ntstatus(ndr_err
);
123 DBG_WARNING("PAC_LOGON_INFO (presig) push failed: %s\n",
124 nt_errstr(nt_status
));
132 NTSTATUS
samba_get_upn_info_pac_blob(TALLOC_CTX
*mem_ctx
,
133 const struct auth_user_info_dc
*info
,
136 union PAC_INFO pac_upn
= {};
137 enum ndr_err_code ndr_err
;
141 *upn_data
= data_blob_null
;
143 pac_upn
.upn_dns_info
.upn_name
= info
->info
->user_principal_name
;
144 pac_upn
.upn_dns_info
.dns_domain_name
= strupper_talloc(mem_ctx
,
145 info
->info
->dns_domain_name
);
146 if (pac_upn
.upn_dns_info
.dns_domain_name
== NULL
) {
147 return NT_STATUS_NO_MEMORY
;
149 if (info
->info
->user_principal_constructed
) {
150 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_CONSTRUCTED
;
153 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
;
155 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.samaccountname
156 = info
->info
->account_name
;
158 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.objectsid
159 = &info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
161 ndr_err
= ndr_push_union_blob(upn_data
, mem_ctx
, &pac_upn
,
162 PAC_TYPE_UPN_DNS_INFO
,
163 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
164 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
165 nt_status
= ndr_map_error2ntstatus(ndr_err
);
166 DBG_WARNING("PAC UPN_DNS_INFO (presig) push failed: %s\n",
167 nt_errstr(nt_status
));
171 ok
= data_blob_pad(mem_ctx
, upn_data
, 8);
173 return NT_STATUS_NO_MEMORY
;
180 NTSTATUS
samba_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
181 uint64_t pac_attributes
,
182 DATA_BLOB
*pac_attrs_data
)
184 union PAC_INFO pac_attrs
= {};
185 enum ndr_err_code ndr_err
;
188 *pac_attrs_data
= data_blob_null
;
190 /* Set the length of the flags in bits. */
191 pac_attrs
.attributes_info
.flags_length
= 2;
192 pac_attrs
.attributes_info
.flags
= pac_attributes
;
194 ndr_err
= ndr_push_union_blob(pac_attrs_data
, mem_ctx
, &pac_attrs
,
195 PAC_TYPE_ATTRIBUTES_INFO
,
196 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
197 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
198 nt_status
= ndr_map_error2ntstatus(ndr_err
);
199 DBG_WARNING("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
200 nt_errstr(nt_status
));
208 NTSTATUS
samba_get_cred_info_ndr_blob(TALLOC_CTX
*mem_ctx
,
209 const struct ldb_message
*msg
,
210 DATA_BLOB
*cred_blob
)
212 enum ndr_err_code ndr_err
;
214 struct samr_Password
*lm_hash
= NULL
;
215 struct samr_Password
*nt_hash
= NULL
;
216 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg
= {
219 DATA_BLOB ntlm_blob
= data_blob_null
;
220 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs
[1] = {{
221 .credential_size
= 0,
223 struct PAC_CREDENTIAL_DATA cred_data
= {
224 .credential_count
= 0,
226 struct PAC_CREDENTIAL_DATA_NDR cred_ndr
= {};
228 *cred_blob
= data_blob_null
;
230 lm_hash
= samdb_result_hash(mem_ctx
, msg
, "dBCSPwd");
231 if (lm_hash
!= NULL
) {
232 bool zero
= all_zero(lm_hash
->hash
, 16);
237 if (lm_hash
!= NULL
) {
238 DBG_INFO("Passing LM password hash through credentials set\n");
239 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_LM_HASH
;
240 ntlm_secpkg
.lm_password
= *lm_hash
;
241 ZERO_STRUCTP(lm_hash
);
242 TALLOC_FREE(lm_hash
);
245 nt_hash
= samdb_result_hash(mem_ctx
, msg
, "unicodePwd");
246 if (nt_hash
!= NULL
) {
247 bool zero
= all_zero(nt_hash
->hash
, 16);
252 if (nt_hash
!= NULL
) {
253 DBG_INFO("Passing NT password hash through credentials set\n");
254 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_NT_HASH
;
255 ntlm_secpkg
.nt_password
= *nt_hash
;
256 ZERO_STRUCTP(nt_hash
);
257 TALLOC_FREE(nt_hash
);
260 if (ntlm_secpkg
.flags
== 0) {
264 #ifdef DEBUG_PASSWORD
266 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG
, &ntlm_secpkg
);
270 ndr_err
= ndr_push_struct_blob(&ntlm_blob
, mem_ctx
, &ntlm_secpkg
,
271 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG
);
272 ZERO_STRUCT(ntlm_secpkg
);
273 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
274 nt_status
= ndr_map_error2ntstatus(ndr_err
);
275 DBG_WARNING("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
276 nt_errstr(nt_status
));
280 DBG_DEBUG("NTLM credential BLOB (len %zu) for user\n",
282 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
283 ntlm_blob
.data
, ntlm_blob
.length
);
285 secpkgs
[0].package_name
.string
= discard_const_p(char, "NTLM");
286 secpkgs
[0].credential_size
= ntlm_blob
.length
;
287 secpkgs
[0].credential
= ntlm_blob
.data
;
289 cred_data
.credential_count
= ARRAY_SIZE(secpkgs
);
290 cred_data
.credentials
= secpkgs
;
292 #ifdef DEBUG_PASSWORD
294 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA
, &cred_data
);
298 cred_ndr
.ctr
.data
= &cred_data
;
300 #ifdef DEBUG_PASSWORD
302 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR
, &cred_ndr
);
306 ndr_err
= ndr_push_struct_blob(cred_blob
, mem_ctx
, &cred_ndr
,
307 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_DATA_NDR
);
308 data_blob_clear(&ntlm_blob
);
309 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
310 nt_status
= ndr_map_error2ntstatus(ndr_err
);
311 DBG_WARNING("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
312 nt_errstr(nt_status
));
316 DBG_DEBUG("Created credential BLOB (len %zu) for user\n",
318 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
319 cred_blob
->data
, cred_blob
->length
);
324 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
325 const krb5_keyblock
*pkreplykey
,
326 const DATA_BLOB
*cred_ndr_blob
,
328 DATA_BLOB
*cred_info_blob
)
330 #ifdef SAMBA4_USES_HEIMDAL
331 krb5_crypto cred_crypto
;
332 krb5_enctype cred_enctype
;
333 krb5_data cred_ndr_crypt
;
334 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
337 enum ndr_err_code ndr_err
;
340 *cred_info_blob
= data_blob_null
;
342 ret
= krb5_crypto_init(context
, pkreplykey
, ETYPE_NULL
,
345 krb5err
= krb5_get_error_message(context
, ret
);
346 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
347 krb5_free_error_message(context
, krb5err
);
351 ret
= krb5_crypto_getenctype(context
, cred_crypto
, &cred_enctype
);
353 DBG_WARNING("Failed getting crypto type for key\n");
354 krb5_crypto_destroy(context
, cred_crypto
);
358 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
359 cred_ndr_blob
->length
);
360 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
361 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
363 ret
= krb5_encrypt(context
, cred_crypto
,
364 KRB5_KU_OTHER_ENCRYPTED
,
365 cred_ndr_blob
->data
, cred_ndr_blob
->length
,
367 krb5_crypto_destroy(context
, cred_crypto
);
369 krb5err
= krb5_get_error_message(context
, ret
);
370 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err
);
371 krb5_free_error_message(context
, krb5err
);
375 pac_cred_info
.encryption_type
= cred_enctype
;
376 pac_cred_info
.encrypted_data
.length
= cred_ndr_crypt
.length
;
377 pac_cred_info
.encrypted_data
.data
= (uint8_t *)cred_ndr_crypt
.data
;
380 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
383 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
384 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
385 krb5_data_free(&cred_ndr_crypt
);
386 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
387 nt_status
= ndr_map_error2ntstatus(ndr_err
);
388 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
389 nt_errstr(nt_status
));
390 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
393 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
394 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
395 dump_data_pw("PAC_CREDENTIAL_INFO",
396 cred_info_blob
->data
, cred_info_blob
->length
);
399 #else /* SAMBA4_USES_HEIMDAL */
401 krb5_enctype cred_enctype
;
402 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
403 krb5_error_code code
;
405 enum ndr_err_code ndr_err
;
407 krb5_data cred_ndr_data
;
408 krb5_enc_data cred_ndr_crypt
;
411 *cred_info_blob
= data_blob_null
;
413 code
= krb5_k_create_key(context
,
417 krb5err
= krb5_get_error_message(context
, code
);
418 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
419 krb5_free_error_message(context
, krb5err
);
423 cred_enctype
= krb5_k_key_enctype(context
, cred_key
);
425 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
426 cred_ndr_blob
->length
);
427 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
428 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
430 pac_cred_info
.encryption_type
= cred_enctype
;
432 cred_ndr_data
= smb_krb5_data_from_blob(*cred_ndr_blob
);
434 code
= krb5_c_encrypt_length(context
,
436 cred_ndr_data
.length
,
439 krb5err
= krb5_get_error_message(context
, code
);
440 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
441 krb5_free_error_message(context
, krb5err
);
445 pac_cred_info
.encrypted_data
= data_blob_talloc_zero(mem_ctx
, enc_len
);
446 if (pac_cred_info
.encrypted_data
.data
== NULL
) {
447 DBG_ERR("Out of memory\n");
451 cred_ndr_crypt
.ciphertext
= smb_krb5_data_from_blob(pac_cred_info
.encrypted_data
);
453 code
= krb5_k_encrypt(context
,
455 KRB5_KU_OTHER_ENCRYPTED
,
459 krb5_k_free_key(context
, cred_key
);
461 krb5err
= krb5_get_error_message(context
, code
);
462 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err
);
463 krb5_free_error_message(context
, krb5err
);
468 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
471 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
472 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
473 TALLOC_FREE(pac_cred_info
.encrypted_data
.data
);
474 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
475 nt_status
= ndr_map_error2ntstatus(ndr_err
);
476 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
477 nt_errstr(nt_status
));
478 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
481 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
482 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
483 dump_data_pw("PAC_CREDENTIAL_INFO",
484 cred_info_blob
->data
, cred_info_blob
->length
);
487 #endif /* SAMBA4_USES_HEIMDAL */
492 * @brief Create a PAC with the given blobs (logon, credentials, upn and
495 * @param[in] context The KRB5 context to use.
497 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
498 * use NULL to ignore it.
500 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
501 * blob, use NULL to ignore it.
503 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
506 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
507 * blob, use NULL to ignore it.
509 * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
510 * given blob, use NULL to ignore it.
512 * @param[in] device_info_blob Fill the device info PAC buffer with the given
513 * blob, use NULL to ignore it.
515 * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
516 * blob, use NULL to ignore it.
518 * @param[in] pac The pac buffer to fill. This should be allocated with
519 * krb5_pac_init() already.
521 * @returns 0 on success or a corresponding KRB5 error.
523 krb5_error_code
samba_make_krb5_pac(krb5_context context
,
524 const DATA_BLOB
*logon_blob
,
525 const DATA_BLOB
*cred_blob
,
526 const DATA_BLOB
*upn_blob
,
527 const DATA_BLOB
*pac_attrs_blob
,
528 const DATA_BLOB
*requester_sid_blob
,
529 const DATA_BLOB
*deleg_blob
,
530 const DATA_BLOB
*client_claims_blob
,
531 const DATA_BLOB
*device_info_blob
,
532 const DATA_BLOB
*device_claims_blob
,
535 krb5_data logon_data
;
537 char null_byte
= '\0';
538 krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
540 /* The user account may be set not to want the PAC */
541 if (logon_blob
== NULL
) {
545 logon_data
= smb_krb5_data_from_blob(*logon_blob
);
546 ret
= krb5_pac_add_buffer(context
, pac
, PAC_TYPE_LOGON_INFO
, &logon_data
);
551 if (device_info_blob
!= NULL
) {
552 krb5_data device_info_data
= smb_krb5_data_from_blob(*device_info_blob
);
553 ret
= krb5_pac_add_buffer(context
, pac
,
554 PAC_TYPE_DEVICE_INFO
,
561 if (client_claims_blob
!= NULL
) {
562 krb5_data client_claims_data
;
563 krb5_data
*data
= NULL
;
565 if (client_claims_blob
->length
!= 0) {
566 client_claims_data
= smb_krb5_data_from_blob(*client_claims_blob
);
567 data
= &client_claims_data
;
572 ret
= krb5_pac_add_buffer(context
, pac
,
573 PAC_TYPE_CLIENT_CLAIMS_INFO
,
580 if (device_claims_blob
!= NULL
) {
581 krb5_data device_claims_data
= smb_krb5_data_from_blob(*device_claims_blob
);
582 ret
= krb5_pac_add_buffer(context
, pac
,
583 PAC_TYPE_DEVICE_CLAIMS_INFO
,
584 &device_claims_data
);
590 if (cred_blob
!= NULL
) {
591 krb5_data cred_data
= smb_krb5_data_from_blob(*cred_blob
);
592 ret
= krb5_pac_add_buffer(context
, pac
,
593 PAC_TYPE_CREDENTIAL_INFO
,
600 #ifdef SAMBA4_USES_HEIMDAL
602 * null_data will be filled by the generic KDC code in the caller
603 * here we just add it in order to have it before
604 * PAC_TYPE_UPN_DNS_INFO
606 * Not needed with MIT Kerberos - asn
608 ret
= krb5_pac_add_buffer(context
, pac
,
616 if (upn_blob
!= NULL
) {
617 krb5_data upn_data
= smb_krb5_data_from_blob(*upn_blob
);
618 ret
= krb5_pac_add_buffer(context
, pac
,
619 PAC_TYPE_UPN_DNS_INFO
,
626 if (pac_attrs_blob
!= NULL
) {
627 krb5_data pac_attrs_data
= smb_krb5_data_from_blob(*pac_attrs_blob
);
628 ret
= krb5_pac_add_buffer(context
, pac
,
629 PAC_TYPE_ATTRIBUTES_INFO
,
636 if (requester_sid_blob
!= NULL
) {
637 krb5_data requester_sid_data
= smb_krb5_data_from_blob(*requester_sid_blob
);
638 ret
= krb5_pac_add_buffer(context
, pac
,
639 PAC_TYPE_REQUESTER_SID
,
640 &requester_sid_data
);
646 if (deleg_blob
!= NULL
) {
647 krb5_data deleg_data
= smb_krb5_data_from_blob(*deleg_blob
);
648 ret
= krb5_pac_add_buffer(context
, pac
,
649 PAC_TYPE_CONSTRAINED_DELEGATION
,
659 bool samba_princ_needs_pac(const struct samba_kdc_entry
*skdc_entry
)
662 uint32_t userAccountControl
;
664 /* The service account may be set not to want the PAC */
665 userAccountControl
= ldb_msg_find_attr_as_uint(skdc_entry
->msg
, "userAccountControl", 0);
666 if (userAccountControl
& UF_NO_AUTH_DATA_REQUIRED
) {
673 static krb5_error_code
samba_client_requested_pac(krb5_context context
,
674 const krb5_const_pac pac
,
678 enum ndr_err_code ndr_err
;
679 krb5_data k5pac_attrs_in
;
680 DATA_BLOB pac_attrs_in
;
681 union PAC_INFO pac_attrs
;
684 *requested_pac
= true;
686 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_ATTRIBUTES_INFO
,
689 return ret
== ENOENT
? 0 : ret
;
692 pac_attrs_in
= data_blob_const(k5pac_attrs_in
.data
,
693 k5pac_attrs_in
.length
);
695 ndr_err
= ndr_pull_union_blob(&pac_attrs_in
, mem_ctx
, &pac_attrs
,
696 PAC_TYPE_ATTRIBUTES_INFO
,
697 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
698 smb_krb5_free_data_contents(context
, &k5pac_attrs_in
);
699 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
700 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
701 DBG_ERR("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status
));
702 return map_errno_from_nt_status(nt_status
);
705 if (pac_attrs
.attributes_info
.flags
& (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
706 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED
)) {
707 *requested_pac
= true;
709 *requested_pac
= false;
715 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
716 int samba_krbtgt_is_in_db(struct samba_kdc_entry
*p
,
722 int rodc_krbtgt_number
, trust_direction
;
726 trust_direction
= ldb_msg_find_attr_as_int(p
->msg
, "trustDirection", 0);
728 if (trust_direction
!= 0) {
729 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
731 This is exactly where we should flag for SID
732 validation when we do inter-forest trusts
739 /* The lack of password controls etc applies to krbtgt by
740 * virtue of being that particular RID */
741 ret
= samdb_result_dom_sid_buf(p
->msg
, "objectSid", &sid
);
746 status
= dom_sid_split_rid(NULL
, &sid
, NULL
, &rid
);
747 if (!NT_STATUS_IS_OK(status
)) {
748 return map_errno_from_nt_status(status
);
751 rodc_krbtgt_number
= ldb_msg_find_attr_as_int(p
->msg
, "msDS-SecondaryKrbTgtNumber", -1);
753 if (p
->kdc_db_ctx
->my_krbtgt_number
== 0) {
754 if (rid
== DOMAIN_RID_KRBTGT
) {
758 } else if (rodc_krbtgt_number
!= -1) {
763 } else if ((rid
!= DOMAIN_RID_KRBTGT
) && (rodc_krbtgt_number
== p
->kdc_db_ctx
->my_krbtgt_number
)) {
767 } else if (rid
== DOMAIN_RID_KRBTGT
) {
768 /* krbtgt viewed from an RODC */
781 * Because the KDC does not limit protocol transition, two new well-known SIDs
782 * were introduced to give this control to the resource administrator. These
783 * SIDs identify whether protocol transition has occurred, and can be used with
784 * standard access control lists to grant or limit access as needed.
786 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
788 NTSTATUS
samba_kdc_add_asserted_identity(enum samba_asserted_identity ai
,
789 struct auth_user_info_dc
*user_info_dc
)
791 struct dom_sid ai_sid
;
792 const char *sid_str
= NULL
;
795 case SAMBA_ASSERTED_IDENTITY_SERVICE
:
796 sid_str
= SID_SERVICE_ASSERTED_IDENTITY
;
798 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
:
799 sid_str
= SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
;
801 case SAMBA_ASSERTED_IDENTITY_IGNORE
:
804 return NT_STATUS_INVALID_PARAMETER
;
807 if (!dom_sid_parse(sid_str
, &ai_sid
)) {
808 return NT_STATUS_UNSUCCESSFUL
;
811 return add_sid_to_array_attrs_unique(
814 SE_GROUP_DEFAULT_FLAGS
,
816 &user_info_dc
->num_sids
);
819 NTSTATUS
samba_kdc_add_claims_valid(enum samba_claims_valid claims_valid
,
820 struct auth_user_info_dc
*user_info_dc
)
822 switch (claims_valid
) {
823 case SAMBA_CLAIMS_VALID_EXCLUDE
:
825 case SAMBA_CLAIMS_VALID_INCLUDE
:
827 struct dom_sid claims_valid_sid
;
829 if (!dom_sid_parse(SID_CLAIMS_VALID
, &claims_valid_sid
)) {
830 return NT_STATUS_UNSUCCESSFUL
;
833 return add_sid_to_array_attrs_unique(
836 SE_GROUP_DEFAULT_FLAGS
,
838 &user_info_dc
->num_sids
);
842 return NT_STATUS_INVALID_PARAMETER
;
845 NTSTATUS
samba_kdc_add_compounded_auth(enum samba_compounded_auth compounded_auth
,
846 struct auth_user_info_dc
*user_info_dc
)
848 switch (compounded_auth
) {
849 case SAMBA_COMPOUNDED_AUTH_EXCLUDE
:
851 case SAMBA_COMPOUNDED_AUTH_INCLUDE
:
853 struct dom_sid compounded_auth_sid
;
855 if (!dom_sid_parse(SID_COMPOUNDED_AUTHENTICATION
, &compounded_auth_sid
)) {
856 return NT_STATUS_UNSUCCESSFUL
;
859 return add_sid_to_array_attrs_unique(
861 &compounded_auth_sid
,
862 SE_GROUP_DEFAULT_FLAGS
,
864 &user_info_dc
->num_sids
);
868 return NT_STATUS_INVALID_PARAMETER
;
872 * Look up the user's info in the database and create a auth_user_info_dc
873 * structure. If the resulting structure is not talloc_free()d, it will be
874 * reused on future calls to this function.
876 NTSTATUS
samba_kdc_get_user_info_from_db(struct samba_kdc_entry
*skdc_entry
,
877 const struct ldb_message
*msg
,
878 const struct auth_user_info_dc
**user_info_dc
)
880 if (skdc_entry
->user_info_dc
== NULL
) {
882 struct loadparm_context
*lp_ctx
= skdc_entry
->kdc_db_ctx
->lp_ctx
;
884 nt_status
= authsam_make_user_info_dc(skdc_entry
,
885 skdc_entry
->kdc_db_ctx
->samdb
,
886 lpcfg_netbios_name(lp_ctx
),
887 lpcfg_sam_name(lp_ctx
),
888 lpcfg_sam_dnsname(lp_ctx
),
889 skdc_entry
->realm_dn
,
893 &skdc_entry
->user_info_dc
);
894 if (!NT_STATUS_IS_OK(nt_status
)) {
899 *user_info_dc
= skdc_entry
->user_info_dc
;
903 NTSTATUS
samba_kdc_get_logon_info_blob(TALLOC_CTX
*mem_ctx
,
904 const struct auth_user_info_dc
*user_info_dc
,
905 const enum auth_group_inclusion group_inclusion
,
906 DATA_BLOB
**_logon_info_blob
)
908 DATA_BLOB
*logon_blob
= NULL
;
911 *_logon_info_blob
= NULL
;
913 logon_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
914 if (logon_blob
== NULL
) {
915 return NT_STATUS_NO_MEMORY
;
918 nt_status
= samba_get_logon_info_pac_blob(logon_blob
,
923 if (!NT_STATUS_IS_OK(nt_status
)) {
924 DBG_ERR("Building PAC LOGON INFO failed: %s\n",
925 nt_errstr(nt_status
));
929 *_logon_info_blob
= logon_blob
;
934 NTSTATUS
samba_kdc_get_cred_ndr_blob(TALLOC_CTX
*mem_ctx
,
935 const struct samba_kdc_entry
*p
,
936 DATA_BLOB
**_cred_ndr_blob
)
938 DATA_BLOB
*cred_blob
= NULL
;
941 SMB_ASSERT(_cred_ndr_blob
!= NULL
);
943 *_cred_ndr_blob
= NULL
;
945 cred_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
946 if (cred_blob
== NULL
) {
947 return NT_STATUS_NO_MEMORY
;
950 nt_status
= samba_get_cred_info_ndr_blob(cred_blob
,
953 if (!NT_STATUS_IS_OK(nt_status
)) {
954 DBG_ERR("Building PAC CRED INFO failed: %s\n",
955 nt_errstr(nt_status
));
959 *_cred_ndr_blob
= cred_blob
;
964 NTSTATUS
samba_kdc_get_upn_info_blob(TALLOC_CTX
*mem_ctx
,
965 const struct auth_user_info_dc
*user_info_dc
,
966 DATA_BLOB
**_upn_info_blob
)
968 DATA_BLOB
*upn_blob
= NULL
;
971 *_upn_info_blob
= NULL
;
973 upn_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
974 if (upn_blob
== NULL
) {
975 return NT_STATUS_NO_MEMORY
;
978 nt_status
= samba_get_upn_info_pac_blob(upn_blob
,
981 if (!NT_STATUS_IS_OK(nt_status
)) {
982 DBG_ERR("Building PAC UPN INFO failed: %s\n",
983 nt_errstr(nt_status
));
987 *_upn_info_blob
= upn_blob
;
992 NTSTATUS
samba_kdc_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
993 uint64_t pac_attributes
,
994 DATA_BLOB
**_pac_attrs_blob
)
996 DATA_BLOB
*pac_attrs_blob
= NULL
;
999 SMB_ASSERT(_pac_attrs_blob
!= NULL
);
1001 *_pac_attrs_blob
= NULL
;
1003 pac_attrs_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1004 if (pac_attrs_blob
== NULL
) {
1005 return NT_STATUS_NO_MEMORY
;
1008 nt_status
= samba_get_pac_attrs_blob(pac_attrs_blob
,
1012 if (!NT_STATUS_IS_OK(nt_status
)) {
1013 DBG_ERR("Building PAC ATTRIBUTES failed: %s\n",
1014 nt_errstr(nt_status
));
1018 *_pac_attrs_blob
= pac_attrs_blob
;
1020 return NT_STATUS_OK
;
1023 NTSTATUS
samba_kdc_get_requester_sid_blob(TALLOC_CTX
*mem_ctx
,
1024 const struct auth_user_info_dc
*user_info_dc
,
1025 DATA_BLOB
**_requester_sid_blob
)
1027 DATA_BLOB
*requester_sid_blob
= NULL
;
1030 SMB_ASSERT(_requester_sid_blob
!= NULL
);
1032 *_requester_sid_blob
= NULL
;
1034 requester_sid_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1035 if (requester_sid_blob
== NULL
) {
1036 return NT_STATUS_NO_MEMORY
;
1039 if (user_info_dc
->num_sids
> 0) {
1040 union PAC_INFO pac_requester_sid
= {};
1041 enum ndr_err_code ndr_err
;
1043 pac_requester_sid
.requester_sid
.sid
= user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1045 ndr_err
= ndr_push_union_blob(requester_sid_blob
, requester_sid_blob
,
1047 PAC_TYPE_REQUESTER_SID
,
1048 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1049 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1050 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1051 DBG_WARNING("PAC_REQUESTER_SID (presig) push failed: %s\n",
1052 nt_errstr(nt_status
));
1053 DBG_ERR("Building PAC REQUESTER SID failed: %s\n",
1054 nt_errstr(nt_status
));
1060 *_requester_sid_blob
= requester_sid_blob
;
1062 return NT_STATUS_OK
;
1065 NTSTATUS
samba_kdc_get_claims_blob(TALLOC_CTX
*mem_ctx
,
1066 const struct samba_kdc_entry
*p
,
1067 const DATA_BLOB
**_claims_blob
)
1069 DATA_BLOB
*claims_blob
= NULL
;
1073 SMB_ASSERT(_claims_blob
!= NULL
);
1075 *_claims_blob
= NULL
;
1077 claims_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1078 if (claims_blob
== NULL
) {
1079 return NT_STATUS_NO_MEMORY
;
1082 ret
= get_claims_blob_for_principal(p
->kdc_db_ctx
->samdb
,
1086 if (ret
!= LDB_SUCCESS
) {
1087 nt_status
= dsdb_ldb_err_to_ntstatus(ret
);
1088 DBG_ERR("Building claims failed: %s\n",
1089 nt_errstr(nt_status
));
1093 *_claims_blob
= claims_blob
;
1095 return NT_STATUS_OK
;
1098 NTSTATUS
samba_kdc_get_user_info_dc(TALLOC_CTX
*mem_ctx
,
1099 struct samba_kdc_entry
*skdc_entry
,
1100 enum samba_asserted_identity asserted_identity
,
1101 enum samba_claims_valid claims_valid
,
1102 enum samba_compounded_auth compounded_auth
,
1103 struct auth_user_info_dc
**user_info_dc_out
)
1106 const struct auth_user_info_dc
*user_info_dc_from_db
= NULL
;
1107 struct auth_user_info_dc
*user_info_dc
= NULL
;
1109 nt_status
= samba_kdc_get_user_info_from_db(skdc_entry
, skdc_entry
->msg
, &user_info_dc_from_db
);
1110 if (!NT_STATUS_IS_OK(nt_status
)) {
1111 DBG_ERR("Getting user info for PAC failed: %s\n",
1112 nt_errstr(nt_status
));
1116 /* Make a shallow copy of the user_info_dc structure. */
1117 nt_status
= authsam_shallow_copy_user_info_dc(mem_ctx
, user_info_dc_from_db
, &user_info_dc
);
1118 if (!NT_STATUS_IS_OK(nt_status
)) {
1119 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
1120 nt_errstr(nt_status
));
1124 /* Here we modify the SIDs to add the Asserted Identity SID. */
1125 nt_status
= samba_kdc_add_asserted_identity(asserted_identity
,
1127 if (!NT_STATUS_IS_OK(nt_status
)) {
1128 DBG_ERR("Failed to add asserted identity: %s\n",
1129 nt_errstr(nt_status
));
1133 nt_status
= samba_kdc_add_claims_valid(claims_valid
,
1135 if (!NT_STATUS_IS_OK(nt_status
)) {
1136 DBG_ERR("Failed to add Claims Valid: %s\n",
1137 nt_errstr(nt_status
));
1141 nt_status
= samba_kdc_add_compounded_auth(compounded_auth
,
1143 if (!NT_STATUS_IS_OK(nt_status
)) {
1144 DBG_ERR("Failed to add Compounded Authentication: %s\n",
1145 nt_errstr(nt_status
));
1149 *user_info_dc_out
= user_info_dc
;
1151 return NT_STATUS_OK
;
1154 static krb5_error_code
samba_kdc_obtain_user_info_dc(TALLOC_CTX
*mem_ctx
,
1155 krb5_context context
,
1156 struct ldb_context
*samdb
,
1157 const enum auth_group_inclusion group_inclusion
,
1158 struct samba_kdc_entry
*skdc_entry
,
1159 const krb5_const_pac pac
,
1160 const bool pac_is_trusted
,
1161 struct auth_user_info_dc
**user_info_dc_out
,
1162 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups_out
)
1164 struct auth_user_info_dc
*user_info_dc
= NULL
;
1165 krb5_error_code ret
= 0;
1168 *user_info_dc_out
= NULL
;
1169 if (resource_groups_out
!= NULL
) {
1170 *resource_groups_out
= NULL
;
1173 if (pac
!= NULL
&& pac_is_trusted
) {
1174 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
1176 if (group_inclusion
== AUTH_EXCLUDE_RESOURCE_GROUPS
) {
1178 * Since we are creating a TGT, resource groups from our domain
1179 * are not to be put into the PAC. Instead, we take the resource
1180 * groups directly from the original PAC and copy them
1181 * unmodified into the new one.
1183 resource_groups
= resource_groups_out
;
1186 ret
= kerberos_pac_to_user_info_dc(mem_ctx
,
1190 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1195 const char *krb5err
= krb5_get_error_message(context
, ret
);
1196 DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1197 krb5err
!= NULL
? krb5err
: "?");
1198 krb5_free_error_message(context
, krb5err
);
1204 * We need to expand group memberships within our local domain,
1205 * as the token might be generated by a trusted domain.
1207 nt_status
= authsam_update_user_info_dc(mem_ctx
,
1210 if (!NT_STATUS_IS_OK(nt_status
)) {
1211 DBG_ERR("authsam_update_user_info_dc failed: %s\n",
1212 nt_errstr(nt_status
));
1214 ret
= map_errno_from_nt_status(nt_status
);
1218 if (skdc_entry
== NULL
) {
1219 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1224 * In this case the RWDC discards the PAC an RODC generated.
1225 * Windows adds the asserted_identity in this case too.
1227 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1228 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1229 * So we can always use
1230 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1233 nt_status
= samba_kdc_get_user_info_dc(mem_ctx
,
1235 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
1236 SAMBA_CLAIMS_VALID_EXCLUDE
,
1237 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
1239 if (!NT_STATUS_IS_OK(nt_status
)) {
1240 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
1241 nt_errstr(nt_status
));
1242 ret
= KRB5KDC_ERR_TGT_REVOKED
;
1247 *user_info_dc_out
= user_info_dc
;
1248 user_info_dc
= NULL
;
1251 TALLOC_FREE(user_info_dc
);
1256 static NTSTATUS
samba_kdc_update_delegation_info_blob(TALLOC_CTX
*mem_ctx
,
1257 krb5_context context
,
1258 const krb5_const_pac pac
,
1259 const krb5_const_principal server_principal
,
1260 const krb5_const_principal proxy_principal
,
1261 DATA_BLOB
*new_blob
)
1263 krb5_data old_data
= {};
1265 krb5_error_code ret
;
1267 enum ndr_err_code ndr_err
;
1268 union PAC_INFO info
= {};
1269 struct PAC_CONSTRAINED_DELEGATION _d
= {};
1270 struct PAC_CONSTRAINED_DELEGATION
*d
= NULL
;
1271 char *server
= NULL
;
1274 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1276 if (tmp_ctx
== NULL
) {
1277 return NT_STATUS_NO_MEMORY
;
1280 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_CONSTRAINED_DELEGATION
, &old_data
);
1281 if (ret
== ENOENT
) {
1284 talloc_free(tmp_ctx
);
1285 return NT_STATUS_UNSUCCESSFUL
;
1288 old_blob
.length
= old_data
.length
;
1289 old_blob
.data
= (uint8_t *)old_data
.data
;
1291 if (old_blob
.length
> 0) {
1292 ndr_err
= ndr_pull_union_blob(&old_blob
, mem_ctx
,
1293 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1294 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1295 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1296 smb_krb5_free_data_contents(context
, &old_data
);
1297 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1298 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1299 talloc_free(tmp_ctx
);
1303 info
.constrained_delegation
.info
= &_d
;
1305 smb_krb5_free_data_contents(context
, &old_data
);
1307 ret
= krb5_unparse_name_flags(context
, server_principal
,
1308 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &server
);
1310 talloc_free(tmp_ctx
);
1311 return NT_STATUS_INTERNAL_ERROR
;
1314 ret
= krb5_unparse_name(context
, proxy_principal
, &proxy
);
1317 talloc_free(tmp_ctx
);
1318 return NT_STATUS_INTERNAL_ERROR
;
1321 d
= info
.constrained_delegation
.info
;
1322 i
= d
->num_transited_services
;
1323 d
->proxy_target
.string
= server
;
1324 d
->transited_services
= talloc_realloc(mem_ctx
, d
->transited_services
,
1325 struct lsa_String
, i
+ 1);
1326 if (d
->transited_services
== NULL
) {
1329 talloc_free(tmp_ctx
);
1330 return NT_STATUS_INTERNAL_ERROR
;
1332 d
->transited_services
[i
].string
= proxy
;
1333 d
->num_transited_services
= i
+ 1;
1335 ndr_err
= ndr_push_union_blob(new_blob
, mem_ctx
,
1336 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1337 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1340 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1341 smb_krb5_free_data_contents(context
, &old_data
);
1342 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1343 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1344 talloc_free(tmp_ctx
);
1348 talloc_free(tmp_ctx
);
1349 return NT_STATUS_OK
;
1352 /* function to map policy errors */
1353 krb5_error_code
samba_kdc_map_policy_err(NTSTATUS nt_status
)
1355 krb5_error_code ret
;
1357 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_MUST_CHANGE
))
1358 ret
= KRB5KDC_ERR_KEY_EXP
;
1359 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_EXPIRED
))
1360 ret
= KRB5KDC_ERR_KEY_EXP
;
1361 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_EXPIRED
))
1362 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1363 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_DISABLED
))
1364 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1365 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_LOGON_HOURS
))
1366 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1367 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_LOCKED_OUT
))
1368 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1369 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_WORKSTATION
))
1370 ret
= KRB5KDC_ERR_POLICY
;
1372 ret
= KRB5KDC_ERR_POLICY
;
1377 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1378 * for consistency */
1379 NTSTATUS
samba_kdc_check_client_access(struct samba_kdc_entry
*kdc_entry
,
1380 const char *client_name
,
1381 const char *workstation
,
1382 bool password_change
)
1384 TALLOC_CTX
*tmp_ctx
;
1387 tmp_ctx
= talloc_named(NULL
, 0, "samba_kdc_check_client_access");
1389 return NT_STATUS_NO_MEMORY
;
1392 /* we allow all kinds of trusts here */
1393 nt_status
= authsam_account_ok(tmp_ctx
,
1394 kdc_entry
->kdc_db_ctx
->samdb
,
1395 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
1396 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
1397 kdc_entry
->realm_dn
, kdc_entry
->msg
,
1398 workstation
, client_name
,
1399 true, password_change
);
1401 kdc_entry
->reject_status
= nt_status
;
1402 talloc_free(tmp_ctx
);
1406 static krb5_error_code
samba_get_requester_sid(TALLOC_CTX
*mem_ctx
,
1408 krb5_context context
,
1409 struct dom_sid
*sid
)
1412 enum ndr_err_code ndr_err
;
1413 krb5_error_code ret
;
1415 DATA_BLOB pac_requester_sid_in
;
1416 krb5_data k5pac_requester_sid_in
;
1418 union PAC_INFO info
;
1420 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1421 if (tmp_ctx
== NULL
) {
1425 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_REQUESTER_SID
,
1426 &k5pac_requester_sid_in
);
1428 talloc_free(tmp_ctx
);
1432 pac_requester_sid_in
= data_blob_const(k5pac_requester_sid_in
.data
,
1433 k5pac_requester_sid_in
.length
);
1435 ndr_err
= ndr_pull_union_blob(&pac_requester_sid_in
, tmp_ctx
, &info
,
1436 PAC_TYPE_REQUESTER_SID
,
1437 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1438 smb_krb5_free_data_contents(context
, &k5pac_requester_sid_in
);
1439 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1440 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1441 DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status
));
1442 talloc_free(tmp_ctx
);
1443 return map_errno_from_nt_status(nt_status
);
1446 *sid
= info
.requester_sid
.sid
;
1448 talloc_free(tmp_ctx
);
1452 /* Does a parse and SID check, but no crypto. */
1453 static krb5_error_code
samba_kdc_validate_pac_blob(
1454 krb5_context context
,
1455 const struct samba_kdc_entry
*client_skdc_entry
,
1456 const krb5_const_pac pac
)
1458 TALLOC_CTX
*frame
= talloc_stackframe();
1459 struct auth_user_info_dc
*pac_user_info
= NULL
;
1460 struct dom_sid client_sid
;
1461 struct dom_sid pac_sid
;
1462 krb5_error_code code
;
1466 * First, try to get the SID from the requester SID buffer in the PAC.
1468 code
= samba_get_requester_sid(frame
, pac
, context
, &pac_sid
);
1470 if (code
== ENOENT
) {
1472 * If the requester SID buffer isn't present, fall back to the
1473 * SID in the LOGON_INFO PAC buffer.
1475 code
= kerberos_pac_to_user_info_dc(frame
,
1479 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1487 if (pac_user_info
->num_sids
== 0) {
1492 pac_sid
= pac_user_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1493 } else if (code
!= 0) {
1497 code
= samdb_result_dom_sid_buf(client_skdc_entry
->msg
,
1504 ok
= dom_sid_equal(&pac_sid
, &client_sid
);
1506 struct dom_sid_buf buf1
;
1507 struct dom_sid_buf buf2
;
1509 DBG_ERR("SID mismatch between PAC and looked up client: "
1510 "PAC[%s] != CLI[%s]\n",
1511 dom_sid_str_buf(&pac_sid
, &buf1
),
1512 dom_sid_str_buf(&client_sid
, &buf2
));
1513 code
= KRB5KDC_ERR_TGT_REVOKED
;
1525 * In the RODC case, to confirm that the returned user is permitted to
1526 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1528 static WERROR
samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids
,
1529 const struct dom_sid
*object_sids
,
1530 const struct samba_kdc_entry
*rodc
,
1531 const struct samba_kdc_entry
*object
)
1535 TALLOC_CTX
*frame
= talloc_stackframe();
1536 const char *rodc_attrs
[] = { "msDS-KrbTgtLink",
1537 "msDS-NeverRevealGroup",
1538 "msDS-RevealOnDemandGroup",
1539 "userAccountControl",
1542 struct ldb_result
*rodc_machine_account
= NULL
;
1543 struct ldb_dn
*rodc_machine_account_dn
= samdb_result_dn(rodc
->kdc_db_ctx
->samdb
,
1546 "msDS-KrbTgtLinkBL",
1548 const struct dom_sid
*rodc_machine_account_sid
= NULL
;
1550 if (rodc_machine_account_dn
== NULL
) {
1551 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1552 ldb_dn_get_linearized(rodc
->msg
->dn
));
1554 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1558 * Follow the link and get the RODC account (the krbtgt
1559 * account is the krbtgt_XXX account, but the
1560 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1561 * the RODC$ account)
1563 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1564 * out of the extended DNs
1567 ret
= dsdb_search_dn(rodc
->kdc_db_ctx
->samdb
,
1569 &rodc_machine_account
,
1570 rodc_machine_account_dn
,
1572 DSDB_SEARCH_SHOW_EXTENDED_DN
);
1573 if (ret
!= LDB_SUCCESS
) {
1574 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1575 ldb_dn_get_linearized(rodc_machine_account_dn
),
1576 ldb_dn_get_linearized(rodc
->msg
->dn
),
1577 ldb_errstring(rodc
->kdc_db_ctx
->samdb
));
1579 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1582 if (rodc_machine_account
->count
!= 1) {
1583 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1584 ldb_dn_get_linearized(rodc_machine_account_dn
),
1585 ldb_dn_get_linearized(rodc
->msg
->dn
),
1586 rodc_machine_account
->count
);
1588 return WERR_DS_DRA_BAD_DN
;
1591 /* if the object SID is equal to the user_sid, allow */
1592 rodc_machine_account_sid
= samdb_result_dom_sid(frame
,
1593 rodc_machine_account
->msgs
[0],
1595 if (rodc_machine_account_sid
== NULL
) {
1597 return WERR_DS_DRA_BAD_DN
;
1600 werr
= samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc
->kdc_db_ctx
->samdb
,
1601 rodc_machine_account_sid
,
1602 rodc_machine_account
->msgs
[0],
1612 * Perform an access check for the client attempting to authenticate to the
1613 * server. ‘client_info’ must be talloc-allocated so that we can make a
1616 krb5_error_code
samba_kdc_allowed_to_authenticate_to(TALLOC_CTX
*mem_ctx
,
1617 struct ldb_context
*samdb
,
1618 struct loadparm_context
*lp_ctx
,
1619 const struct samba_kdc_entry
*client
,
1620 const struct auth_user_info_dc
*client_info
,
1621 const struct samba_kdc_entry
*server
,
1622 struct authn_audit_info
**server_audit_info_out
,
1623 NTSTATUS
*status_out
)
1625 krb5_error_code ret
= 0;
1627 _UNUSED_ NTSTATUS _status
;
1628 struct dom_sid server_sid
= {};
1629 const struct authn_server_policy
*server_policy
= server
->server_policy
;
1631 if (status_out
!= NULL
) {
1632 *status_out
= NT_STATUS_OK
;
1635 ret
= samdb_result_dom_sid_buf(server
->msg
, "objectSid", &server_sid
);
1638 * Ignore the return status — we are already in an error path,
1639 * and overwriting the real error code with the audit info
1640 * status is unhelpful.
1642 _status
= authn_server_policy_audit_info(mem_ctx
,
1645 AUTHN_AUDIT_EVENT_OTHER_ERROR
,
1646 AUTHN_AUDIT_REASON_NONE
,
1647 dsdb_ldb_err_to_ntstatus(ret
),
1648 server_audit_info_out
);
1652 if (dom_sid_equal(&client_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
, &server_sid
)) {
1653 /* Authenticating to ourselves is always allowed. */
1654 status
= authn_server_policy_audit_info(mem_ctx
,
1657 AUTHN_AUDIT_EVENT_OK
,
1658 AUTHN_AUDIT_REASON_NONE
,
1660 server_audit_info_out
);
1661 if (!NT_STATUS_IS_OK(status
)) {
1662 ret
= KRB5KRB_ERR_GENERIC
;
1667 status
= authn_policy_authenticate_to_service(mem_ctx
,
1670 AUTHN_POLICY_AUTH_TYPE_KERBEROS
,
1673 server_audit_info_out
);
1674 if (!NT_STATUS_IS_OK(status
)) {
1675 if (status_out
!= NULL
) {
1676 *status_out
= status
;
1678 if (NT_STATUS_EQUAL(status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
1679 ret
= KRB5KDC_ERR_POLICY
;
1680 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1681 ret
= KRB5KDC_ERR_POLICY
;
1683 ret
= KRB5KRB_ERR_GENERIC
;
1691 static krb5_error_code
samba_kdc_add_domain_group_sid(TALLOC_CTX
*mem_ctx
,
1692 struct PAC_DEVICE_INFO
*info
,
1693 const struct netr_SidAttr
*sid
)
1699 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_group
= NULL
;
1701 for (i
= 0; i
< info
->domain_group_count
; ++i
) {
1702 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*this_domain_group
1703 = &info
->domain_groups
[i
];
1705 if (dom_sid_in_domain(this_domain_group
->domain_sid
, sid
->sid
)) {
1706 domain_group
= this_domain_group
;
1711 if (domain_group
== NULL
) {
1712 info
->domain_groups
= talloc_realloc(
1714 info
->domain_groups
,
1715 struct PAC_DOMAIN_GROUP_MEMBERSHIP
,
1716 info
->domain_group_count
+ 1);
1717 if (info
->domain_groups
== NULL
) {
1721 domain_group
= &info
->domain_groups
[
1722 info
->domain_group_count
++];
1724 domain_group
->domain_sid
= NULL
;
1726 domain_group
->groups
.count
= 0;
1727 domain_group
->groups
.rids
= NULL
;
1729 status
= dom_sid_split_rid(info
->domain_groups
,
1731 &domain_group
->domain_sid
,
1733 if (!NT_STATUS_IS_OK(status
)) {
1734 return map_errno_from_nt_status(status
);
1737 status
= dom_sid_split_rid(NULL
,
1741 if (!NT_STATUS_IS_OK(status
)) {
1742 return map_errno_from_nt_status(status
);
1746 domain_group
->groups
.rids
= talloc_realloc(info
->domain_groups
,
1747 domain_group
->groups
.rids
,
1748 struct samr_RidWithAttribute
,
1749 domain_group
->groups
.count
+ 1);
1750 if (domain_group
->groups
.rids
== NULL
) {
1754 domain_group
->groups
.rids
[domain_group
->groups
.count
].rid
= rid
;
1755 domain_group
->groups
.rids
[domain_group
->groups
.count
].attributes
= sid
->attributes
;
1757 ++domain_group
->groups
.count
;
1762 static krb5_error_code
samba_kdc_make_device_info(TALLOC_CTX
*mem_ctx
,
1763 const struct netr_SamInfo3
*info3
,
1764 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
1765 union PAC_INFO
*info
)
1767 struct PAC_DEVICE_INFO
*device_info
= NULL
;
1770 *info
= (union PAC_INFO
) {};
1772 info
->device_info
.info
= NULL
;
1774 device_info
= talloc(mem_ctx
, struct PAC_DEVICE_INFO
);
1775 if (device_info
== NULL
) {
1779 device_info
->rid
= info3
->base
.rid
;
1780 device_info
->primary_gid
= info3
->base
.primary_gid
;
1781 device_info
->domain_sid
= info3
->base
.domain_sid
;
1782 device_info
->groups
= info3
->base
.groups
;
1784 device_info
->sid_count
= 0;
1785 device_info
->sids
= NULL
;
1787 if (resource_groups
!= NULL
) {
1789 * The account's resource groups all belong to the same domain,
1790 * so we can add them all in one go.
1792 device_info
->domain_group_count
= 1;
1793 device_info
->domain_groups
= talloc_move(mem_ctx
, &resource_groups
);
1795 device_info
->domain_group_count
= 0;
1796 device_info
->domain_groups
= NULL
;
1799 for (i
= 0; i
< info3
->sidcount
; ++i
) {
1800 const struct netr_SidAttr
*device_sid
= &info3
->sids
[i
];
1802 if (dom_sid_has_account_domain(device_sid
->sid
)) {
1803 krb5_error_code ret
= samba_kdc_add_domain_group_sid(mem_ctx
, device_info
, device_sid
);
1808 device_info
->sids
= talloc_realloc(mem_ctx
, device_info
->sids
,
1809 struct netr_SidAttr
,
1810 device_info
->sid_count
+ 1);
1811 if (device_info
->sids
== NULL
) {
1815 device_info
->sids
[device_info
->sid_count
].sid
= dom_sid_dup(device_info
->sids
, device_sid
->sid
);
1816 if (device_info
->sids
[device_info
->sid_count
].sid
== NULL
) {
1820 device_info
->sids
[device_info
->sid_count
].attributes
= device_sid
->attributes
;
1822 ++device_info
->sid_count
;
1826 info
->device_info
.info
= device_info
;
1831 static krb5_error_code
samba_kdc_update_device_info(TALLOC_CTX
*mem_ctx
,
1832 struct ldb_context
*samdb
,
1833 const union PAC_INFO
*logon_info
,
1834 struct PAC_DEVICE_INFO
*device_info
)
1837 struct auth_user_info_dc
*device_info_dc
= NULL
;
1838 union netr_Validation validation
;
1840 uint32_t num_existing_sids
;
1843 * This does a bit of unnecessary work, setting up fields we don't care
1844 * about -- we only want the SIDs.
1846 validation
.sam3
= &logon_info
->logon_info
.info
->info3
;
1847 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
1848 true, /* This user was authenticated */
1850 if (!NT_STATUS_IS_OK(nt_status
)) {
1851 return map_errno_from_nt_status(nt_status
);
1854 num_existing_sids
= device_info_dc
->num_sids
;
1857 * We need to expand group memberships within our local domain,
1858 * as the token might be generated by a trusted domain.
1860 nt_status
= authsam_update_user_info_dc(mem_ctx
,
1863 if (!NT_STATUS_IS_OK(nt_status
)) {
1864 return map_errno_from_nt_status(nt_status
);
1867 for (i
= num_existing_sids
; i
< device_info_dc
->num_sids
; ++i
) {
1868 struct auth_SidAttr
*device_sid
= &device_info_dc
->sids
[i
];
1869 const struct netr_SidAttr sid
= (struct netr_SidAttr
) {
1870 .sid
= &device_sid
->sid
,
1871 .attributes
= device_sid
->attrs
,
1874 krb5_error_code ret
= samba_kdc_add_domain_group_sid(mem_ctx
, device_info
, &sid
);
1883 static krb5_error_code
samba_kdc_get_device_info_pac_blob(TALLOC_CTX
*mem_ctx
,
1884 union PAC_INFO
*info
,
1885 DATA_BLOB
**device_info_blob
)
1887 enum ndr_err_code ndr_err
;
1889 *device_info_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1890 if (*device_info_blob
== NULL
) {
1891 DBG_ERR("Out of memory\n");
1895 ndr_err
= ndr_push_union_blob(*device_info_blob
, *device_info_blob
,
1896 info
, PAC_TYPE_DEVICE_INFO
,
1897 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1898 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1899 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1900 DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
1901 nt_errstr(nt_status
));
1902 return map_errno_from_nt_status(nt_status
);
1908 static krb5_error_code
samba_kdc_create_device_info_blob(TALLOC_CTX
*mem_ctx
,
1909 krb5_context context
,
1910 struct ldb_context
*samdb
,
1911 const krb5_const_pac device_pac
,
1912 DATA_BLOB
**device_info_blob
)
1914 TALLOC_CTX
*frame
= NULL
;
1915 krb5_data device_logon_info
;
1916 krb5_error_code code
= EINVAL
;
1919 union PAC_INFO info
;
1920 enum ndr_err_code ndr_err
;
1921 DATA_BLOB device_logon_info_blob
;
1923 union PAC_INFO logon_info
;
1925 code
= krb5_pac_get_buffer(context
, device_pac
,
1926 PAC_TYPE_LOGON_INFO
,
1927 &device_logon_info
);
1929 if (code
== ENOENT
) {
1930 DBG_ERR("Device PAC is missing LOGON_INFO\n");
1932 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
1937 frame
= talloc_stackframe();
1939 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
1940 device_logon_info
.length
);
1942 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &logon_info
,
1943 PAC_TYPE_LOGON_INFO
,
1944 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1945 smb_krb5_free_data_contents(context
, &device_logon_info
);
1946 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1947 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1948 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
1949 nt_errstr(nt_status
));
1951 return map_errno_from_nt_status(nt_status
);
1955 * When creating the device info structure, existing resource groups are
1958 code
= samba_kdc_make_device_info(frame
,
1959 &logon_info
.logon_info
.info
->info3
,
1960 NULL
, /* resource_groups */
1967 code
= samba_kdc_update_device_info(frame
,
1970 info
.device_info
.info
);
1976 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
1984 static krb5_error_code
samba_kdc_get_device_info_blob(TALLOC_CTX
*mem_ctx
,
1985 struct samba_kdc_entry
*device
,
1986 DATA_BLOB
**device_info_blob
)
1988 TALLOC_CTX
*frame
= NULL
;
1989 krb5_error_code code
= EINVAL
;
1992 struct auth_user_info_dc
*device_info_dc
= NULL
;
1993 struct netr_SamInfo3
*info3
= NULL
;
1994 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
1996 union PAC_INFO info
;
1998 frame
= talloc_stackframe();
2000 nt_status
= samba_kdc_get_user_info_dc(frame
,
2002 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
2003 SAMBA_CLAIMS_VALID_INCLUDE
,
2004 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
2006 if (!NT_STATUS_IS_OK(nt_status
)) {
2007 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2008 nt_errstr(nt_status
));
2010 return KRB5KDC_ERR_TGT_REVOKED
;
2013 nt_status
= auth_convert_user_info_dc_saminfo3(frame
, device_info_dc
,
2014 AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
,
2017 if (!NT_STATUS_IS_OK(nt_status
)) {
2018 DBG_WARNING("Getting Samba info failed: %s\n",
2019 nt_errstr(nt_status
));
2021 return nt_status_to_krb5(nt_status
);
2024 code
= samba_kdc_make_device_info(frame
,
2033 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2042 * @brief Verify a PAC
2044 * @param mem_ctx A talloc memory context
2046 * @param context A krb5 context
2048 * @param flags Bitwise OR'ed flags
2050 * @param client The client samba kdc entry.
2052 * @param krbtgt The krbtgt samba kdc entry.
2054 * @param device The computer's samba kdc entry; used for compound
2057 * @param device_pac The PAC from the computer's TGT; used
2058 * for compound authentication.
2060 * @param pac The PAC
2062 * @return A Kerberos error code.
2064 krb5_error_code
samba_kdc_verify_pac(TALLOC_CTX
*mem_ctx
,
2065 krb5_context context
,
2067 struct samba_kdc_entry
*client
,
2068 const struct samba_kdc_entry
*krbtgt
,
2069 const struct samba_kdc_entry
*device
,
2070 const krb5_const_pac
*device_pac
,
2071 const krb5_const_pac pac
)
2073 krb5_error_code code
= EINVAL
;
2075 bool is_trusted
= flags
& SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED
;
2077 struct pac_blobs pac_blobs
;
2078 pac_blobs_init(&pac_blobs
);
2080 if (client
!= NULL
) {
2082 * Check the objectSID of the client and pac data are the same.
2083 * Does a parse and SID check, but no crypto.
2085 code
= samba_kdc_validate_pac_blob(context
,
2093 if (device
!= NULL
) {
2094 SMB_ASSERT(*device_pac
!= NULL
);
2097 * Check the objectSID of the device and pac data are the same.
2098 * Does a parse and SID check, but no crypto.
2100 code
= samba_kdc_validate_pac_blob(context
,
2109 const struct auth_user_info_dc
*user_info_dc
= NULL
;
2112 struct dom_sid
*object_sids
= NULL
;
2115 if (client
== NULL
) {
2116 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2120 nt_status
= samba_kdc_get_user_info_from_db(client
, client
->msg
, &user_info_dc
);
2121 if (!NT_STATUS_IS_OK(nt_status
)) {
2122 DBG_ERR("Getting user info for PAC failed: %s\n",
2123 nt_errstr(nt_status
));
2124 code
= KRB5KDC_ERR_TGT_REVOKED
;
2129 * Check if the SID list in the user_info_dc intersects
2130 * correctly with the RODC allow/deny lists.
2132 object_sids
= talloc_array(mem_ctx
, struct dom_sid
, user_info_dc
->num_sids
);
2133 if (object_sids
== NULL
) {
2138 for (j
= 0; j
< user_info_dc
->num_sids
; ++j
) {
2139 object_sids
[j
] = user_info_dc
->sids
[j
].sid
;
2142 werr
= samba_rodc_confirm_user_is_allowed(user_info_dc
->num_sids
,
2146 TALLOC_FREE(object_sids
);
2147 if (!W_ERROR_IS_OK(werr
)) {
2148 code
= KRB5KDC_ERR_TGT_REVOKED
;
2149 if (W_ERROR_EQUAL(werr
,
2150 WERR_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2151 code
= KRB5KDC_ERR_POLICY
;
2157 * The RODC PAC data isn't trusted for authorization as it may
2158 * be stale. The only thing meaningful we can do with an RODC
2159 * account on a full DC is exchange the RODC TGT for a 'real'
2162 * So we match Windows (at least server 2022) and
2163 * don't allow S4U2Self.
2165 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
2167 if (flags
& SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
) {
2168 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2173 /* Check the types of the given PAC */
2175 code
= pac_blobs_from_krb5_pac(&pac_blobs
,
2183 code
= pac_blobs_ensure_exists(&pac_blobs
,
2184 PAC_TYPE_LOGON_INFO
);
2189 code
= pac_blobs_ensure_exists(&pac_blobs
,
2190 PAC_TYPE_LOGON_NAME
);
2195 code
= pac_blobs_ensure_exists(&pac_blobs
,
2196 PAC_TYPE_SRV_CHECKSUM
);
2201 code
= pac_blobs_ensure_exists(&pac_blobs
,
2202 PAC_TYPE_KDC_CHECKSUM
);
2207 if (!(flags
& SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
)) {
2208 code
= pac_blobs_ensure_exists(&pac_blobs
,
2209 PAC_TYPE_REQUESTER_SID
);
2211 code
= KRB5KDC_ERR_TGT_REVOKED
;
2219 pac_blobs_destroy(&pac_blobs
);
2225 * @brief Update a PAC
2227 * @param mem_ctx A talloc memory context
2229 * @param context A krb5 context
2231 * @param samdb An open samdb connection.
2233 * @param lp_ctx A loadparm context.
2235 * @param flags Bitwise OR'ed flags
2237 * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
2238 * as opposed to an RODC.
2240 * @param client The client samba kdc entry.
2242 * @param client_krbtgt The krbtgt samba kdc entry that verified the client
2244 * @param server_principal The server principal
2246 * @param server The server samba kdc entry.
2248 * @param delegated_proxy_principal The delegated proxy principal used for
2249 * updating the constrained delegation PAC
2252 * @param delegated_proxy The delegated proxy kdc entry.
2254 * @param delegated_proxy_pac The PAC from the primary TGT (i.e., that of
2255 * the delegating service) during a constrained
2256 * delegation request.
2258 * @param device The computer's samba kdc entry; used for compound
2261 * @param device_krbtgt The krbtgt samba kdc entry that verified the device
2263 * @param device_pac The PAC from the computer's TGT; used
2264 * for compound authentication.
2266 * @param old_pac The old PAC
2268 * @param new_pac The new already allocated PAC
2270 * @return A Kerberos error code. If no PAC should be returned, the code will be
2273 krb5_error_code
samba_kdc_update_pac(TALLOC_CTX
*mem_ctx
,
2274 krb5_context context
,
2275 struct ldb_context
*samdb
,
2276 struct loadparm_context
*lp_ctx
,
2278 const struct samba_kdc_entry
*client_krbtgt
,
2279 struct samba_kdc_entry
*client
,
2280 const krb5_const_principal server_principal
,
2281 const struct samba_kdc_entry
*server
,
2282 const krb5_const_principal delegated_proxy_principal
,
2283 struct samba_kdc_entry
*delegated_proxy
,
2284 const krb5_const_pac delegated_proxy_pac
,
2285 const struct samba_kdc_entry
*device_krbtgt
,
2286 struct samba_kdc_entry
*device
,
2287 const krb5_const_pac device_pac
,
2288 const krb5_const_pac old_pac
,
2290 struct authn_audit_info
**server_audit_info_out
,
2291 NTSTATUS
*status_out
)
2293 krb5_error_code code
= EINVAL
;
2295 DATA_BLOB
*pac_blob
= NULL
;
2296 DATA_BLOB
*upn_blob
= NULL
;
2297 DATA_BLOB
*deleg_blob
= NULL
;
2298 DATA_BLOB
*requester_sid_blob
= NULL
;
2299 const DATA_BLOB
*client_claims_blob
= NULL
;
2300 bool client_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED
;
2301 bool device_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_DEVICE_KRBTGT_IS_TRUSTED
;
2302 bool delegated_proxy_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_DELEGATED_PROXY_IS_TRUSTED
;
2303 const DATA_BLOB
*device_claims_blob
= NULL
;
2304 DATA_BLOB
*device_info_blob
= NULL
;
2305 bool is_tgs
= false;
2306 struct auth_user_info_dc
*user_info_dc
= NULL
;
2307 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
2308 enum auth_group_inclusion group_inclusion
;
2309 enum samba_compounded_auth compounded_auth
;
2312 struct pac_blobs pac_blobs
;
2313 pac_blobs_init(&pac_blobs
);
2315 if (server_audit_info_out
!= NULL
) {
2316 *server_audit_info_out
= NULL
;
2319 if (status_out
!= NULL
) {
2320 *status_out
= NT_STATUS_OK
;
2324 int result
= smb_krb5_principal_is_tgs(context
, server_principal
);
2333 /* Only include resource groups in a service ticket. */
2335 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
2336 } else if (server
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
2337 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
2339 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
2342 if (device
!= NULL
&& !is_tgs
) {
2343 compounded_auth
= SAMBA_COMPOUNDED_AUTH_INCLUDE
;
2345 compounded_auth
= SAMBA_COMPOUNDED_AUTH_EXCLUDE
;
2348 if (device
!= NULL
&& !is_tgs
) {
2349 SMB_ASSERT(device_pac
!= NULL
);
2351 if (device_pac_is_trusted
) {
2352 krb5_data device_claims_data
;
2355 * [MS-KILE] 3.3.5.7.4 Compound Identity: the client
2356 * claims from the device PAC become the device claims
2359 code
= krb5_pac_get_buffer(context
, device_pac
,
2360 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2361 &device_claims_data
);
2362 if (code
== ENOENT
) {
2364 } else if (code
!= 0) {
2366 } else if (device_krbtgt
->is_trust
) {
2368 * TODO: we need claim translation over trusts,
2369 * for now we just clear them...
2371 device_claims_blob
= &data_blob_null
;
2373 DATA_BLOB
*device_claims
= NULL
;
2375 device_claims
= talloc_zero(mem_ctx
, DATA_BLOB
);
2376 if (device_claims
== NULL
) {
2377 smb_krb5_free_data_contents(context
, &device_claims_data
);
2382 *device_claims
= data_blob_talloc(mem_ctx
,
2383 device_claims_data
.data
,
2384 device_claims_data
.length
);
2385 if (device_claims
->data
== NULL
&& device_claims_data
.length
!= 0) {
2386 smb_krb5_free_data_contents(context
, &device_claims_data
);
2391 smb_krb5_free_data_contents(context
, &device_claims_data
);
2393 device_claims_blob
= device_claims
;
2396 code
= samba_kdc_create_device_info_blob(mem_ctx
,
2405 /* Don't trust RODC-issued claims. Regenerate them. */
2406 nt_status
= samba_kdc_get_claims_blob(mem_ctx
,
2408 &device_claims_blob
);
2409 if (!NT_STATUS_IS_OK(nt_status
)) {
2410 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2411 nt_errstr(nt_status
));
2412 code
= map_errno_from_nt_status(nt_status
);
2416 /* Also regenerate device info. */
2417 code
= samba_kdc_get_device_info_blob(mem_ctx
,
2426 if (delegated_proxy_principal
!= NULL
) {
2427 deleg_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2428 if (deleg_blob
== NULL
) {
2433 nt_status
= samba_kdc_update_delegation_info_blob(
2438 delegated_proxy_principal
,
2440 if (!NT_STATUS_IS_OK(nt_status
)) {
2441 DBG_ERR("update delegation info blob failed: %s\n",
2442 nt_errstr(nt_status
));
2443 code
= map_errno_from_nt_status(nt_status
);
2448 code
= samba_kdc_obtain_user_info_dc(mem_ctx
,
2454 client_pac_is_trusted
,
2458 const char *err_str
= krb5_get_error_message(context
, code
);
2459 DBG_ERR("samba_kdc_obtain_user_info_dc failed: %s\n",
2460 err_str
!= NULL
? err_str
: "<unknown>");
2461 krb5_free_error_message(context
, err_str
);
2467 * Enforce the AllowedToAuthenticateTo part of an authentication policy,
2468 * if one is present.
2470 if (!is_tgs
&& authn_policy_restrictions_present(server
->server_policy
)) {
2471 const struct samba_kdc_entry
*auth_entry
= NULL
;
2472 struct auth_user_info_dc
*auth_user_info_dc
= NULL
;
2474 if (delegated_proxy
!= NULL
) {
2475 auth_entry
= delegated_proxy
;
2477 code
= samba_kdc_obtain_user_info_dc(mem_ctx
,
2480 AUTH_INCLUDE_RESOURCE_GROUPS
,
2482 delegated_proxy_pac
,
2483 delegated_proxy_pac_is_trusted
,
2490 auth_entry
= client
;
2491 auth_user_info_dc
= user_info_dc
;
2494 code
= samba_kdc_allowed_to_authenticate_to(mem_ctx
,
2500 server_audit_info_out
,
2502 if (auth_user_info_dc
!= user_info_dc
) {
2503 talloc_unlink(mem_ctx
, auth_user_info_dc
);
2510 nt_status
= samba_kdc_add_compounded_auth(compounded_auth
,
2512 if (!NT_STATUS_IS_OK(nt_status
)) {
2513 DBG_ERR("Failed to add Compounded Authentication: %s\n",
2514 nt_errstr(nt_status
));
2516 code
= KRB5KDC_ERR_TGT_REVOKED
;
2520 if (client_pac_is_trusted
) {
2521 pac_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2522 if (pac_blob
== NULL
) {
2527 nt_status
= samba_get_logon_info_pac_blob(mem_ctx
,
2532 if (!NT_STATUS_IS_OK(nt_status
)) {
2533 DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
2534 nt_errstr(nt_status
));
2536 code
= map_errno_from_nt_status(nt_status
);
2541 * TODO: we need claim translation over trusts,
2542 * for now we just clear them...
2544 if (client_krbtgt
->is_trust
) {
2545 client_claims_blob
= &data_blob_null
;
2548 nt_status
= samba_kdc_get_logon_info_blob(mem_ctx
,
2552 if (!NT_STATUS_IS_OK(nt_status
)) {
2553 DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
2554 nt_errstr(nt_status
));
2555 code
= KRB5KDC_ERR_TGT_REVOKED
;
2559 nt_status
= samba_kdc_get_upn_info_blob(mem_ctx
,
2562 if (!NT_STATUS_IS_OK(nt_status
)) {
2563 DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
2564 nt_errstr(nt_status
));
2565 code
= KRB5KDC_ERR_TGT_REVOKED
;
2569 nt_status
= samba_kdc_get_requester_sid_blob(mem_ctx
,
2571 &requester_sid_blob
);
2572 if (!NT_STATUS_IS_OK(nt_status
)) {
2573 DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
2574 nt_errstr(nt_status
));
2575 code
= KRB5KDC_ERR_TGT_REVOKED
;
2579 /* Don't trust RODC-issued claims. Regenerate them. */
2580 nt_status
= samba_kdc_get_claims_blob(mem_ctx
,
2582 &client_claims_blob
);
2583 if (!NT_STATUS_IS_OK(nt_status
)) {
2584 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2585 nt_errstr(nt_status
));
2586 code
= map_errno_from_nt_status(nt_status
);
2591 /* Check the types of the given PAC */
2592 code
= pac_blobs_from_krb5_pac(&pac_blobs
,
2600 code
= pac_blobs_replace_existing(&pac_blobs
,
2601 PAC_TYPE_LOGON_INFO
,
2607 #ifdef SAMBA4_USES_HEIMDAL
2608 /* Not needed with MIT Kerberos */
2609 code
= pac_blobs_replace_existing(&pac_blobs
,
2610 PAC_TYPE_LOGON_NAME
,
2616 code
= pac_blobs_replace_existing(&pac_blobs
,
2617 PAC_TYPE_SRV_CHECKSUM
,
2623 code
= pac_blobs_replace_existing(&pac_blobs
,
2624 PAC_TYPE_KDC_CHECKSUM
,
2631 code
= pac_blobs_add_blob(&pac_blobs
,
2633 PAC_TYPE_CONSTRAINED_DELEGATION
,
2639 code
= pac_blobs_add_blob(&pac_blobs
,
2641 PAC_TYPE_UPN_DNS_INFO
,
2647 code
= pac_blobs_add_blob(&pac_blobs
,
2649 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2650 client_claims_blob
);
2655 code
= pac_blobs_add_blob(&pac_blobs
,
2657 PAC_TYPE_DEVICE_INFO
,
2663 code
= pac_blobs_add_blob(&pac_blobs
,
2665 PAC_TYPE_DEVICE_CLAIMS_INFO
,
2666 device_claims_blob
);
2671 if (!client_pac_is_trusted
|| !is_tgs
) {
2672 code
= pac_blobs_remove_blob(&pac_blobs
,
2674 PAC_TYPE_ATTRIBUTES_INFO
);
2681 code
= pac_blobs_remove_blob(&pac_blobs
,
2683 PAC_TYPE_REQUESTER_SID
);
2688 code
= pac_blobs_add_blob(&pac_blobs
,
2690 PAC_TYPE_REQUESTER_SID
,
2691 requester_sid_blob
);
2698 * The server account may be set not to want the PAC.
2700 * While this is wasteful if the above calculations were done
2701 * and now thrown away, this is cleaner as we do any ticket
2702 * signature checking etc always.
2704 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
2705 * time (eg not accepting a ticket from the RODC) we do not
2706 * need to re-generate anything anyway.
2708 if (!samba_princ_needs_pac(server
)) {
2713 if (client_pac_is_trusted
&& !is_tgs
) {
2715 * The client may have requested no PAC when obtaining the
2718 bool requested_pac
= false;
2720 code
= samba_client_requested_pac(context
,
2724 if (code
!= 0 || !requested_pac
) {
2725 if (!requested_pac
) {
2732 for (i
= 0; i
< pac_blobs
.num_types
; ++i
) {
2733 krb5_data type_data
;
2734 const DATA_BLOB
*type_blob
= pac_blobs
.type_blobs
[i
].data
;
2735 uint32_t type
= pac_blobs
.type_blobs
[i
].type
;
2737 static char null_byte
= '\0';
2738 const krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
2740 #ifndef SAMBA4_USES_HEIMDAL
2741 /* Not needed with MIT Kerberos */
2743 case PAC_TYPE_LOGON_NAME
:
2744 case PAC_TYPE_SRV_CHECKSUM
:
2745 case PAC_TYPE_KDC_CHECKSUM
:
2746 case PAC_TYPE_FULL_CHECKSUM
:
2753 if (type_blob
!= NULL
) {
2754 type_data
= smb_krb5_data_from_blob(*type_blob
);
2756 * Passing a NULL pointer into krb5_pac_add_buffer() is
2757 * not allowed, so pass null_data instead if needed.
2759 code
= krb5_pac_add_buffer(context
,
2762 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2764 code
= krb5_pac_get_buffer(context
,
2772 * Passing a NULL pointer into krb5_pac_add_buffer() is
2773 * not allowed, so pass null_data instead if needed.
2775 code
= krb5_pac_add_buffer(context
,
2778 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2779 smb_krb5_free_data_contents(context
, &type_data
);
2789 pac_blobs_destroy(&pac_blobs
);
2790 TALLOC_FREE(pac_blob
);
2791 TALLOC_FREE(upn_blob
);
2792 TALLOC_FREE(deleg_blob
);
2794 * Release our handle to user_info_dc. ‘server_audit_info_out’, if
2795 * non-NULL, becomes the new parent.
2797 talloc_unlink(mem_ctx
, user_info_dc
);
2801 krb5_error_code
samba_kdc_check_device(TALLOC_CTX
*mem_ctx
,
2802 krb5_context context
,
2803 struct ldb_context
*samdb
,
2804 struct loadparm_context
*lp_ctx
,
2805 struct samba_kdc_entry
*device
,
2806 const krb5_const_pac device_pac
,
2807 const bool device_pac_is_trusted
,
2808 const struct authn_kerberos_client_policy
*client_policy
,
2809 struct authn_audit_info
**client_audit_info_out
,
2810 NTSTATUS
*status_out
)
2812 TALLOC_CTX
*frame
= NULL
;
2813 krb5_error_code code
= 0;
2815 struct auth_user_info_dc
*device_info
= NULL
;
2816 struct authn_audit_info
*client_audit_info
= NULL
;
2818 if (status_out
!= NULL
) {
2819 *status_out
= NT_STATUS_OK
;
2822 if (!authn_policy_device_restrictions_present(client_policy
)) {
2826 if (device
== NULL
|| device_pac
== NULL
) {
2827 NTSTATUS out_status
= NT_STATUS_INVALID_WORKSTATION
;
2829 nt_status
= authn_kerberos_client_policy_audit_info(mem_ctx
,
2831 NULL
/* client_info */,
2832 AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION
,
2833 AUTHN_AUDIT_REASON_FAST_REQUIRED
,
2835 client_audit_info_out
);
2836 if (!NT_STATUS_IS_OK(nt_status
)) {
2837 code
= KRB5KRB_ERR_GENERIC
;
2838 } else if (authn_kerberos_client_policy_is_enforced(client_policy
)) {
2839 code
= KRB5KDC_ERR_POLICY
;
2841 if (status_out
!= NULL
) {
2842 *status_out
= out_status
;
2852 frame
= talloc_stackframe();
2854 if (device_pac_is_trusted
) {
2855 krb5_data device_logon_info
;
2857 enum ndr_err_code ndr_err
;
2858 DATA_BLOB device_logon_info_blob
;
2860 union PAC_INFO pac_logon_info
;
2861 union netr_Validation validation
;
2863 code
= krb5_pac_get_buffer(context
, device_pac
,
2864 PAC_TYPE_LOGON_INFO
,
2865 &device_logon_info
);
2867 if (code
== ENOENT
) {
2868 DBG_ERR("Device PAC is missing LOGON_INFO\n");
2870 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
2876 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
2877 device_logon_info
.length
);
2879 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &pac_logon_info
,
2880 PAC_TYPE_LOGON_INFO
,
2881 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
2882 smb_krb5_free_data_contents(context
, &device_logon_info
);
2883 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2884 nt_status
= ndr_map_error2ntstatus(ndr_err
);
2885 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
2886 nt_errstr(nt_status
));
2888 code
= ndr_map_error2errno(ndr_err
);
2893 * This does a bit of unnecessary work, setting up fields we
2894 * don’t care about — we only want the SIDs.
2896 validation
.sam3
= &pac_logon_info
.logon_info
.info
->info3
;
2897 nt_status
= make_user_info_dc_netlogon_validation(frame
, "", 3, &validation
,
2898 true, /* This user was authenticated */
2900 if (!NT_STATUS_IS_OK(nt_status
)) {
2901 code
= map_errno_from_nt_status(nt_status
);
2906 * We need to expand group memberships within our local domain,
2907 * as the token might be generated by a trusted domain.
2909 nt_status
= authsam_update_user_info_dc(frame
,
2912 if (!NT_STATUS_IS_OK(nt_status
)) {
2913 code
= map_errno_from_nt_status(nt_status
);
2917 nt_status
= samba_kdc_get_user_info_dc(frame
,
2919 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
2920 SAMBA_CLAIMS_VALID_INCLUDE
,
2921 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
2923 if (!NT_STATUS_IS_OK(nt_status
)) {
2924 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2925 nt_errstr(nt_status
));
2927 code
= KRB5KDC_ERR_TGT_REVOKED
;
2932 nt_status
= authn_policy_authenticate_from_device(frame
,
2937 &client_audit_info
);
2938 if (client_audit_info
!= NULL
) {
2939 *client_audit_info_out
= talloc_move(mem_ctx
, &client_audit_info
);
2941 if (!NT_STATUS_IS_OK(nt_status
)) {
2942 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
2943 code
= KRB5KDC_ERR_POLICY
;
2945 code
= KRB5KRB_ERR_GENERIC
;