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_requester_sid_pac_blob(TALLOC_CTX
*mem_ctx
,
133 const struct auth_user_info_dc
*info
,
134 DATA_BLOB
*requester_sid_blob
)
136 enum ndr_err_code ndr_err
;
139 if (requester_sid_blob
!= NULL
) {
140 *requester_sid_blob
= data_blob_null
;
143 if (requester_sid_blob
!= NULL
&& info
->num_sids
> 0) {
144 union PAC_INFO pac_requester_sid
= {};
146 pac_requester_sid
.requester_sid
.sid
= info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
148 ndr_err
= ndr_push_union_blob(requester_sid_blob
, mem_ctx
,
150 PAC_TYPE_REQUESTER_SID
,
151 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
152 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
153 nt_status
= ndr_map_error2ntstatus(ndr_err
);
154 DBG_WARNING("PAC_REQUESTER_SID (presig) push failed: %s\n",
155 nt_errstr(nt_status
));
164 NTSTATUS
samba_get_upn_info_pac_blob(TALLOC_CTX
*mem_ctx
,
165 const struct auth_user_info_dc
*info
,
168 union PAC_INFO pac_upn
= {};
169 enum ndr_err_code ndr_err
;
173 *upn_data
= data_blob_null
;
175 pac_upn
.upn_dns_info
.upn_name
= info
->info
->user_principal_name
;
176 pac_upn
.upn_dns_info
.dns_domain_name
= strupper_talloc(mem_ctx
,
177 info
->info
->dns_domain_name
);
178 if (pac_upn
.upn_dns_info
.dns_domain_name
== NULL
) {
179 return NT_STATUS_NO_MEMORY
;
181 if (info
->info
->user_principal_constructed
) {
182 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_CONSTRUCTED
;
185 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
;
187 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.samaccountname
188 = info
->info
->account_name
;
190 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.objectsid
191 = &info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
193 ndr_err
= ndr_push_union_blob(upn_data
, mem_ctx
, &pac_upn
,
194 PAC_TYPE_UPN_DNS_INFO
,
195 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
196 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
197 nt_status
= ndr_map_error2ntstatus(ndr_err
);
198 DBG_WARNING("PAC UPN_DNS_INFO (presig) push failed: %s\n",
199 nt_errstr(nt_status
));
203 ok
= data_blob_pad(mem_ctx
, upn_data
, 8);
205 return NT_STATUS_NO_MEMORY
;
212 NTSTATUS
samba_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
213 uint64_t pac_attributes
,
214 DATA_BLOB
*pac_attrs_data
)
216 union PAC_INFO pac_attrs
= {};
217 enum ndr_err_code ndr_err
;
220 *pac_attrs_data
= data_blob_null
;
222 /* Set the length of the flags in bits. */
223 pac_attrs
.attributes_info
.flags_length
= 2;
224 pac_attrs
.attributes_info
.flags
= pac_attributes
;
226 ndr_err
= ndr_push_union_blob(pac_attrs_data
, mem_ctx
, &pac_attrs
,
227 PAC_TYPE_ATTRIBUTES_INFO
,
228 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
229 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
230 nt_status
= ndr_map_error2ntstatus(ndr_err
);
231 DBG_WARNING("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
232 nt_errstr(nt_status
));
240 NTSTATUS
samba_get_cred_info_ndr_blob(TALLOC_CTX
*mem_ctx
,
241 const struct ldb_message
*msg
,
242 DATA_BLOB
*cred_blob
)
244 enum ndr_err_code ndr_err
;
246 struct samr_Password
*lm_hash
= NULL
;
247 struct samr_Password
*nt_hash
= NULL
;
248 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg
= {
251 DATA_BLOB ntlm_blob
= data_blob_null
;
252 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs
[1] = {{
253 .credential_size
= 0,
255 struct PAC_CREDENTIAL_DATA cred_data
= {
256 .credential_count
= 0,
258 struct PAC_CREDENTIAL_DATA_NDR cred_ndr
= {};
260 *cred_blob
= data_blob_null
;
262 lm_hash
= samdb_result_hash(mem_ctx
, msg
, "dBCSPwd");
263 if (lm_hash
!= NULL
) {
264 bool zero
= all_zero(lm_hash
->hash
, 16);
269 if (lm_hash
!= NULL
) {
270 DBG_INFO("Passing LM password hash through credentials set\n");
271 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_LM_HASH
;
272 ntlm_secpkg
.lm_password
= *lm_hash
;
273 ZERO_STRUCTP(lm_hash
);
274 TALLOC_FREE(lm_hash
);
277 nt_hash
= samdb_result_hash(mem_ctx
, msg
, "unicodePwd");
278 if (nt_hash
!= NULL
) {
279 bool zero
= all_zero(nt_hash
->hash
, 16);
284 if (nt_hash
!= NULL
) {
285 DBG_INFO("Passing NT password hash through credentials set\n");
286 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_NT_HASH
;
287 ntlm_secpkg
.nt_password
= *nt_hash
;
288 ZERO_STRUCTP(nt_hash
);
289 TALLOC_FREE(nt_hash
);
292 if (ntlm_secpkg
.flags
== 0) {
296 #ifdef DEBUG_PASSWORD
298 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG
, &ntlm_secpkg
);
302 ndr_err
= ndr_push_struct_blob(&ntlm_blob
, mem_ctx
, &ntlm_secpkg
,
303 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG
);
304 ZERO_STRUCT(ntlm_secpkg
);
305 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
306 nt_status
= ndr_map_error2ntstatus(ndr_err
);
307 DBG_WARNING("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
308 nt_errstr(nt_status
));
312 DBG_DEBUG("NTLM credential BLOB (len %zu) for user\n",
314 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
315 ntlm_blob
.data
, ntlm_blob
.length
);
317 secpkgs
[0].package_name
.string
= discard_const_p(char, "NTLM");
318 secpkgs
[0].credential_size
= ntlm_blob
.length
;
319 secpkgs
[0].credential
= ntlm_blob
.data
;
321 cred_data
.credential_count
= ARRAY_SIZE(secpkgs
);
322 cred_data
.credentials
= secpkgs
;
324 #ifdef DEBUG_PASSWORD
326 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA
, &cred_data
);
330 cred_ndr
.ctr
.data
= &cred_data
;
332 #ifdef DEBUG_PASSWORD
334 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR
, &cred_ndr
);
338 ndr_err
= ndr_push_struct_blob(cred_blob
, mem_ctx
, &cred_ndr
,
339 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_DATA_NDR
);
340 data_blob_clear(&ntlm_blob
);
341 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
342 nt_status
= ndr_map_error2ntstatus(ndr_err
);
343 DBG_WARNING("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
344 nt_errstr(nt_status
));
348 DBG_DEBUG("Created credential BLOB (len %zu) for user\n",
350 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
351 cred_blob
->data
, cred_blob
->length
);
356 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
357 const krb5_keyblock
*pkreplykey
,
358 const DATA_BLOB
*cred_ndr_blob
,
360 DATA_BLOB
*cred_info_blob
)
362 #ifdef SAMBA4_USES_HEIMDAL
363 krb5_crypto cred_crypto
;
364 krb5_enctype cred_enctype
;
365 krb5_data cred_ndr_crypt
;
366 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
369 enum ndr_err_code ndr_err
;
372 *cred_info_blob
= data_blob_null
;
374 ret
= krb5_crypto_init(context
, pkreplykey
, ETYPE_NULL
,
377 krb5err
= krb5_get_error_message(context
, ret
);
378 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
379 krb5_free_error_message(context
, krb5err
);
383 ret
= krb5_crypto_getenctype(context
, cred_crypto
, &cred_enctype
);
385 DBG_WARNING("Failed getting crypto type for key\n");
386 krb5_crypto_destroy(context
, cred_crypto
);
390 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
391 cred_ndr_blob
->length
);
392 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
393 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
395 ret
= krb5_encrypt(context
, cred_crypto
,
396 KRB5_KU_OTHER_ENCRYPTED
,
397 cred_ndr_blob
->data
, cred_ndr_blob
->length
,
399 krb5_crypto_destroy(context
, cred_crypto
);
401 krb5err
= krb5_get_error_message(context
, ret
);
402 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err
);
403 krb5_free_error_message(context
, krb5err
);
407 pac_cred_info
.encryption_type
= cred_enctype
;
408 pac_cred_info
.encrypted_data
.length
= cred_ndr_crypt
.length
;
409 pac_cred_info
.encrypted_data
.data
= (uint8_t *)cred_ndr_crypt
.data
;
412 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
415 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
416 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
417 krb5_data_free(&cred_ndr_crypt
);
418 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
419 nt_status
= ndr_map_error2ntstatus(ndr_err
);
420 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
421 nt_errstr(nt_status
));
422 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
425 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
426 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
427 dump_data_pw("PAC_CREDENTIAL_INFO",
428 cred_info_blob
->data
, cred_info_blob
->length
);
431 #else /* SAMBA4_USES_HEIMDAL */
433 krb5_enctype cred_enctype
;
434 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
435 krb5_error_code code
;
437 enum ndr_err_code ndr_err
;
439 krb5_data cred_ndr_data
;
440 krb5_enc_data cred_ndr_crypt
;
443 *cred_info_blob
= data_blob_null
;
445 code
= krb5_k_create_key(context
,
449 krb5err
= krb5_get_error_message(context
, code
);
450 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
451 krb5_free_error_message(context
, krb5err
);
455 cred_enctype
= krb5_k_key_enctype(context
, cred_key
);
457 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
458 cred_ndr_blob
->length
);
459 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
460 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
462 pac_cred_info
.encryption_type
= cred_enctype
;
464 cred_ndr_data
= smb_krb5_data_from_blob(*cred_ndr_blob
);
466 code
= krb5_c_encrypt_length(context
,
468 cred_ndr_data
.length
,
471 krb5err
= krb5_get_error_message(context
, code
);
472 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
473 krb5_free_error_message(context
, krb5err
);
477 pac_cred_info
.encrypted_data
= data_blob_talloc_zero(mem_ctx
, enc_len
);
478 if (pac_cred_info
.encrypted_data
.data
== NULL
) {
479 DBG_ERR("Out of memory\n");
483 cred_ndr_crypt
.ciphertext
= smb_krb5_data_from_blob(pac_cred_info
.encrypted_data
);
485 code
= krb5_k_encrypt(context
,
487 KRB5_KU_OTHER_ENCRYPTED
,
491 krb5_k_free_key(context
, cred_key
);
493 krb5err
= krb5_get_error_message(context
, code
);
494 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err
);
495 krb5_free_error_message(context
, krb5err
);
500 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
503 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
504 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
505 TALLOC_FREE(pac_cred_info
.encrypted_data
.data
);
506 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
507 nt_status
= ndr_map_error2ntstatus(ndr_err
);
508 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
509 nt_errstr(nt_status
));
510 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
513 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
514 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
515 dump_data_pw("PAC_CREDENTIAL_INFO",
516 cred_info_blob
->data
, cred_info_blob
->length
);
519 #endif /* SAMBA4_USES_HEIMDAL */
524 * @brief Create a PAC with the given blobs (logon, credentials, upn and
527 * @param[in] context The KRB5 context to use.
529 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
530 * use NULL to ignore it.
532 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
533 * blob, use NULL to ignore it.
535 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
538 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
539 * blob, use NULL to ignore it.
541 * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
542 * given blob, use NULL to ignore it.
544 * @param[in] device_info_blob Fill the device info PAC buffer with the given
545 * blob, use NULL to ignore it.
547 * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
548 * blob, use NULL to ignore it.
550 * @param[in] pac The pac buffer to fill. This should be allocated with
551 * krb5_pac_init() already.
553 * @returns 0 on success or a corresponding KRB5 error.
555 krb5_error_code
samba_make_krb5_pac(krb5_context context
,
556 const DATA_BLOB
*logon_blob
,
557 const DATA_BLOB
*cred_blob
,
558 const DATA_BLOB
*upn_blob
,
559 const DATA_BLOB
*pac_attrs_blob
,
560 const DATA_BLOB
*requester_sid_blob
,
561 const DATA_BLOB
*deleg_blob
,
562 const DATA_BLOB
*client_claims_blob
,
563 const DATA_BLOB
*device_info_blob
,
564 const DATA_BLOB
*device_claims_blob
,
567 krb5_data logon_data
;
569 char null_byte
= '\0';
570 krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
572 /* The user account may be set not to want the PAC */
573 if (logon_blob
== NULL
) {
577 logon_data
= smb_krb5_data_from_blob(*logon_blob
);
578 ret
= krb5_pac_add_buffer(context
, pac
, PAC_TYPE_LOGON_INFO
, &logon_data
);
583 if (device_info_blob
!= NULL
) {
584 krb5_data device_info_data
= smb_krb5_data_from_blob(*device_info_blob
);
585 ret
= krb5_pac_add_buffer(context
, pac
,
586 PAC_TYPE_DEVICE_INFO
,
593 if (client_claims_blob
!= NULL
) {
594 krb5_data client_claims_data
;
595 krb5_data
*data
= NULL
;
597 if (client_claims_blob
->length
!= 0) {
598 client_claims_data
= smb_krb5_data_from_blob(*client_claims_blob
);
599 data
= &client_claims_data
;
604 ret
= krb5_pac_add_buffer(context
, pac
,
605 PAC_TYPE_CLIENT_CLAIMS_INFO
,
612 if (device_claims_blob
!= NULL
) {
613 krb5_data device_claims_data
= smb_krb5_data_from_blob(*device_claims_blob
);
614 ret
= krb5_pac_add_buffer(context
, pac
,
615 PAC_TYPE_DEVICE_CLAIMS_INFO
,
616 &device_claims_data
);
622 if (cred_blob
!= NULL
) {
623 krb5_data cred_data
= smb_krb5_data_from_blob(*cred_blob
);
624 ret
= krb5_pac_add_buffer(context
, pac
,
625 PAC_TYPE_CREDENTIAL_INFO
,
632 #ifdef SAMBA4_USES_HEIMDAL
634 * null_data will be filled by the generic KDC code in the caller
635 * here we just add it in order to have it before
636 * PAC_TYPE_UPN_DNS_INFO
638 * Not needed with MIT Kerberos - asn
640 ret
= krb5_pac_add_buffer(context
, pac
,
648 if (upn_blob
!= NULL
) {
649 krb5_data upn_data
= smb_krb5_data_from_blob(*upn_blob
);
650 ret
= krb5_pac_add_buffer(context
, pac
,
651 PAC_TYPE_UPN_DNS_INFO
,
658 if (pac_attrs_blob
!= NULL
) {
659 krb5_data pac_attrs_data
= smb_krb5_data_from_blob(*pac_attrs_blob
);
660 ret
= krb5_pac_add_buffer(context
, pac
,
661 PAC_TYPE_ATTRIBUTES_INFO
,
668 if (requester_sid_blob
!= NULL
) {
669 krb5_data requester_sid_data
= smb_krb5_data_from_blob(*requester_sid_blob
);
670 ret
= krb5_pac_add_buffer(context
, pac
,
671 PAC_TYPE_REQUESTER_SID
,
672 &requester_sid_data
);
678 if (deleg_blob
!= NULL
) {
679 krb5_data deleg_data
= smb_krb5_data_from_blob(*deleg_blob
);
680 ret
= krb5_pac_add_buffer(context
, pac
,
681 PAC_TYPE_CONSTRAINED_DELEGATION
,
691 bool samba_princ_needs_pac(const struct samba_kdc_entry
*skdc_entry
)
694 uint32_t userAccountControl
;
696 /* The service account may be set not to want the PAC */
697 userAccountControl
= ldb_msg_find_attr_as_uint(skdc_entry
->msg
, "userAccountControl", 0);
698 if (userAccountControl
& UF_NO_AUTH_DATA_REQUIRED
) {
705 static krb5_error_code
samba_client_requested_pac(krb5_context context
,
706 const krb5_const_pac pac
,
710 enum ndr_err_code ndr_err
;
711 krb5_data k5pac_attrs_in
;
712 DATA_BLOB pac_attrs_in
;
713 union PAC_INFO pac_attrs
;
716 *requested_pac
= true;
718 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_ATTRIBUTES_INFO
,
721 return ret
== ENOENT
? 0 : ret
;
724 pac_attrs_in
= data_blob_const(k5pac_attrs_in
.data
,
725 k5pac_attrs_in
.length
);
727 ndr_err
= ndr_pull_union_blob(&pac_attrs_in
, mem_ctx
, &pac_attrs
,
728 PAC_TYPE_ATTRIBUTES_INFO
,
729 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
730 smb_krb5_free_data_contents(context
, &k5pac_attrs_in
);
731 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
732 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
733 DBG_ERR("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status
));
734 return map_errno_from_nt_status(nt_status
);
737 if (pac_attrs
.attributes_info
.flags
& (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
738 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED
)) {
739 *requested_pac
= true;
741 *requested_pac
= false;
747 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
748 int samba_krbtgt_is_in_db(struct samba_kdc_entry
*p
,
753 int rodc_krbtgt_number
, trust_direction
;
756 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
761 trust_direction
= ldb_msg_find_attr_as_int(p
->msg
, "trustDirection", 0);
763 if (trust_direction
!= 0) {
764 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
766 This is exactly where we should flag for SID
767 validation when we do inter-forest trusts
769 talloc_free(mem_ctx
);
775 /* The lack of password controls etc applies to krbtgt by
776 * virtue of being that particular RID */
777 status
= dom_sid_split_rid(NULL
, samdb_result_dom_sid(mem_ctx
, p
->msg
, "objectSid"), NULL
, &rid
);
779 if (!NT_STATUS_IS_OK(status
)) {
780 talloc_free(mem_ctx
);
781 return map_errno_from_nt_status(status
);
784 rodc_krbtgt_number
= ldb_msg_find_attr_as_int(p
->msg
, "msDS-SecondaryKrbTgtNumber", -1);
786 if (p
->kdc_db_ctx
->my_krbtgt_number
== 0) {
787 if (rid
== DOMAIN_RID_KRBTGT
) {
790 talloc_free(mem_ctx
);
792 } else if (rodc_krbtgt_number
!= -1) {
795 talloc_free(mem_ctx
);
798 } else if ((rid
!= DOMAIN_RID_KRBTGT
) && (rodc_krbtgt_number
== p
->kdc_db_ctx
->my_krbtgt_number
)) {
799 talloc_free(mem_ctx
);
803 } else if (rid
== DOMAIN_RID_KRBTGT
) {
804 /* krbtgt viewed from an RODC */
805 talloc_free(mem_ctx
);
812 talloc_free(mem_ctx
);
819 * Because the KDC does not limit protocol transition, two new well-known SIDs
820 * were introduced to give this control to the resource administrator. These
821 * SIDs identify whether protocol transition has occurred, and can be used with
822 * standard access control lists to grant or limit access as needed.
824 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
826 static NTSTATUS
samba_add_asserted_identity(enum samba_asserted_identity ai
,
827 struct auth_user_info_dc
*user_info_dc
)
829 struct dom_sid ai_sid
;
830 const char *sid_str
= NULL
;
833 case SAMBA_ASSERTED_IDENTITY_SERVICE
:
834 sid_str
= SID_SERVICE_ASSERTED_IDENTITY
;
836 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
:
837 sid_str
= SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
;
839 case SAMBA_ASSERTED_IDENTITY_IGNORE
:
842 return NT_STATUS_INVALID_PARAMETER
;
845 if (!dom_sid_parse(sid_str
, &ai_sid
)) {
846 return NT_STATUS_UNSUCCESSFUL
;
849 return add_sid_to_array_attrs_unique(
852 SE_GROUP_DEFAULT_FLAGS
,
854 &user_info_dc
->num_sids
);
857 static NTSTATUS
samba_add_claims_valid(enum samba_claims_valid claims_valid
,
858 struct auth_user_info_dc
*user_info_dc
)
860 switch (claims_valid
) {
861 case SAMBA_CLAIMS_VALID_EXCLUDE
:
863 case SAMBA_CLAIMS_VALID_INCLUDE
:
865 struct dom_sid claims_valid_sid
;
867 if (!dom_sid_parse(SID_CLAIMS_VALID
, &claims_valid_sid
)) {
868 return NT_STATUS_UNSUCCESSFUL
;
871 return add_sid_to_array_attrs_unique(
874 SE_GROUP_DEFAULT_FLAGS
,
876 &user_info_dc
->num_sids
);
880 return NT_STATUS_INVALID_PARAMETER
;
883 static NTSTATUS
samba_add_compounded_auth(enum samba_compounded_auth compounded_auth
,
884 struct auth_user_info_dc
*user_info_dc
)
886 switch (compounded_auth
) {
887 case SAMBA_COMPOUNDED_AUTH_EXCLUDE
:
889 case SAMBA_COMPOUNDED_AUTH_INCLUDE
:
891 struct dom_sid compounded_auth_sid
;
893 if (!dom_sid_parse(SID_COMPOUNDED_AUTHENTICATION
, &compounded_auth_sid
)) {
894 return NT_STATUS_UNSUCCESSFUL
;
897 return add_sid_to_array_attrs_unique(
899 &compounded_auth_sid
,
900 SE_GROUP_DEFAULT_FLAGS
,
902 &user_info_dc
->num_sids
);
906 return NT_STATUS_INVALID_PARAMETER
;
910 * Look up the user's info in the database and create a auth_user_info_dc
911 * structure. If the resulting structure is not talloc_free()d, it will be
912 * reused on future calls to this function.
914 NTSTATUS
samba_kdc_get_user_info_from_db(struct samba_kdc_entry
*skdc_entry
,
915 const struct ldb_message
*msg
,
916 const struct auth_user_info_dc
**user_info_dc
)
918 if (skdc_entry
->user_info_dc
== NULL
) {
920 struct loadparm_context
*lp_ctx
= skdc_entry
->kdc_db_ctx
->lp_ctx
;
922 nt_status
= authsam_make_user_info_dc(skdc_entry
,
923 skdc_entry
->kdc_db_ctx
->samdb
,
924 lpcfg_netbios_name(lp_ctx
),
925 lpcfg_sam_name(lp_ctx
),
926 lpcfg_sam_dnsname(lp_ctx
),
927 skdc_entry
->realm_dn
,
931 &skdc_entry
->user_info_dc
);
932 if (!NT_STATUS_IS_OK(nt_status
)) {
937 *user_info_dc
= skdc_entry
->user_info_dc
;
941 NTSTATUS
samba_kdc_get_logon_info_blob(TALLOC_CTX
*mem_ctx
,
942 const struct auth_user_info_dc
*user_info_dc
,
943 const enum auth_group_inclusion group_inclusion
,
944 DATA_BLOB
**_logon_info_blob
)
946 DATA_BLOB
*logon_blob
= NULL
;
949 *_logon_info_blob
= NULL
;
951 logon_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
952 if (logon_blob
== NULL
) {
953 return NT_STATUS_NO_MEMORY
;
956 nt_status
= samba_get_logon_info_pac_blob(logon_blob
,
961 if (!NT_STATUS_IS_OK(nt_status
)) {
962 DBG_ERR("Building PAC LOGON INFO failed: %s\n",
963 nt_errstr(nt_status
));
967 *_logon_info_blob
= logon_blob
;
972 NTSTATUS
samba_kdc_get_cred_ndr_blob(TALLOC_CTX
*mem_ctx
,
973 const struct samba_kdc_entry
*p
,
974 DATA_BLOB
**_cred_ndr_blob
)
976 DATA_BLOB
*cred_blob
= NULL
;
979 SMB_ASSERT(_cred_ndr_blob
!= NULL
);
981 *_cred_ndr_blob
= NULL
;
983 cred_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
984 if (cred_blob
== NULL
) {
985 return NT_STATUS_NO_MEMORY
;
988 nt_status
= samba_get_cred_info_ndr_blob(cred_blob
,
991 if (!NT_STATUS_IS_OK(nt_status
)) {
992 DBG_ERR("Building PAC CRED INFO failed: %s\n",
993 nt_errstr(nt_status
));
997 *_cred_ndr_blob
= cred_blob
;
1002 NTSTATUS
samba_kdc_get_upn_info_blob(TALLOC_CTX
*mem_ctx
,
1003 const struct auth_user_info_dc
*user_info_dc
,
1004 DATA_BLOB
**_upn_info_blob
)
1006 DATA_BLOB
*upn_blob
= NULL
;
1009 *_upn_info_blob
= NULL
;
1011 upn_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1012 if (upn_blob
== NULL
) {
1013 return NT_STATUS_NO_MEMORY
;
1016 nt_status
= samba_get_upn_info_pac_blob(upn_blob
,
1019 if (!NT_STATUS_IS_OK(nt_status
)) {
1020 DBG_ERR("Building PAC UPN INFO failed: %s\n",
1021 nt_errstr(nt_status
));
1025 *_upn_info_blob
= upn_blob
;
1027 return NT_STATUS_OK
;
1030 NTSTATUS
samba_kdc_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
1031 uint64_t pac_attributes
,
1032 DATA_BLOB
**_pac_attrs_blob
)
1034 DATA_BLOB
*pac_attrs_blob
= NULL
;
1037 SMB_ASSERT(_pac_attrs_blob
!= NULL
);
1039 *_pac_attrs_blob
= NULL
;
1041 pac_attrs_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1042 if (pac_attrs_blob
== NULL
) {
1043 return NT_STATUS_NO_MEMORY
;
1046 nt_status
= samba_get_pac_attrs_blob(pac_attrs_blob
,
1050 if (!NT_STATUS_IS_OK(nt_status
)) {
1051 DBG_ERR("Building PAC ATTRIBUTES failed: %s\n",
1052 nt_errstr(nt_status
));
1056 *_pac_attrs_blob
= pac_attrs_blob
;
1058 return NT_STATUS_OK
;
1061 NTSTATUS
samba_kdc_get_requester_sid_blob(TALLOC_CTX
*mem_ctx
,
1062 const struct auth_user_info_dc
*user_info_dc
,
1063 DATA_BLOB
**_requester_sid_blob
)
1065 DATA_BLOB
*requester_sid_blob
= NULL
;
1068 SMB_ASSERT(_requester_sid_blob
!= NULL
);
1070 *_requester_sid_blob
= NULL
;
1072 requester_sid_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1073 if (requester_sid_blob
== NULL
) {
1074 return NT_STATUS_NO_MEMORY
;
1077 nt_status
= samba_get_requester_sid_pac_blob(mem_ctx
,
1079 requester_sid_blob
);
1080 if (!NT_STATUS_IS_OK(nt_status
)) {
1081 DBG_ERR("Building PAC LOGON INFO failed: %s\n",
1082 nt_errstr(nt_status
));
1086 *_requester_sid_blob
= requester_sid_blob
;
1088 return NT_STATUS_OK
;
1091 NTSTATUS
samba_kdc_get_claims_blob(TALLOC_CTX
*mem_ctx
,
1092 const struct samba_kdc_entry
*p
,
1093 const DATA_BLOB
**_claims_blob
)
1095 DATA_BLOB
*claims_blob
= NULL
;
1099 SMB_ASSERT(_claims_blob
!= NULL
);
1101 *_claims_blob
= NULL
;
1103 claims_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1104 if (claims_blob
== NULL
) {
1105 return NT_STATUS_NO_MEMORY
;
1108 ret
= get_claims_blob_for_principal(p
->kdc_db_ctx
->samdb
,
1112 if (ret
!= LDB_SUCCESS
) {
1113 nt_status
= dsdb_ldb_err_to_ntstatus(ret
);
1114 DBG_ERR("Building claims failed: %s\n",
1115 nt_errstr(nt_status
));
1119 *_claims_blob
= claims_blob
;
1121 return NT_STATUS_OK
;
1124 NTSTATUS
samba_kdc_get_user_info_dc(TALLOC_CTX
*mem_ctx
,
1125 struct samba_kdc_entry
*skdc_entry
,
1126 enum samba_asserted_identity asserted_identity
,
1127 enum samba_claims_valid claims_valid
,
1128 enum samba_compounded_auth compounded_auth
,
1129 struct auth_user_info_dc
**user_info_dc_out
)
1132 const struct auth_user_info_dc
*user_info_dc_from_db
= NULL
;
1133 struct auth_user_info_dc
*user_info_dc
= NULL
;
1135 nt_status
= samba_kdc_get_user_info_from_db(skdc_entry
, skdc_entry
->msg
, &user_info_dc_from_db
);
1136 if (!NT_STATUS_IS_OK(nt_status
)) {
1137 DBG_ERR("Getting user info for PAC failed: %s\n",
1138 nt_errstr(nt_status
));
1142 /* Make a shallow copy of the user_info_dc structure. */
1143 nt_status
= authsam_shallow_copy_user_info_dc(mem_ctx
, user_info_dc_from_db
, &user_info_dc
);
1144 if (!NT_STATUS_IS_OK(nt_status
)) {
1145 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
1146 nt_errstr(nt_status
));
1150 /* Here we modify the SIDs to add the Asserted Identity SID. */
1151 nt_status
= samba_add_asserted_identity(asserted_identity
,
1153 if (!NT_STATUS_IS_OK(nt_status
)) {
1154 DBG_ERR("Failed to add asserted identity: %s\n",
1155 nt_errstr(nt_status
));
1159 nt_status
= samba_add_claims_valid(claims_valid
,
1161 if (!NT_STATUS_IS_OK(nt_status
)) {
1162 DBG_ERR("Failed to add Claims Valid: %s\n",
1163 nt_errstr(nt_status
));
1167 nt_status
= samba_add_compounded_auth(compounded_auth
,
1169 if (!NT_STATUS_IS_OK(nt_status
)) {
1170 DBG_ERR("Failed to add Compounded Authentication: %s\n",
1171 nt_errstr(nt_status
));
1175 *user_info_dc_out
= user_info_dc
;
1177 return NT_STATUS_OK
;
1180 static krb5_error_code
samba_kdc_obtain_user_info_dc(TALLOC_CTX
*mem_ctx
,
1181 krb5_context context
,
1182 struct ldb_context
*samdb
,
1183 const enum auth_group_inclusion group_inclusion
,
1184 struct samba_kdc_entry
*skdc_entry
,
1185 const krb5_const_pac pac
,
1186 const bool pac_is_trusted
,
1187 struct auth_user_info_dc
**user_info_dc_out
,
1188 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups_out
)
1190 struct auth_user_info_dc
*user_info_dc
= NULL
;
1191 krb5_error_code ret
= 0;
1194 *user_info_dc_out
= NULL
;
1195 if (resource_groups_out
!= NULL
) {
1196 *resource_groups_out
= NULL
;
1199 if (pac
!= NULL
&& pac_is_trusted
) {
1200 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
1202 if (group_inclusion
== AUTH_EXCLUDE_RESOURCE_GROUPS
) {
1204 * Since we are creating a TGT, resource groups from our domain
1205 * are not to be put into the PAC. Instead, we take the resource
1206 * groups directly from the original PAC and copy them
1207 * unmodified into the new one.
1209 resource_groups
= resource_groups_out
;
1212 ret
= kerberos_pac_to_user_info_dc(mem_ctx
,
1216 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1221 const char *krb5err
= krb5_get_error_message(context
, ret
);
1222 DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1223 krb5err
!= NULL
? krb5err
: "?");
1224 krb5_free_error_message(context
, krb5err
);
1230 * We need to expand group memberships within our local domain,
1231 * as the token might be generated by a trusted domain.
1233 nt_status
= authsam_update_user_info_dc(mem_ctx
,
1236 if (!NT_STATUS_IS_OK(nt_status
)) {
1237 DBG_ERR("authsam_update_user_info_dc failed: %s\n",
1238 nt_errstr(nt_status
));
1240 ret
= map_errno_from_nt_status(nt_status
);
1244 if (skdc_entry
== NULL
) {
1245 ret
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1250 * In this case the RWDC discards the PAC an RODC generated.
1251 * Windows adds the asserted_identity in this case too.
1253 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1254 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1255 * So we can always use
1256 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1259 nt_status
= samba_kdc_get_user_info_dc(mem_ctx
,
1261 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
1262 SAMBA_CLAIMS_VALID_EXCLUDE
,
1263 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
1265 if (!NT_STATUS_IS_OK(nt_status
)) {
1266 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
1267 nt_errstr(nt_status
));
1268 ret
= KRB5KDC_ERR_TGT_REVOKED
;
1273 *user_info_dc_out
= user_info_dc
;
1274 user_info_dc
= NULL
;
1277 TALLOC_FREE(user_info_dc
);
1282 static NTSTATUS
samba_kdc_update_delegation_info_blob(TALLOC_CTX
*mem_ctx
,
1283 krb5_context context
,
1284 const krb5_const_pac pac
,
1285 const krb5_const_principal server_principal
,
1286 const krb5_const_principal proxy_principal
,
1287 DATA_BLOB
*new_blob
)
1289 krb5_data old_data
= {};
1291 krb5_error_code ret
;
1293 enum ndr_err_code ndr_err
;
1294 union PAC_INFO info
= {};
1295 struct PAC_CONSTRAINED_DELEGATION _d
= {};
1296 struct PAC_CONSTRAINED_DELEGATION
*d
= NULL
;
1297 char *server
= NULL
;
1300 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1302 if (tmp_ctx
== NULL
) {
1303 return NT_STATUS_NO_MEMORY
;
1306 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_CONSTRAINED_DELEGATION
, &old_data
);
1307 if (ret
== ENOENT
) {
1310 talloc_free(tmp_ctx
);
1311 return NT_STATUS_UNSUCCESSFUL
;
1314 old_blob
.length
= old_data
.length
;
1315 old_blob
.data
= (uint8_t *)old_data
.data
;
1317 if (old_blob
.length
> 0) {
1318 ndr_err
= ndr_pull_union_blob(&old_blob
, mem_ctx
,
1319 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1320 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1321 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1322 smb_krb5_free_data_contents(context
, &old_data
);
1323 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1324 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1325 talloc_free(tmp_ctx
);
1329 info
.constrained_delegation
.info
= &_d
;
1331 smb_krb5_free_data_contents(context
, &old_data
);
1333 ret
= krb5_unparse_name_flags(context
, server_principal
,
1334 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &server
);
1336 talloc_free(tmp_ctx
);
1337 return NT_STATUS_INTERNAL_ERROR
;
1340 ret
= krb5_unparse_name(context
, proxy_principal
, &proxy
);
1343 talloc_free(tmp_ctx
);
1344 return NT_STATUS_INTERNAL_ERROR
;
1347 d
= info
.constrained_delegation
.info
;
1348 i
= d
->num_transited_services
;
1349 d
->proxy_target
.string
= server
;
1350 d
->transited_services
= talloc_realloc(mem_ctx
, d
->transited_services
,
1351 struct lsa_String
, i
+ 1);
1352 d
->transited_services
[i
].string
= proxy
;
1353 d
->num_transited_services
= i
+ 1;
1355 ndr_err
= ndr_push_union_blob(new_blob
, mem_ctx
,
1356 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1357 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1360 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1361 smb_krb5_free_data_contents(context
, &old_data
);
1362 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1363 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1364 talloc_free(tmp_ctx
);
1368 talloc_free(tmp_ctx
);
1369 return NT_STATUS_OK
;
1372 /* function to map policy errors */
1373 krb5_error_code
samba_kdc_map_policy_err(NTSTATUS nt_status
)
1375 krb5_error_code ret
;
1377 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_MUST_CHANGE
))
1378 ret
= KRB5KDC_ERR_KEY_EXP
;
1379 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_EXPIRED
))
1380 ret
= KRB5KDC_ERR_KEY_EXP
;
1381 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_EXPIRED
))
1382 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1383 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_DISABLED
))
1384 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1385 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_LOGON_HOURS
))
1386 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1387 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_LOCKED_OUT
))
1388 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1389 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_WORKSTATION
))
1390 ret
= KRB5KDC_ERR_POLICY
;
1392 ret
= KRB5KDC_ERR_POLICY
;
1397 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1398 * for consistency */
1399 NTSTATUS
samba_kdc_check_client_access(struct samba_kdc_entry
*kdc_entry
,
1400 const char *client_name
,
1401 const char *workstation
,
1402 bool password_change
)
1404 TALLOC_CTX
*tmp_ctx
;
1407 tmp_ctx
= talloc_named(NULL
, 0, "samba_kdc_check_client_access");
1409 return NT_STATUS_NO_MEMORY
;
1412 /* we allow all kinds of trusts here */
1413 nt_status
= authsam_account_ok(tmp_ctx
,
1414 kdc_entry
->kdc_db_ctx
->samdb
,
1415 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
1416 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
1417 kdc_entry
->realm_dn
, kdc_entry
->msg
,
1418 workstation
, client_name
,
1419 true, password_change
);
1421 kdc_entry
->reject_status
= nt_status
;
1422 talloc_free(tmp_ctx
);
1426 static krb5_error_code
samba_get_requester_sid(TALLOC_CTX
*mem_ctx
,
1428 krb5_context context
,
1429 struct dom_sid
*sid
)
1432 enum ndr_err_code ndr_err
;
1433 krb5_error_code ret
;
1435 DATA_BLOB pac_requester_sid_in
;
1436 krb5_data k5pac_requester_sid_in
;
1438 union PAC_INFO info
;
1440 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1441 if (tmp_ctx
== NULL
) {
1445 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_REQUESTER_SID
,
1446 &k5pac_requester_sid_in
);
1448 talloc_free(tmp_ctx
);
1452 pac_requester_sid_in
= data_blob_const(k5pac_requester_sid_in
.data
,
1453 k5pac_requester_sid_in
.length
);
1455 ndr_err
= ndr_pull_union_blob(&pac_requester_sid_in
, tmp_ctx
, &info
,
1456 PAC_TYPE_REQUESTER_SID
,
1457 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1458 smb_krb5_free_data_contents(context
, &k5pac_requester_sid_in
);
1459 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1460 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1461 DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status
));
1462 talloc_free(tmp_ctx
);
1463 return map_errno_from_nt_status(nt_status
);
1466 *sid
= info
.requester_sid
.sid
;
1468 talloc_free(tmp_ctx
);
1472 /* Does a parse and SID check, but no crypto. */
1473 static krb5_error_code
samba_kdc_validate_pac_blob(
1474 krb5_context context
,
1475 const struct samba_kdc_entry
*client_skdc_entry
,
1476 const krb5_const_pac pac
)
1478 TALLOC_CTX
*frame
= talloc_stackframe();
1479 struct auth_user_info_dc
*pac_user_info
= NULL
;
1480 struct dom_sid client_sid
;
1481 struct dom_sid pac_sid
;
1482 krb5_error_code code
;
1486 * First, try to get the SID from the requester SID buffer in the PAC.
1488 code
= samba_get_requester_sid(frame
, pac
, context
, &pac_sid
);
1490 if (code
== ENOENT
) {
1492 * If the requester SID buffer isn't present, fall back to the
1493 * SID in the LOGON_INFO PAC buffer.
1495 code
= kerberos_pac_to_user_info_dc(frame
,
1499 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1507 if (pac_user_info
->num_sids
== 0) {
1512 pac_sid
= pac_user_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1513 } else if (code
!= 0) {
1517 code
= samdb_result_dom_sid_buf(client_skdc_entry
->msg
,
1524 ok
= dom_sid_equal(&pac_sid
, &client_sid
);
1526 struct dom_sid_buf buf1
;
1527 struct dom_sid_buf buf2
;
1529 DBG_ERR("SID mismatch between PAC and looked up client: "
1530 "PAC[%s] != CLI[%s]\n",
1531 dom_sid_str_buf(&pac_sid
, &buf1
),
1532 dom_sid_str_buf(&client_sid
, &buf2
));
1533 code
= KRB5KDC_ERR_TGT_REVOKED
;
1545 * In the RODC case, to confirm that the returned user is permitted to
1546 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1548 static WERROR
samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids
,
1549 const struct dom_sid
*object_sids
,
1550 const struct samba_kdc_entry
*rodc
,
1551 const struct samba_kdc_entry
*object
)
1555 TALLOC_CTX
*frame
= talloc_stackframe();
1556 const char *rodc_attrs
[] = { "msDS-KrbTgtLink",
1557 "msDS-NeverRevealGroup",
1558 "msDS-RevealOnDemandGroup",
1559 "userAccountControl",
1562 struct ldb_result
*rodc_machine_account
= NULL
;
1563 struct ldb_dn
*rodc_machine_account_dn
= samdb_result_dn(rodc
->kdc_db_ctx
->samdb
,
1566 "msDS-KrbTgtLinkBL",
1568 const struct dom_sid
*rodc_machine_account_sid
= NULL
;
1570 if (rodc_machine_account_dn
== NULL
) {
1571 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1572 ldb_dn_get_linearized(rodc
->msg
->dn
));
1574 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1578 * Follow the link and get the RODC account (the krbtgt
1579 * account is the krbtgt_XXX account, but the
1580 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1581 * the RODC$ account)
1583 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1584 * out of the extended DNs
1587 ret
= dsdb_search_dn(rodc
->kdc_db_ctx
->samdb
,
1589 &rodc_machine_account
,
1590 rodc_machine_account_dn
,
1592 DSDB_SEARCH_SHOW_EXTENDED_DN
);
1593 if (ret
!= LDB_SUCCESS
) {
1594 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1595 ldb_dn_get_linearized(rodc_machine_account_dn
),
1596 ldb_dn_get_linearized(rodc
->msg
->dn
),
1597 ldb_errstring(rodc
->kdc_db_ctx
->samdb
));
1599 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1602 if (rodc_machine_account
->count
!= 1) {
1603 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1604 ldb_dn_get_linearized(rodc_machine_account_dn
),
1605 ldb_dn_get_linearized(rodc
->msg
->dn
),
1606 rodc_machine_account
->count
);
1608 return WERR_DS_DRA_BAD_DN
;
1611 /* if the object SID is equal to the user_sid, allow */
1612 rodc_machine_account_sid
= samdb_result_dom_sid(frame
,
1613 rodc_machine_account
->msgs
[0],
1615 if (rodc_machine_account_sid
== NULL
) {
1617 return WERR_DS_DRA_BAD_DN
;
1620 werr
= samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc
->kdc_db_ctx
->samdb
,
1621 rodc_machine_account_sid
,
1622 rodc_machine_account
->msgs
[0],
1632 * Perform an access check for the client attempting to authenticate to the
1633 * server. ‘client_info’ must be talloc-allocated so that we can make a
1636 krb5_error_code
samba_kdc_allowed_to_authenticate_to(TALLOC_CTX
*mem_ctx
,
1637 struct ldb_context
*samdb
,
1638 struct loadparm_context
*lp_ctx
,
1639 const struct samba_kdc_entry
*client
,
1640 const struct auth_user_info_dc
*client_info
,
1641 const struct samba_kdc_entry
*server
,
1642 struct authn_audit_info
**server_audit_info_out
,
1643 NTSTATUS
*status_out
)
1645 krb5_error_code ret
= 0;
1647 _UNUSED_ NTSTATUS _status
;
1648 struct dom_sid server_sid
= {};
1649 const struct authn_server_policy
*server_policy
= server
->server_policy
;
1651 if (status_out
!= NULL
) {
1652 *status_out
= NT_STATUS_OK
;
1655 ret
= samdb_result_dom_sid_buf(server
->msg
, "objectSid", &server_sid
);
1658 * Ignore the return status — we are already in an error path,
1659 * and overwriting the real error code with the audit info
1660 * status is unhelpful.
1662 _status
= authn_server_policy_audit_info(mem_ctx
,
1665 AUTHN_AUDIT_EVENT_OTHER_ERROR
,
1666 AUTHN_AUDIT_REASON_NONE
,
1667 dsdb_ldb_err_to_ntstatus(ret
),
1668 server_audit_info_out
);
1672 if (dom_sid_equal(&client_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
, &server_sid
)) {
1673 /* Authenticating to ourselves is always allowed. */
1674 status
= authn_server_policy_audit_info(mem_ctx
,
1677 AUTHN_AUDIT_EVENT_OK
,
1678 AUTHN_AUDIT_REASON_NONE
,
1680 server_audit_info_out
);
1681 if (!NT_STATUS_IS_OK(status
)) {
1682 ret
= KRB5KRB_ERR_GENERIC
;
1687 status
= authn_policy_authenticate_to_service(mem_ctx
,
1690 AUTHN_POLICY_AUTH_TYPE_KERBEROS
,
1693 server_audit_info_out
);
1694 if (!NT_STATUS_IS_OK(status
)) {
1695 if (status_out
!= NULL
) {
1696 *status_out
= status
;
1698 if (NT_STATUS_EQUAL(status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
1699 ret
= KRB5KDC_ERR_POLICY
;
1700 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1701 ret
= KRB5KDC_ERR_POLICY
;
1703 ret
= KRB5KRB_ERR_GENERIC
;
1711 static krb5_error_code
samba_kdc_add_domain_group_sid(TALLOC_CTX
*mem_ctx
,
1712 struct PAC_DEVICE_INFO
*info
,
1713 const struct netr_SidAttr
*sid
)
1719 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_group
= NULL
;
1721 for (i
= 0; i
< info
->domain_group_count
; ++i
) {
1722 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*this_domain_group
1723 = &info
->domain_groups
[i
];
1725 if (dom_sid_in_domain(this_domain_group
->domain_sid
, sid
->sid
)) {
1726 domain_group
= this_domain_group
;
1731 if (domain_group
== NULL
) {
1732 info
->domain_groups
= talloc_realloc(
1734 info
->domain_groups
,
1735 struct PAC_DOMAIN_GROUP_MEMBERSHIP
,
1736 info
->domain_group_count
+ 1);
1737 if (info
->domain_groups
== NULL
) {
1741 domain_group
= &info
->domain_groups
[
1742 info
->domain_group_count
++];
1744 domain_group
->domain_sid
= NULL
;
1746 domain_group
->groups
.count
= 0;
1747 domain_group
->groups
.rids
= NULL
;
1749 status
= dom_sid_split_rid(info
->domain_groups
,
1751 &domain_group
->domain_sid
,
1753 if (!NT_STATUS_IS_OK(status
)) {
1754 return map_errno_from_nt_status(status
);
1757 status
= dom_sid_split_rid(NULL
,
1761 if (!NT_STATUS_IS_OK(status
)) {
1762 return map_errno_from_nt_status(status
);
1766 domain_group
->groups
.rids
= talloc_realloc(info
->domain_groups
,
1767 domain_group
->groups
.rids
,
1768 struct samr_RidWithAttribute
,
1769 domain_group
->groups
.count
+ 1);
1770 if (domain_group
->groups
.rids
== NULL
) {
1774 domain_group
->groups
.rids
[domain_group
->groups
.count
].rid
= rid
;
1775 domain_group
->groups
.rids
[domain_group
->groups
.count
].attributes
= sid
->attributes
;
1777 ++domain_group
->groups
.count
;
1782 static krb5_error_code
samba_kdc_make_device_info(TALLOC_CTX
*mem_ctx
,
1783 const struct netr_SamInfo3
*info3
,
1784 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
1785 union PAC_INFO
*info
)
1787 struct PAC_DEVICE_INFO
*device_info
= NULL
;
1790 *info
= (union PAC_INFO
) {};
1792 info
->device_info
.info
= NULL
;
1794 device_info
= talloc(mem_ctx
, struct PAC_DEVICE_INFO
);
1795 if (device_info
== NULL
) {
1799 device_info
->rid
= info3
->base
.rid
;
1800 device_info
->primary_gid
= info3
->base
.primary_gid
;
1801 device_info
->domain_sid
= info3
->base
.domain_sid
;
1802 device_info
->groups
= info3
->base
.groups
;
1804 device_info
->sid_count
= 0;
1805 device_info
->sids
= NULL
;
1807 if (resource_groups
!= NULL
) {
1809 * The account's resource groups all belong to the same domain,
1810 * so we can add them all in one go.
1812 device_info
->domain_group_count
= 1;
1813 device_info
->domain_groups
= talloc_move(mem_ctx
, &resource_groups
);
1815 device_info
->domain_group_count
= 0;
1816 device_info
->domain_groups
= NULL
;
1819 for (i
= 0; i
< info3
->sidcount
; ++i
) {
1820 const struct netr_SidAttr
*device_sid
= &info3
->sids
[i
];
1822 if (dom_sid_has_account_domain(device_sid
->sid
)) {
1823 krb5_error_code ret
= samba_kdc_add_domain_group_sid(mem_ctx
, device_info
, device_sid
);
1828 device_info
->sids
= talloc_realloc(mem_ctx
, device_info
->sids
,
1829 struct netr_SidAttr
,
1830 device_info
->sid_count
+ 1);
1831 if (device_info
->sids
== NULL
) {
1835 device_info
->sids
[device_info
->sid_count
].sid
= dom_sid_dup(device_info
->sids
, device_sid
->sid
);
1836 if (device_info
->sids
[device_info
->sid_count
].sid
== NULL
) {
1840 device_info
->sids
[device_info
->sid_count
].attributes
= device_sid
->attributes
;
1842 ++device_info
->sid_count
;
1846 info
->device_info
.info
= device_info
;
1851 static krb5_error_code
samba_kdc_update_device_info(TALLOC_CTX
*mem_ctx
,
1852 struct ldb_context
*samdb
,
1853 const union PAC_INFO
*logon_info
,
1854 struct PAC_DEVICE_INFO
*device_info
)
1857 struct auth_user_info_dc
*device_info_dc
= NULL
;
1858 union netr_Validation validation
;
1860 uint32_t num_existing_sids
;
1863 * This does a bit of unnecessary work, setting up fields we don't care
1864 * about -- we only want the SIDs.
1866 validation
.sam3
= &logon_info
->logon_info
.info
->info3
;
1867 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
1868 true, /* This user was authenticated */
1870 if (!NT_STATUS_IS_OK(nt_status
)) {
1871 return map_errno_from_nt_status(nt_status
);
1874 num_existing_sids
= device_info_dc
->num_sids
;
1877 * We need to expand group memberships within our local domain,
1878 * as the token might be generated by a trusted domain.
1880 nt_status
= authsam_update_user_info_dc(mem_ctx
,
1883 if (!NT_STATUS_IS_OK(nt_status
)) {
1884 return map_errno_from_nt_status(nt_status
);
1887 for (i
= num_existing_sids
; i
< device_info_dc
->num_sids
; ++i
) {
1888 struct auth_SidAttr
*device_sid
= &device_info_dc
->sids
[i
];
1889 const struct netr_SidAttr sid
= (struct netr_SidAttr
) {
1890 .sid
= &device_sid
->sid
,
1891 .attributes
= device_sid
->attrs
,
1894 krb5_error_code ret
= samba_kdc_add_domain_group_sid(mem_ctx
, device_info
, &sid
);
1903 static krb5_error_code
samba_kdc_get_device_info_pac_blob(TALLOC_CTX
*mem_ctx
,
1904 union PAC_INFO
*info
,
1905 DATA_BLOB
**device_info_blob
)
1907 enum ndr_err_code ndr_err
;
1909 *device_info_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1910 if (*device_info_blob
== NULL
) {
1911 DBG_ERR("Out of memory\n");
1915 ndr_err
= ndr_push_union_blob(*device_info_blob
, mem_ctx
,
1916 info
, PAC_TYPE_DEVICE_INFO
,
1917 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1918 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1919 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
1920 DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
1921 nt_errstr(nt_status
));
1922 return map_errno_from_nt_status(nt_status
);
1928 static krb5_error_code
samba_kdc_create_device_info_blob(TALLOC_CTX
*mem_ctx
,
1929 krb5_context context
,
1930 struct ldb_context
*samdb
,
1931 const krb5_const_pac device_pac
,
1932 DATA_BLOB
**device_info_blob
)
1934 TALLOC_CTX
*frame
= NULL
;
1935 krb5_data device_logon_info
;
1936 krb5_error_code code
= EINVAL
;
1939 union PAC_INFO info
;
1940 enum ndr_err_code ndr_err
;
1941 DATA_BLOB device_logon_info_blob
;
1943 union PAC_INFO logon_info
;
1945 code
= krb5_pac_get_buffer(context
, device_pac
,
1946 PAC_TYPE_LOGON_INFO
,
1947 &device_logon_info
);
1949 if (code
== ENOENT
) {
1950 DBG_ERR("Device PAC is missing LOGON_INFO\n");
1952 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
1957 frame
= talloc_stackframe();
1959 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
1960 device_logon_info
.length
);
1962 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &logon_info
,
1963 PAC_TYPE_LOGON_INFO
,
1964 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1965 smb_krb5_free_data_contents(context
, &device_logon_info
);
1966 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1967 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1968 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
1969 nt_errstr(nt_status
));
1971 return map_errno_from_nt_status(nt_status
);
1975 * When creating the device info structure, existing resource groups are
1978 code
= samba_kdc_make_device_info(frame
,
1979 &logon_info
.logon_info
.info
->info3
,
1980 NULL
, /* resource_groups */
1987 code
= samba_kdc_update_device_info(frame
,
1990 info
.device_info
.info
);
1996 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2004 static krb5_error_code
samba_kdc_get_device_info_blob(TALLOC_CTX
*mem_ctx
,
2005 struct samba_kdc_entry
*device
,
2006 DATA_BLOB
**device_info_blob
)
2008 TALLOC_CTX
*frame
= NULL
;
2009 krb5_error_code code
= EINVAL
;
2012 struct auth_user_info_dc
*device_info_dc
= NULL
;
2013 struct netr_SamInfo3
*info3
= NULL
;
2014 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
2016 union PAC_INFO info
;
2018 frame
= talloc_stackframe();
2020 nt_status
= samba_kdc_get_user_info_dc(frame
,
2022 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
2023 SAMBA_CLAIMS_VALID_INCLUDE
,
2024 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
2026 if (!NT_STATUS_IS_OK(nt_status
)) {
2027 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2028 nt_errstr(nt_status
));
2030 return KRB5KDC_ERR_TGT_REVOKED
;
2033 nt_status
= auth_convert_user_info_dc_saminfo3(frame
, device_info_dc
,
2034 AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
,
2037 if (!NT_STATUS_IS_OK(nt_status
)) {
2038 DBG_WARNING("Getting Samba info failed: %s\n",
2039 nt_errstr(nt_status
));
2041 return nt_status_to_krb5(nt_status
);
2044 code
= samba_kdc_make_device_info(frame
,
2053 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2062 * @brief Verify a PAC
2064 * @param mem_ctx A talloc memory context
2066 * @param context A krb5 context
2068 * @param flags Bitwise OR'ed flags
2070 * @param client The client samba kdc entry.
2072 * @param krbtgt The krbtgt samba kdc entry.
2074 * @param device The computer's samba kdc entry; used for compound
2077 * @param device_pac The PAC from the computer's TGT; used
2078 * for compound authentication.
2080 * @param pac The PAC
2082 * @return A Kerberos error code.
2084 krb5_error_code
samba_kdc_verify_pac(TALLOC_CTX
*mem_ctx
,
2085 krb5_context context
,
2087 struct samba_kdc_entry
*client
,
2088 const struct samba_kdc_entry
*krbtgt
,
2089 const struct samba_kdc_entry
*device
,
2090 const krb5_const_pac
*device_pac
,
2091 const krb5_const_pac pac
)
2093 krb5_error_code code
= EINVAL
;
2095 bool is_trusted
= flags
& SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED
;
2097 struct pac_blobs pac_blobs
;
2098 pac_blobs_init(&pac_blobs
);
2100 if (client
!= NULL
) {
2102 * Check the objectSID of the client and pac data are the same.
2103 * Does a parse and SID check, but no crypto.
2105 code
= samba_kdc_validate_pac_blob(context
,
2113 if (device
!= NULL
) {
2114 SMB_ASSERT(*device_pac
!= NULL
);
2117 * Check the objectSID of the device and pac data are the same.
2118 * Does a parse and SID check, but no crypto.
2120 code
= samba_kdc_validate_pac_blob(context
,
2129 const struct auth_user_info_dc
*user_info_dc
= NULL
;
2132 struct dom_sid
*object_sids
= NULL
;
2135 if (client
== NULL
) {
2136 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2140 nt_status
= samba_kdc_get_user_info_from_db(client
, client
->msg
, &user_info_dc
);
2141 if (!NT_STATUS_IS_OK(nt_status
)) {
2142 DBG_ERR("Getting user info for PAC failed: %s\n",
2143 nt_errstr(nt_status
));
2144 code
= KRB5KDC_ERR_TGT_REVOKED
;
2149 * Check if the SID list in the user_info_dc intersects
2150 * correctly with the RODC allow/deny lists.
2152 object_sids
= talloc_array(mem_ctx
, struct dom_sid
, user_info_dc
->num_sids
);
2153 if (object_sids
== NULL
) {
2158 for (j
= 0; j
< user_info_dc
->num_sids
; ++j
) {
2159 object_sids
[j
] = user_info_dc
->sids
[j
].sid
;
2162 werr
= samba_rodc_confirm_user_is_allowed(user_info_dc
->num_sids
,
2166 TALLOC_FREE(object_sids
);
2167 if (!W_ERROR_IS_OK(werr
)) {
2168 code
= KRB5KDC_ERR_TGT_REVOKED
;
2169 if (W_ERROR_EQUAL(werr
,
2170 WERR_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2171 code
= KRB5KDC_ERR_POLICY
;
2177 * The RODC PAC data isn't trusted for authorization as it may
2178 * be stale. The only thing meaningful we can do with an RODC
2179 * account on a full DC is exchange the RODC TGT for a 'real'
2182 * So we match Windows (at least server 2022) and
2183 * don't allow S4U2Self.
2185 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
2187 if (flags
& SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
) {
2188 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2193 /* Check the types of the given PAC */
2195 code
= pac_blobs_from_krb5_pac(&pac_blobs
,
2203 code
= pac_blobs_ensure_exists(&pac_blobs
,
2204 PAC_TYPE_LOGON_INFO
);
2209 code
= pac_blobs_ensure_exists(&pac_blobs
,
2210 PAC_TYPE_LOGON_NAME
);
2215 code
= pac_blobs_ensure_exists(&pac_blobs
,
2216 PAC_TYPE_SRV_CHECKSUM
);
2221 code
= pac_blobs_ensure_exists(&pac_blobs
,
2222 PAC_TYPE_KDC_CHECKSUM
);
2227 if (!(flags
& SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
)) {
2228 code
= pac_blobs_ensure_exists(&pac_blobs
,
2229 PAC_TYPE_REQUESTER_SID
);
2231 code
= KRB5KDC_ERR_TGT_REVOKED
;
2239 pac_blobs_destroy(&pac_blobs
);
2245 * @brief Update a PAC
2247 * @param mem_ctx A talloc memory context
2249 * @param context A krb5 context
2251 * @param samdb An open samdb connection.
2253 * @param lp_ctx A loadparm context.
2255 * @param flags Bitwise OR'ed flags
2257 * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
2258 * as opposed to an RODC.
2260 * @param client The client samba kdc entry.
2262 * @param client_krbtgt The krbtgt samba kdc entry that verified the client
2264 * @param server_principal The server principal
2266 * @param server The server samba kdc entry.
2268 * @param delegated_proxy_principal The delegated proxy principal used for
2269 * updating the constrained delegation PAC
2272 * @param delegated_proxy The delegated proxy kdc entry.
2274 * @param delegated_proxy_pac The PAC from the primary TGT (i.e., that of
2275 * the delegating service) during a constrained
2276 * delegation request.
2278 * @param device The computer's samba kdc entry; used for compound
2281 * @param device_krbtgt The krbtgt samba kdc entry that verified the device
2283 * @param device_pac The PAC from the computer's TGT; used
2284 * for compound authentication.
2286 * @param old_pac The old PAC
2288 * @param new_pac The new already allocated PAC
2290 * @return A Kerberos error code. If no PAC should be returned, the code will be
2293 krb5_error_code
samba_kdc_update_pac(TALLOC_CTX
*mem_ctx
,
2294 krb5_context context
,
2295 struct ldb_context
*samdb
,
2296 struct loadparm_context
*lp_ctx
,
2298 const struct samba_kdc_entry
*client_krbtgt
,
2299 struct samba_kdc_entry
*client
,
2300 const krb5_const_principal server_principal
,
2301 const struct samba_kdc_entry
*server
,
2302 const krb5_const_principal delegated_proxy_principal
,
2303 struct samba_kdc_entry
*delegated_proxy
,
2304 const krb5_const_pac delegated_proxy_pac
,
2305 const struct samba_kdc_entry
*device_krbtgt
,
2306 struct samba_kdc_entry
*device
,
2307 const krb5_const_pac device_pac
,
2308 const krb5_const_pac old_pac
,
2310 struct authn_audit_info
**server_audit_info_out
,
2311 NTSTATUS
*status_out
)
2313 krb5_error_code code
= EINVAL
;
2315 DATA_BLOB
*pac_blob
= NULL
;
2316 DATA_BLOB
*upn_blob
= NULL
;
2317 DATA_BLOB
*deleg_blob
= NULL
;
2318 DATA_BLOB
*requester_sid_blob
= NULL
;
2319 const DATA_BLOB
*client_claims_blob
= NULL
;
2320 bool client_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED
;
2321 bool device_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_DEVICE_KRBTGT_IS_TRUSTED
;
2322 bool delegated_proxy_pac_is_trusted
= flags
& SAMBA_KDC_FLAG_DELEGATED_PROXY_IS_TRUSTED
;
2323 const DATA_BLOB
*device_claims_blob
= NULL
;
2324 DATA_BLOB
*device_info_blob
= NULL
;
2325 bool is_tgs
= false;
2326 struct auth_user_info_dc
*user_info_dc
= NULL
;
2327 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
2328 enum auth_group_inclusion group_inclusion
;
2329 enum samba_compounded_auth compounded_auth
;
2332 struct pac_blobs pac_blobs
;
2333 pac_blobs_init(&pac_blobs
);
2335 if (server_audit_info_out
!= NULL
) {
2336 *server_audit_info_out
= NULL
;
2339 if (status_out
!= NULL
) {
2340 *status_out
= NT_STATUS_OK
;
2344 int result
= smb_krb5_principal_is_tgs(context
, server_principal
);
2353 /* Only include resource groups in a service ticket. */
2355 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
2356 } else if (server
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
2357 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
2359 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
2362 if (device
!= NULL
&& !is_tgs
) {
2363 compounded_auth
= SAMBA_COMPOUNDED_AUTH_INCLUDE
;
2365 compounded_auth
= SAMBA_COMPOUNDED_AUTH_EXCLUDE
;
2368 if (device
!= NULL
&& !is_tgs
) {
2369 SMB_ASSERT(device_pac
!= NULL
);
2371 if (device_pac_is_trusted
) {
2372 krb5_data device_claims_data
;
2375 * [MS-KILE] 3.3.5.7.4 Compound Identity: the client
2376 * claims from the device PAC become the device claims
2379 code
= krb5_pac_get_buffer(context
, device_pac
,
2380 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2381 &device_claims_data
);
2382 if (code
== ENOENT
) {
2384 } else if (code
!= 0) {
2386 } else if (device_krbtgt
->is_trust
) {
2388 * TODO: we need claim translation over trusts,
2389 * for now we just clear them...
2391 device_claims_blob
= &data_blob_null
;
2393 DATA_BLOB
*device_claims
= NULL
;
2395 device_claims
= talloc_zero(mem_ctx
, DATA_BLOB
);
2396 if (device_claims
== NULL
) {
2397 smb_krb5_free_data_contents(context
, &device_claims_data
);
2402 *device_claims
= data_blob_talloc(mem_ctx
,
2403 device_claims_data
.data
,
2404 device_claims_data
.length
);
2405 if (device_claims
->data
== NULL
&& device_claims_data
.length
!= 0) {
2406 smb_krb5_free_data_contents(context
, &device_claims_data
);
2411 smb_krb5_free_data_contents(context
, &device_claims_data
);
2413 device_claims_blob
= device_claims
;
2416 code
= samba_kdc_create_device_info_blob(mem_ctx
,
2425 /* Don't trust RODC-issued claims. Regenerate them. */
2426 nt_status
= samba_kdc_get_claims_blob(mem_ctx
,
2428 &device_claims_blob
);
2429 if (!NT_STATUS_IS_OK(nt_status
)) {
2430 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2431 nt_errstr(nt_status
));
2432 code
= map_errno_from_nt_status(nt_status
);
2436 /* Also regenerate device info. */
2437 code
= samba_kdc_get_device_info_blob(mem_ctx
,
2446 if (delegated_proxy_principal
!= NULL
) {
2447 deleg_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2448 if (deleg_blob
== NULL
) {
2453 nt_status
= samba_kdc_update_delegation_info_blob(
2458 delegated_proxy_principal
,
2460 if (!NT_STATUS_IS_OK(nt_status
)) {
2461 DBG_ERR("update delegation info blob failed: %s\n",
2462 nt_errstr(nt_status
));
2463 code
= map_errno_from_nt_status(nt_status
);
2468 code
= samba_kdc_obtain_user_info_dc(mem_ctx
,
2474 client_pac_is_trusted
,
2478 const char *err_str
= krb5_get_error_message(context
, code
);
2479 DBG_ERR("samba_kdc_obtain_user_info_dc failed: %s\n",
2480 err_str
!= NULL
? err_str
: "<unknown>");
2481 krb5_free_error_message(context
, err_str
);
2487 * Enforce the AllowedToAuthenticateTo part of an authentication policy,
2488 * if one is present.
2490 if (!is_tgs
&& authn_policy_restrictions_present(server
->server_policy
)) {
2491 const struct samba_kdc_entry
*auth_entry
= NULL
;
2492 struct auth_user_info_dc
*auth_user_info_dc
= NULL
;
2494 if (delegated_proxy
!= NULL
) {
2495 auth_entry
= delegated_proxy
;
2497 code
= samba_kdc_obtain_user_info_dc(mem_ctx
,
2500 AUTH_INCLUDE_RESOURCE_GROUPS
,
2502 delegated_proxy_pac
,
2503 delegated_proxy_pac_is_trusted
,
2510 auth_entry
= client
;
2511 auth_user_info_dc
= user_info_dc
;
2514 code
= samba_kdc_allowed_to_authenticate_to(mem_ctx
,
2520 server_audit_info_out
,
2522 if (auth_user_info_dc
!= user_info_dc
) {
2523 talloc_unlink(mem_ctx
, auth_user_info_dc
);
2530 nt_status
= samba_add_compounded_auth(compounded_auth
,
2532 if (!NT_STATUS_IS_OK(nt_status
)) {
2533 DBG_ERR("Failed to add Compounded Authentication: %s\n",
2534 nt_errstr(nt_status
));
2536 code
= KRB5KDC_ERR_TGT_REVOKED
;
2540 if (client_pac_is_trusted
) {
2541 pac_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2542 if (pac_blob
== NULL
) {
2547 nt_status
= samba_get_logon_info_pac_blob(mem_ctx
,
2552 if (!NT_STATUS_IS_OK(nt_status
)) {
2553 DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
2554 nt_errstr(nt_status
));
2556 code
= map_errno_from_nt_status(nt_status
);
2561 * TODO: we need claim translation over trusts,
2562 * for now we just clear them...
2564 if (client_krbtgt
->is_trust
) {
2565 client_claims_blob
= &data_blob_null
;
2568 nt_status
= samba_kdc_get_logon_info_blob(mem_ctx
,
2572 if (!NT_STATUS_IS_OK(nt_status
)) {
2573 DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
2574 nt_errstr(nt_status
));
2575 code
= KRB5KDC_ERR_TGT_REVOKED
;
2579 nt_status
= samba_kdc_get_upn_info_blob(mem_ctx
,
2582 if (!NT_STATUS_IS_OK(nt_status
)) {
2583 DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
2584 nt_errstr(nt_status
));
2585 code
= KRB5KDC_ERR_TGT_REVOKED
;
2589 nt_status
= samba_kdc_get_requester_sid_blob(mem_ctx
,
2591 &requester_sid_blob
);
2592 if (!NT_STATUS_IS_OK(nt_status
)) {
2593 DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
2594 nt_errstr(nt_status
));
2595 code
= KRB5KDC_ERR_TGT_REVOKED
;
2599 /* Don't trust RODC-issued claims. Regenerate them. */
2600 nt_status
= samba_kdc_get_claims_blob(mem_ctx
,
2602 &client_claims_blob
);
2603 if (!NT_STATUS_IS_OK(nt_status
)) {
2604 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2605 nt_errstr(nt_status
));
2606 code
= map_errno_from_nt_status(nt_status
);
2611 /* Check the types of the given PAC */
2612 code
= pac_blobs_from_krb5_pac(&pac_blobs
,
2620 code
= pac_blobs_replace_existing(&pac_blobs
,
2621 PAC_TYPE_LOGON_INFO
,
2627 #ifdef SAMBA4_USES_HEIMDAL
2628 /* Not needed with MIT Kerberos */
2629 code
= pac_blobs_replace_existing(&pac_blobs
,
2630 PAC_TYPE_LOGON_NAME
,
2636 code
= pac_blobs_replace_existing(&pac_blobs
,
2637 PAC_TYPE_SRV_CHECKSUM
,
2643 code
= pac_blobs_replace_existing(&pac_blobs
,
2644 PAC_TYPE_KDC_CHECKSUM
,
2651 code
= pac_blobs_add_blob(&pac_blobs
,
2653 PAC_TYPE_CONSTRAINED_DELEGATION
,
2659 code
= pac_blobs_add_blob(&pac_blobs
,
2661 PAC_TYPE_UPN_DNS_INFO
,
2667 code
= pac_blobs_add_blob(&pac_blobs
,
2669 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2670 client_claims_blob
);
2675 code
= pac_blobs_add_blob(&pac_blobs
,
2677 PAC_TYPE_DEVICE_INFO
,
2683 code
= pac_blobs_add_blob(&pac_blobs
,
2685 PAC_TYPE_DEVICE_CLAIMS_INFO
,
2686 device_claims_blob
);
2691 if (!client_pac_is_trusted
|| !is_tgs
) {
2692 code
= pac_blobs_remove_blob(&pac_blobs
,
2694 PAC_TYPE_ATTRIBUTES_INFO
);
2701 code
= pac_blobs_remove_blob(&pac_blobs
,
2703 PAC_TYPE_REQUESTER_SID
);
2708 code
= pac_blobs_add_blob(&pac_blobs
,
2710 PAC_TYPE_REQUESTER_SID
,
2711 requester_sid_blob
);
2718 * The server account may be set not to want the PAC.
2720 * While this is wasteful if the above calculations were done
2721 * and now thrown away, this is cleaner as we do any ticket
2722 * signature checking etc always.
2724 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
2725 * time (eg not accepting a ticket from the RODC) we do not
2726 * need to re-generate anything anyway.
2728 if (!samba_princ_needs_pac(server
)) {
2733 if (client_pac_is_trusted
&& !is_tgs
) {
2735 * The client may have requested no PAC when obtaining the
2738 bool requested_pac
= false;
2740 code
= samba_client_requested_pac(context
,
2744 if (code
!= 0 || !requested_pac
) {
2745 if (!requested_pac
) {
2752 for (i
= 0; i
< pac_blobs
.num_types
; ++i
) {
2753 krb5_data type_data
;
2754 const DATA_BLOB
*type_blob
= pac_blobs
.type_blobs
[i
].data
;
2755 uint32_t type
= pac_blobs
.type_blobs
[i
].type
;
2757 static char null_byte
= '\0';
2758 const krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
2760 #ifndef SAMBA4_USES_HEIMDAL
2761 /* Not needed with MIT Kerberos */
2763 case PAC_TYPE_LOGON_NAME
:
2764 case PAC_TYPE_SRV_CHECKSUM
:
2765 case PAC_TYPE_KDC_CHECKSUM
:
2766 case PAC_TYPE_FULL_CHECKSUM
:
2773 if (type_blob
!= NULL
) {
2774 type_data
= smb_krb5_data_from_blob(*type_blob
);
2776 * Passing a NULL pointer into krb5_pac_add_buffer() is
2777 * not allowed, so pass null_data instead if needed.
2779 code
= krb5_pac_add_buffer(context
,
2782 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2784 code
= krb5_pac_get_buffer(context
,
2792 * Passing a NULL pointer into krb5_pac_add_buffer() is
2793 * not allowed, so pass null_data instead if needed.
2795 code
= krb5_pac_add_buffer(context
,
2798 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2799 smb_krb5_free_data_contents(context
, &type_data
);
2809 pac_blobs_destroy(&pac_blobs
);
2810 TALLOC_FREE(pac_blob
);
2811 TALLOC_FREE(upn_blob
);
2812 TALLOC_FREE(deleg_blob
);
2814 * Release our handle to user_info_dc. ‘server_audit_info_out’, if
2815 * non-NULL, becomes the new parent.
2817 talloc_unlink(mem_ctx
, user_info_dc
);
2821 krb5_error_code
samba_kdc_check_device(TALLOC_CTX
*mem_ctx
,
2822 krb5_context context
,
2823 struct ldb_context
*samdb
,
2824 struct loadparm_context
*lp_ctx
,
2825 struct samba_kdc_entry
*device
,
2826 const krb5_const_pac device_pac
,
2827 const bool device_pac_is_trusted
,
2828 const struct authn_kerberos_client_policy
*client_policy
,
2829 struct authn_audit_info
**client_audit_info_out
,
2830 NTSTATUS
*status_out
)
2832 TALLOC_CTX
*frame
= NULL
;
2833 krb5_error_code code
= 0;
2835 struct auth_user_info_dc
*device_info
= NULL
;
2836 struct authn_audit_info
*client_audit_info
= NULL
;
2838 if (status_out
!= NULL
) {
2839 *status_out
= NT_STATUS_OK
;
2842 if (!authn_policy_device_restrictions_present(client_policy
)) {
2846 if (device
== NULL
|| device_pac
== NULL
) {
2847 NTSTATUS out_status
= NT_STATUS_INVALID_WORKSTATION
;
2849 nt_status
= authn_kerberos_client_policy_audit_info(mem_ctx
,
2851 NULL
/* client_info */,
2852 AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION
,
2853 AUTHN_AUDIT_REASON_FAST_REQUIRED
,
2855 client_audit_info_out
);
2856 if (!NT_STATUS_IS_OK(nt_status
)) {
2857 code
= KRB5KRB_ERR_GENERIC
;
2858 } else if (authn_kerberos_client_policy_is_enforced(client_policy
)) {
2859 code
= KRB5KDC_ERR_POLICY
;
2861 if (status_out
!= NULL
) {
2862 *status_out
= out_status
;
2872 frame
= talloc_stackframe();
2874 if (device_pac_is_trusted
) {
2875 krb5_data device_logon_info
;
2877 enum ndr_err_code ndr_err
;
2878 DATA_BLOB device_logon_info_blob
;
2880 union PAC_INFO pac_logon_info
;
2881 union netr_Validation validation
;
2883 code
= krb5_pac_get_buffer(context
, device_pac
,
2884 PAC_TYPE_LOGON_INFO
,
2885 &device_logon_info
);
2887 if (code
== ENOENT
) {
2888 DBG_ERR("Device PAC is missing LOGON_INFO\n");
2890 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
2896 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
2897 device_logon_info
.length
);
2899 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &pac_logon_info
,
2900 PAC_TYPE_LOGON_INFO
,
2901 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
2902 smb_krb5_free_data_contents(context
, &device_logon_info
);
2903 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2904 nt_status
= ndr_map_error2ntstatus(ndr_err
);
2905 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
2906 nt_errstr(nt_status
));
2908 code
= ndr_map_error2errno(ndr_err
);
2913 * This does a bit of unnecessary work, setting up fields we
2914 * don’t care about — we only want the SIDs.
2916 validation
.sam3
= &pac_logon_info
.logon_info
.info
->info3
;
2917 nt_status
= make_user_info_dc_netlogon_validation(frame
, "", 3, &validation
,
2918 true, /* This user was authenticated */
2920 if (!NT_STATUS_IS_OK(nt_status
)) {
2921 code
= map_errno_from_nt_status(nt_status
);
2926 * We need to expand group memberships within our local domain,
2927 * as the token might be generated by a trusted domain.
2929 nt_status
= authsam_update_user_info_dc(frame
,
2932 if (!NT_STATUS_IS_OK(nt_status
)) {
2933 code
= map_errno_from_nt_status(nt_status
);
2937 nt_status
= samba_kdc_get_user_info_dc(frame
,
2939 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
2940 SAMBA_CLAIMS_VALID_INCLUDE
,
2941 SAMBA_COMPOUNDED_AUTH_EXCLUDE
,
2943 if (!NT_STATUS_IS_OK(nt_status
)) {
2944 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2945 nt_errstr(nt_status
));
2947 code
= KRB5KDC_ERR_TGT_REVOKED
;
2952 nt_status
= authn_policy_authenticate_from_device(frame
,
2957 &client_audit_info
);
2958 if (client_audit_info
!= NULL
) {
2959 *client_audit_info_out
= talloc_move(mem_ctx
, &client_audit_info
);
2961 if (!NT_STATUS_IS_OK(nt_status
)) {
2962 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
2963 code
= KRB5KDC_ERR_POLICY
;
2965 code
= KRB5KRB_ERR_GENERIC
;