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 TALLOC_CTX
*tmp_ctx
= NULL
;
61 struct netr_SamInfo3
*info3
= NULL
;
62 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
63 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
64 union PAC_INFO pac_info
= {};
65 enum ndr_err_code ndr_err
;
66 NTSTATUS nt_status
= NT_STATUS_OK
;
68 *pac_data
= data_blob_null
;
70 tmp_ctx
= talloc_new(mem_ctx
);
71 if (tmp_ctx
== NULL
) {
72 return NT_STATUS_NO_MEMORY
;
75 if (override_resource_groups
== NULL
) {
76 resource_groups
= &_resource_groups
;
77 } else if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
79 * It doesn't make sense to override resource groups if we claim
80 * to want resource groups from user_info_dc.
82 DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
84 nt_status
= NT_STATUS_INVALID_PARAMETER
;
88 nt_status
= auth_convert_user_info_dc_saminfo3(tmp_ctx
, info
,
92 if (!NT_STATUS_IS_OK(nt_status
)) {
93 DBG_WARNING("Getting Samba info failed: %s\n",
94 nt_errstr(nt_status
));
98 pac_info
.logon_info
.info
= talloc_zero(tmp_ctx
, struct PAC_LOGON_INFO
);
99 if (!pac_info
.logon_info
.info
) {
100 nt_status
= NT_STATUS_NO_MEMORY
;
104 pac_info
.logon_info
.info
->info3
= *info3
;
105 if (_resource_groups
!= NULL
) {
106 pac_info
.logon_info
.info
->resource_groups
= *_resource_groups
;
109 if (override_resource_groups
!= NULL
) {
110 pac_info
.logon_info
.info
->resource_groups
= *override_resource_groups
;
113 if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
115 * Set the resource groups flag based on whether any groups are
116 * present. Otherwise, the flag is propagated from the
119 if (pac_info
.logon_info
.info
->resource_groups
.groups
.count
> 0) {
120 pac_info
.logon_info
.info
->info3
.base
.user_flags
|= NETLOGON_RESOURCE_GROUPS
;
122 pac_info
.logon_info
.info
->info3
.base
.user_flags
&= ~NETLOGON_RESOURCE_GROUPS
;
126 ndr_err
= ndr_push_union_blob(pac_data
, mem_ctx
, &pac_info
,
128 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
129 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
130 nt_status
= ndr_map_error2ntstatus(ndr_err
);
131 DBG_WARNING("PAC_LOGON_INFO (presig) push failed: %s\n",
132 nt_errstr(nt_status
));
137 talloc_free(tmp_ctx
);
142 NTSTATUS
samba_get_upn_info_pac_blob(TALLOC_CTX
*mem_ctx
,
143 const struct auth_user_info_dc
*info
,
146 TALLOC_CTX
*tmp_ctx
= NULL
;
147 union PAC_INFO pac_upn
= {};
148 enum ndr_err_code ndr_err
;
149 NTSTATUS nt_status
= NT_STATUS_OK
;
152 *upn_data
= data_blob_null
;
154 tmp_ctx
= talloc_new(mem_ctx
);
155 if (tmp_ctx
== NULL
) {
156 return NT_STATUS_NO_MEMORY
;
159 pac_upn
.upn_dns_info
.upn_name
= info
->info
->user_principal_name
;
160 pac_upn
.upn_dns_info
.dns_domain_name
= strupper_talloc(tmp_ctx
,
161 info
->info
->dns_domain_name
);
162 if (pac_upn
.upn_dns_info
.dns_domain_name
== NULL
) {
163 nt_status
= NT_STATUS_NO_MEMORY
;
166 if (info
->info
->user_principal_constructed
) {
167 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_CONSTRUCTED
;
170 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
;
172 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.samaccountname
173 = info
->info
->account_name
;
175 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.objectsid
176 = &info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
178 ndr_err
= ndr_push_union_blob(upn_data
, mem_ctx
, &pac_upn
,
179 PAC_TYPE_UPN_DNS_INFO
,
180 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
182 nt_status
= ndr_map_error2ntstatus(ndr_err
);
183 DBG_WARNING("PAC UPN_DNS_INFO (presig) push failed: %s\n",
184 nt_errstr(nt_status
));
188 ok
= data_blob_pad(mem_ctx
, upn_data
, 8);
190 talloc_free(upn_data
);
191 nt_status
= NT_STATUS_NO_MEMORY
;
196 talloc_free(tmp_ctx
);
201 NTSTATUS
samba_get_cred_info_ndr_blob(TALLOC_CTX
*mem_ctx
,
202 const struct ldb_message
*msg
,
203 DATA_BLOB
*cred_blob
)
205 enum ndr_err_code ndr_err
;
207 struct samr_Password
*lm_hash
= NULL
;
208 struct samr_Password
*nt_hash
= NULL
;
209 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg
= {
212 DATA_BLOB ntlm_blob
= data_blob_null
;
213 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs
[1] = {{
214 .credential_size
= 0,
216 struct PAC_CREDENTIAL_DATA cred_data
= {
217 .credential_count
= 0,
219 struct PAC_CREDENTIAL_DATA_NDR cred_ndr
= {};
221 *cred_blob
= data_blob_null
;
223 lm_hash
= samdb_result_hash(mem_ctx
, msg
, "dBCSPwd");
224 if (lm_hash
!= NULL
) {
225 bool zero
= all_zero(lm_hash
->hash
, 16);
230 if (lm_hash
!= NULL
) {
231 DBG_INFO("Passing LM password hash through credentials set\n");
232 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_LM_HASH
;
233 ntlm_secpkg
.lm_password
= *lm_hash
;
234 ZERO_STRUCTP(lm_hash
);
235 TALLOC_FREE(lm_hash
);
238 nt_hash
= samdb_result_hash(mem_ctx
, msg
, "unicodePwd");
239 if (nt_hash
!= NULL
) {
240 bool zero
= all_zero(nt_hash
->hash
, 16);
245 if (nt_hash
!= NULL
) {
246 DBG_INFO("Passing NT password hash through credentials set\n");
247 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_NT_HASH
;
248 ntlm_secpkg
.nt_password
= *nt_hash
;
249 ZERO_STRUCTP(nt_hash
);
250 TALLOC_FREE(nt_hash
);
253 if (ntlm_secpkg
.flags
== 0) {
257 #ifdef DEBUG_PASSWORD
259 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG
, &ntlm_secpkg
);
263 ndr_err
= ndr_push_struct_blob(&ntlm_blob
, mem_ctx
, &ntlm_secpkg
,
264 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG
);
265 ZERO_STRUCT(ntlm_secpkg
);
266 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
267 nt_status
= ndr_map_error2ntstatus(ndr_err
);
268 DBG_WARNING("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
269 nt_errstr(nt_status
));
273 DBG_DEBUG("NTLM credential BLOB (len %zu) for user\n",
275 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
276 ntlm_blob
.data
, ntlm_blob
.length
);
278 secpkgs
[0].package_name
.string
= discard_const_p(char, "NTLM");
279 secpkgs
[0].credential_size
= ntlm_blob
.length
;
280 secpkgs
[0].credential
= ntlm_blob
.data
;
282 cred_data
.credential_count
= ARRAY_SIZE(secpkgs
);
283 cred_data
.credentials
= secpkgs
;
285 #ifdef DEBUG_PASSWORD
287 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA
, &cred_data
);
291 cred_ndr
.ctr
.data
= &cred_data
;
293 #ifdef DEBUG_PASSWORD
295 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR
, &cred_ndr
);
299 ndr_err
= ndr_push_struct_blob(cred_blob
, mem_ctx
, &cred_ndr
,
300 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_DATA_NDR
);
301 data_blob_clear(&ntlm_blob
);
302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
303 nt_status
= ndr_map_error2ntstatus(ndr_err
);
304 DBG_WARNING("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
305 nt_errstr(nt_status
));
309 DBG_DEBUG("Created credential BLOB (len %zu) for user\n",
311 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
312 cred_blob
->data
, cred_blob
->length
);
317 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
318 const krb5_keyblock
*pkreplykey
,
319 const DATA_BLOB
*cred_ndr_blob
,
321 DATA_BLOB
*cred_info_blob
)
323 #ifdef SAMBA4_USES_HEIMDAL
324 krb5_crypto cred_crypto
;
325 krb5_enctype cred_enctype
;
326 krb5_data cred_ndr_crypt
;
327 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
330 enum ndr_err_code ndr_err
;
333 *cred_info_blob
= data_blob_null
;
335 ret
= krb5_crypto_init(context
, pkreplykey
, ETYPE_NULL
,
338 krb5err
= krb5_get_error_message(context
, ret
);
339 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
340 krb5_free_error_message(context
, krb5err
);
344 ret
= krb5_crypto_getenctype(context
, cred_crypto
, &cred_enctype
);
346 DBG_WARNING("Failed getting crypto type for key\n");
347 krb5_crypto_destroy(context
, cred_crypto
);
351 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
352 cred_ndr_blob
->length
);
353 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
354 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
356 ret
= krb5_encrypt(context
, cred_crypto
,
357 KRB5_KU_OTHER_ENCRYPTED
,
358 cred_ndr_blob
->data
, cred_ndr_blob
->length
,
360 krb5_crypto_destroy(context
, cred_crypto
);
362 krb5err
= krb5_get_error_message(context
, ret
);
363 DBG_WARNING("Failed crypt of cred data: %s\n", krb5err
);
364 krb5_free_error_message(context
, krb5err
);
368 pac_cred_info
.encryption_type
= cred_enctype
;
369 pac_cred_info
.encrypted_data
.length
= cred_ndr_crypt
.length
;
370 pac_cred_info
.encrypted_data
.data
= (uint8_t *)cred_ndr_crypt
.data
;
373 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
376 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
377 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
378 krb5_data_free(&cred_ndr_crypt
);
379 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
380 nt_status
= ndr_map_error2ntstatus(ndr_err
);
381 DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
382 nt_errstr(nt_status
));
383 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
386 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
387 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
388 dump_data_pw("PAC_CREDENTIAL_INFO",
389 cred_info_blob
->data
, cred_info_blob
->length
);
392 #else /* SAMBA4_USES_HEIMDAL */
393 TALLOC_CTX
*tmp_ctx
= NULL
;
395 krb5_enctype cred_enctype
;
396 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
397 krb5_error_code code
= 0;
399 enum ndr_err_code ndr_err
;
401 krb5_data cred_ndr_data
;
402 krb5_enc_data cred_ndr_crypt
;
405 *cred_info_blob
= data_blob_null
;
407 tmp_ctx
= talloc_new(mem_ctx
);
408 if (tmp_ctx
== NULL
) {
412 code
= krb5_k_create_key(context
,
416 krb5err
= krb5_get_error_message(context
, code
);
417 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
418 krb5_free_error_message(context
, krb5err
);
422 cred_enctype
= krb5_k_key_enctype(context
, cred_key
);
424 DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
425 cred_ndr_blob
->length
);
426 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
427 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
429 pac_cred_info
.encryption_type
= cred_enctype
;
431 cred_ndr_data
= smb_krb5_data_from_blob(*cred_ndr_blob
);
433 code
= krb5_c_encrypt_length(context
,
435 cred_ndr_data
.length
,
438 krb5err
= krb5_get_error_message(context
, code
);
439 DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err
);
440 krb5_free_error_message(context
, krb5err
);
444 pac_cred_info
.encrypted_data
= data_blob_talloc_zero(tmp_ctx
, enc_len
);
445 if (pac_cred_info
.encrypted_data
.data
== NULL
) {
446 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 code
= KRB5KDC_ERR_SVC_UNAVAILABLE
;
482 DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32
"\n",
483 cred_info_blob
->length
, pac_cred_info
.encryption_type
);
484 dump_data_pw("PAC_CREDENTIAL_INFO",
485 cred_info_blob
->data
, cred_info_blob
->length
);
488 talloc_free(tmp_ctx
);
490 #endif /* SAMBA4_USES_HEIMDAL */
495 * @brief Create a PAC with the given blobs (logon, credentials, upn and
498 * @param[in] context The KRB5 context to use.
500 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
501 * use NULL to ignore it.
503 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
504 * blob, use NULL to ignore it.
506 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
509 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
510 * blob, use NULL to ignore it.
512 * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
513 * given blob, use NULL to ignore it.
515 * @param[in] device_info_blob Fill the device info PAC buffer with the given
516 * blob, use NULL to ignore it.
518 * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
519 * blob, use NULL to ignore it.
521 * @param[in] pac The pac buffer to fill. This should be allocated with
522 * krb5_pac_init() already.
524 * @returns 0 on success or a corresponding KRB5 error.
526 krb5_error_code
samba_make_krb5_pac(krb5_context context
,
527 const DATA_BLOB
*logon_blob
,
528 const DATA_BLOB
*cred_blob
,
529 const DATA_BLOB
*upn_blob
,
530 const DATA_BLOB
*pac_attrs_blob
,
531 const DATA_BLOB
*requester_sid_blob
,
532 const DATA_BLOB
*deleg_blob
,
533 const DATA_BLOB
*client_claims_blob
,
534 const DATA_BLOB
*device_info_blob
,
535 const DATA_BLOB
*device_claims_blob
,
538 krb5_data logon_data
;
540 char null_byte
= '\0';
541 krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
543 /* The user account may be set not to want the PAC */
544 if (logon_blob
== NULL
) {
548 logon_data
= smb_krb5_data_from_blob(*logon_blob
);
549 ret
= krb5_pac_add_buffer(context
, pac
, PAC_TYPE_LOGON_INFO
, &logon_data
);
554 if (device_info_blob
!= NULL
) {
555 krb5_data device_info_data
= smb_krb5_data_from_blob(*device_info_blob
);
556 ret
= krb5_pac_add_buffer(context
, pac
,
557 PAC_TYPE_DEVICE_INFO
,
564 if (client_claims_blob
!= NULL
) {
565 krb5_data client_claims_data
;
566 krb5_data
*data
= NULL
;
568 if (client_claims_blob
->length
!= 0) {
569 client_claims_data
= smb_krb5_data_from_blob(*client_claims_blob
);
570 data
= &client_claims_data
;
575 ret
= krb5_pac_add_buffer(context
, pac
,
576 PAC_TYPE_CLIENT_CLAIMS_INFO
,
583 if (device_claims_blob
!= NULL
) {
584 krb5_data device_claims_data
= smb_krb5_data_from_blob(*device_claims_blob
);
585 ret
= krb5_pac_add_buffer(context
, pac
,
586 PAC_TYPE_DEVICE_CLAIMS_INFO
,
587 &device_claims_data
);
593 if (cred_blob
!= NULL
) {
594 krb5_data cred_data
= smb_krb5_data_from_blob(*cred_blob
);
595 ret
= krb5_pac_add_buffer(context
, pac
,
596 PAC_TYPE_CREDENTIAL_INFO
,
603 #ifdef SAMBA4_USES_HEIMDAL
605 * null_data will be filled by the generic KDC code in the caller
606 * here we just add it in order to have it before
607 * PAC_TYPE_UPN_DNS_INFO
609 * Not needed with MIT Kerberos - asn
611 ret
= krb5_pac_add_buffer(context
, pac
,
619 if (upn_blob
!= NULL
) {
620 krb5_data upn_data
= smb_krb5_data_from_blob(*upn_blob
);
621 ret
= krb5_pac_add_buffer(context
, pac
,
622 PAC_TYPE_UPN_DNS_INFO
,
629 if (pac_attrs_blob
!= NULL
) {
630 krb5_data pac_attrs_data
= smb_krb5_data_from_blob(*pac_attrs_blob
);
631 ret
= krb5_pac_add_buffer(context
, pac
,
632 PAC_TYPE_ATTRIBUTES_INFO
,
639 if (requester_sid_blob
!= NULL
) {
640 krb5_data requester_sid_data
= smb_krb5_data_from_blob(*requester_sid_blob
);
641 ret
= krb5_pac_add_buffer(context
, pac
,
642 PAC_TYPE_REQUESTER_SID
,
643 &requester_sid_data
);
649 if (deleg_blob
!= NULL
) {
650 krb5_data deleg_data
= smb_krb5_data_from_blob(*deleg_blob
);
651 ret
= krb5_pac_add_buffer(context
, pac
,
652 PAC_TYPE_CONSTRAINED_DELEGATION
,
662 bool samba_princ_needs_pac(const struct samba_kdc_entry
*skdc_entry
)
665 uint32_t userAccountControl
;
667 /* The service account may be set not to want the PAC */
668 userAccountControl
= ldb_msg_find_attr_as_uint(skdc_entry
->msg
, "userAccountControl", 0);
669 if (userAccountControl
& UF_NO_AUTH_DATA_REQUIRED
) {
676 static krb5_error_code
samba_client_requested_pac(krb5_context context
,
677 const krb5_const_pac pac
,
681 enum ndr_err_code ndr_err
;
682 krb5_data k5pac_attrs_in
;
683 DATA_BLOB pac_attrs_in
;
684 union PAC_INFO pac_attrs
;
687 *requested_pac
= true;
689 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_ATTRIBUTES_INFO
,
692 return ret
== ENOENT
? 0 : ret
;
695 pac_attrs_in
= data_blob_const(k5pac_attrs_in
.data
,
696 k5pac_attrs_in
.length
);
698 ndr_err
= ndr_pull_union_blob(&pac_attrs_in
, mem_ctx
, &pac_attrs
,
699 PAC_TYPE_ATTRIBUTES_INFO
,
700 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
701 smb_krb5_free_data_contents(context
, &k5pac_attrs_in
);
702 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
703 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
704 DBG_ERR("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status
));
705 return map_errno_from_nt_status(nt_status
);
708 if (pac_attrs
.attributes_info
.flags
& (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
709 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED
)) {
710 *requested_pac
= true;
712 *requested_pac
= false;
718 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
719 krb5_error_code
samba_krbtgt_is_in_db(const struct samba_kdc_entry
*p
,
725 int rodc_krbtgt_number
, trust_direction
;
729 trust_direction
= ldb_msg_find_attr_as_int(p
->msg
, "trustDirection", 0);
731 if (trust_direction
!= 0) {
732 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
734 This is exactly where we should flag for SID
735 validation when we do inter-forest trusts
742 /* The lack of password controls etc applies to krbtgt by
743 * virtue of being that particular RID */
744 ret
= samdb_result_dom_sid_buf(p
->msg
, "objectSid", &sid
);
749 status
= dom_sid_split_rid(NULL
, &sid
, NULL
, &rid
);
750 if (!NT_STATUS_IS_OK(status
)) {
751 return map_errno_from_nt_status(status
);
754 rodc_krbtgt_number
= ldb_msg_find_attr_as_int(p
->msg
, "msDS-SecondaryKrbTgtNumber", -1);
756 if (p
->kdc_db_ctx
->my_krbtgt_number
== 0) {
757 if (rid
== DOMAIN_RID_KRBTGT
) {
761 } else if (rodc_krbtgt_number
!= -1) {
766 } else if ((rid
!= DOMAIN_RID_KRBTGT
) && (rodc_krbtgt_number
== p
->kdc_db_ctx
->my_krbtgt_number
)) {
770 } else if (rid
== DOMAIN_RID_KRBTGT
) {
771 /* krbtgt viewed from an RODC */
784 * Because the KDC does not limit protocol transition, two new well-known SIDs
785 * were introduced to give this control to the resource administrator. These
786 * SIDs identify whether protocol transition has occurred, and can be used with
787 * standard access control lists to grant or limit access as needed.
789 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
791 NTSTATUS
samba_kdc_add_asserted_identity(enum samba_asserted_identity ai
,
792 struct auth_user_info_dc
*user_info_dc
)
794 const struct dom_sid
*ai_sid
= NULL
;
797 case SAMBA_ASSERTED_IDENTITY_SERVICE
:
798 ai_sid
= &global_sid_Asserted_Identity_Service
;
800 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
:
801 ai_sid
= &global_sid_Asserted_Identity_Authentication_Authority
;
803 case SAMBA_ASSERTED_IDENTITY_IGNORE
:
806 return NT_STATUS_INVALID_PARAMETER
;
809 return add_sid_to_array_attrs_unique(
812 SE_GROUP_DEFAULT_FLAGS
,
814 &user_info_dc
->num_sids
);
817 NTSTATUS
samba_kdc_add_claims_valid(struct auth_user_info_dc
*user_info_dc
)
819 return add_sid_to_array_attrs_unique(
821 &global_sid_Claims_Valid
,
822 SE_GROUP_DEFAULT_FLAGS
,
824 &user_info_dc
->num_sids
);
827 NTSTATUS
samba_kdc_add_fresh_public_key_identity(struct auth_user_info_dc
*user_info_dc
)
829 return add_sid_to_array_attrs_unique(
831 &global_sid_Fresh_Public_Key_Identity
,
832 SE_GROUP_DEFAULT_FLAGS
,
834 &user_info_dc
->num_sids
);
837 static NTSTATUS
samba_kdc_add_compounded_auth(struct auth_user_info_dc
*user_info_dc
)
839 return add_sid_to_array_attrs_unique(
841 &global_sid_Compounded_Authentication
,
842 SE_GROUP_DEFAULT_FLAGS
,
844 &user_info_dc
->num_sids
);
847 bool samba_kdc_entry_is_trust(const struct samba_kdc_entry
*entry
)
849 return entry
!= NULL
&& entry
->is_trust
;
853 * Return true if this entry has an associated PAC issued or signed by a KDC
854 * that our KDC trusts. We trust the main krbtgt account, but we don’t trust any
855 * RODC krbtgt besides ourselves.
857 bool samba_krb5_pac_is_trusted(const struct samba_kdc_entry_pac pac
)
859 if (pac
.pac
== NULL
) {
863 #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
864 return krb5_pac_is_trusted(pac
.pac
);
866 return pac
.pac_is_trusted
;
867 #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
870 #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
871 struct samba_kdc_entry_pac
samba_kdc_entry_pac(krb5_const_pac pac
,
872 struct samba_kdc_entry
*entry
,
875 return (struct samba_kdc_entry_pac
) {
878 .is_from_trust
= is_from_trust
,
882 struct samba_kdc_entry_pac
samba_kdc_entry_pac_from_trusted(krb5_const_pac pac
,
883 struct samba_kdc_entry
*entry
,
887 return (struct samba_kdc_entry_pac
) {
890 .is_from_trust
= is_from_trust
,
891 .pac_is_trusted
= is_trusted
,
894 #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
896 static bool samba_kdc_entry_pac_issued_by_trust(const struct samba_kdc_entry_pac entry
)
898 return entry
.pac
!= NULL
&& entry
.is_from_trust
;
901 NTSTATUS
samba_kdc_get_logon_info_blob(TALLOC_CTX
*mem_ctx
,
902 const struct auth_user_info_dc
*user_info_dc
,
903 const enum auth_group_inclusion group_inclusion
,
904 DATA_BLOB
**_logon_info_blob
)
906 DATA_BLOB
*logon_blob
= NULL
;
909 *_logon_info_blob
= NULL
;
911 logon_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
912 if (logon_blob
== NULL
) {
913 return NT_STATUS_NO_MEMORY
;
916 nt_status
= samba_get_logon_info_pac_blob(logon_blob
,
921 if (!NT_STATUS_IS_OK(nt_status
)) {
922 DBG_ERR("Building PAC LOGON INFO failed: %s\n",
923 nt_errstr(nt_status
));
924 talloc_free(logon_blob
);
928 *_logon_info_blob
= logon_blob
;
933 NTSTATUS
samba_kdc_get_cred_ndr_blob(TALLOC_CTX
*mem_ctx
,
934 const struct samba_kdc_entry
*p
,
935 DATA_BLOB
**_cred_ndr_blob
)
937 DATA_BLOB
*cred_blob
= NULL
;
940 SMB_ASSERT(_cred_ndr_blob
!= NULL
);
942 *_cred_ndr_blob
= NULL
;
944 cred_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
945 if (cred_blob
== NULL
) {
946 return NT_STATUS_NO_MEMORY
;
949 nt_status
= samba_get_cred_info_ndr_blob(cred_blob
,
952 if (!NT_STATUS_IS_OK(nt_status
)) {
953 DBG_ERR("Building PAC CRED INFO failed: %s\n",
954 nt_errstr(nt_status
));
955 talloc_free(cred_blob
);
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
));
984 talloc_free(upn_blob
);
988 *_upn_info_blob
= upn_blob
;
993 NTSTATUS
samba_kdc_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
994 uint64_t pac_attributes
,
995 DATA_BLOB
**_pac_attrs_blob
)
997 DATA_BLOB
*pac_attrs_blob
= NULL
;
998 union PAC_INFO pac_attrs
= {};
999 enum ndr_err_code ndr_err
;
1002 SMB_ASSERT(_pac_attrs_blob
!= NULL
);
1004 *_pac_attrs_blob
= NULL
;
1006 pac_attrs_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1007 if (pac_attrs_blob
== NULL
) {
1008 return NT_STATUS_NO_MEMORY
;
1011 /* Set the length of the flags in bits. */
1012 pac_attrs
.attributes_info
.flags_length
= 2;
1013 pac_attrs
.attributes_info
.flags
= pac_attributes
;
1015 ndr_err
= ndr_push_union_blob(pac_attrs_blob
, pac_attrs_blob
, &pac_attrs
,
1016 PAC_TYPE_ATTRIBUTES_INFO
,
1017 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1018 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1019 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1020 DBG_WARNING("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
1021 nt_errstr(nt_status
));
1022 DBG_ERR("Building PAC ATTRIBUTES failed: %s\n",
1023 nt_errstr(nt_status
));
1025 talloc_free(pac_attrs_blob
);
1029 *_pac_attrs_blob
= pac_attrs_blob
;
1031 return NT_STATUS_OK
;
1034 NTSTATUS
samba_kdc_get_requester_sid_blob(TALLOC_CTX
*mem_ctx
,
1035 const struct auth_user_info_dc
*user_info_dc
,
1036 DATA_BLOB
**_requester_sid_blob
)
1038 DATA_BLOB
*requester_sid_blob
= NULL
;
1041 SMB_ASSERT(_requester_sid_blob
!= NULL
);
1043 *_requester_sid_blob
= NULL
;
1045 requester_sid_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1046 if (requester_sid_blob
== NULL
) {
1047 return NT_STATUS_NO_MEMORY
;
1050 if (user_info_dc
->num_sids
> 0) {
1051 union PAC_INFO pac_requester_sid
= {};
1052 enum ndr_err_code ndr_err
;
1054 pac_requester_sid
.requester_sid
.sid
= user_info_dc
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1056 ndr_err
= ndr_push_union_blob(requester_sid_blob
, requester_sid_blob
,
1058 PAC_TYPE_REQUESTER_SID
,
1059 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1060 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1061 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1062 DBG_WARNING("PAC_REQUESTER_SID (presig) push failed: %s\n",
1063 nt_errstr(nt_status
));
1064 DBG_ERR("Building PAC REQUESTER SID failed: %s\n",
1065 nt_errstr(nt_status
));
1067 talloc_free(requester_sid_blob
);
1072 *_requester_sid_blob
= requester_sid_blob
;
1074 return NT_STATUS_OK
;
1077 NTSTATUS
samba_kdc_get_claims_blob(TALLOC_CTX
*mem_ctx
,
1078 struct samba_kdc_entry
*p
,
1079 const DATA_BLOB
**_claims_blob
)
1081 DATA_BLOB
*claims_blob
= NULL
;
1082 struct claims_data
*claims_data
= NULL
;
1086 SMB_ASSERT(_claims_blob
!= NULL
);
1088 *_claims_blob
= NULL
;
1090 claims_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1091 if (claims_blob
== NULL
) {
1092 return NT_STATUS_NO_MEMORY
;
1095 ret
= samba_kdc_get_claims_data_from_db(p
->kdc_db_ctx
->samdb
,
1098 if (ret
!= LDB_SUCCESS
) {
1099 nt_status
= dsdb_ldb_err_to_ntstatus(ret
);
1100 DBG_ERR("Building claims failed: %s\n",
1101 nt_errstr(nt_status
));
1102 talloc_free(claims_blob
);
1106 nt_status
= claims_data_encoded_claims_set(claims_blob
,
1109 if (!NT_STATUS_IS_OK(nt_status
)) {
1110 talloc_free(claims_blob
);
1114 *_claims_blob
= claims_blob
;
1116 return NT_STATUS_OK
;
1119 krb5_error_code
samba_kdc_get_user_info_from_db(TALLOC_CTX
*mem_ctx
,
1120 struct ldb_context
*samdb
,
1121 struct samba_kdc_entry
*entry
,
1122 const struct ldb_message
*msg
,
1123 const struct auth_user_info_dc
**info_out
)
1127 if (samdb
== NULL
) {
1135 if (info_out
== NULL
) {
1139 if (entry
== NULL
) {
1140 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1145 if (entry
->info_from_db
== NULL
) {
1146 struct auth_user_info_dc
*info_from_db
= NULL
;
1147 struct loadparm_context
*lp_ctx
= entry
->kdc_db_ctx
->lp_ctx
;
1149 nt_status
= authsam_make_user_info_dc(entry
,
1151 lpcfg_netbios_name(lp_ctx
),
1152 lpcfg_sam_name(lp_ctx
),
1153 lpcfg_sam_dnsname(lp_ctx
),
1159 if (!NT_STATUS_IS_OK(nt_status
)) {
1160 DBG_ERR("Getting user info for PAC failed: %s\n",
1161 nt_errstr(nt_status
));
1162 /* NT_STATUS_OBJECT_NAME_NOT_FOUND is mapped to ENOENT. */
1163 return map_errno_from_nt_status(nt_status
);
1166 entry
->info_from_db
= info_from_db
;
1169 *info_out
= entry
->info_from_db
;
1175 * Check whether a PAC contains the Authentication Authority Asserted Identity
1178 static krb5_error_code
samba_kdc_pac_contains_asserted_identity(
1179 krb5_context context
,
1180 const struct samba_kdc_entry_pac entry
,
1183 TALLOC_CTX
*frame
= NULL
;
1184 struct auth_user_info_dc
*info
= NULL
;
1185 krb5_error_code ret
= 0;
1187 if (contains_out
== NULL
) {
1191 *contains_out
= false;
1193 frame
= talloc_stackframe();
1196 * Extract our info from the PAC. This does a bit of unnecessary work,
1197 * setting up fields we don’t care about — we only want the SIDs.
1199 ret
= kerberos_pac_to_user_info_dc(frame
,
1203 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1204 NULL
/* pac_srv_sig */,
1205 NULL
/* pac_kdc_sig */,
1206 /* Ignore the resource groups. */
1207 NULL
/* resource_groups */);
1209 const char *krb5err
= krb5_get_error_message(context
, ret
);
1210 DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1211 krb5err
!= NULL
? krb5err
: "?");
1212 krb5_free_error_message(context
, krb5err
);
1217 /* Determine whether the PAC contains the Asserted Identity SID. */
1218 *contains_out
= sid_attrs_contains_sid(
1221 &global_sid_Asserted_Identity_Authentication_Authority
);
1228 static krb5_error_code
samba_kdc_get_user_info_from_pac(TALLOC_CTX
*mem_ctx
,
1229 krb5_context context
,
1230 struct ldb_context
*samdb
,
1231 const struct samba_kdc_entry_pac entry
,
1232 const struct auth_user_info_dc
**info_out
,
1233 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups_out
)
1235 TALLOC_CTX
*frame
= NULL
;
1236 struct auth_user_info_dc
*info
= NULL
;
1237 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
1238 krb5_error_code ret
= 0;
1241 if (samdb
== NULL
) {
1246 if (!samba_krb5_pac_is_trusted(entry
)) {
1251 if (info_out
== NULL
) {
1257 if (resource_groups_out
!= NULL
) {
1258 *resource_groups_out
= NULL
;
1261 if (entry
.entry
== NULL
|| entry
.entry
->info_from_pac
== NULL
) {
1262 frame
= talloc_stackframe();
1264 ret
= kerberos_pac_to_user_info_dc(frame
,
1268 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1273 const char *krb5err
= krb5_get_error_message(context
, ret
);
1274 DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1275 krb5err
!= NULL
? krb5err
: "?");
1276 krb5_free_error_message(context
, krb5err
);
1282 * We need to expand group memberships within our local domain,
1283 * as the token might be generated by a trusted domain.
1285 nt_status
= authsam_update_user_info_dc(frame
,
1288 if (!NT_STATUS_IS_OK(nt_status
)) {
1289 DBG_ERR("authsam_update_user_info_dc failed: %s\n",
1290 nt_errstr(nt_status
));
1292 ret
= map_errno_from_nt_status(nt_status
);
1296 if (entry
.entry
!= NULL
) {
1297 entry
.entry
->info_from_pac
= talloc_steal(entry
.entry
, info
);
1298 entry
.entry
->resource_groups_from_pac
= talloc_steal(entry
.entry
, resource_groups
);
1303 if (entry
.entry
!= NULL
) {
1304 /* Note: the caller does not own this! */
1305 *info_out
= entry
.entry
->info_from_pac
;
1307 if (resource_groups_out
!= NULL
) {
1308 /* Note: the caller does not own this! */
1309 *resource_groups_out
= entry
.entry
->resource_groups_from_pac
;
1312 *info_out
= talloc_steal(mem_ctx
, info
);
1314 if (resource_groups_out
!= NULL
) {
1315 *resource_groups_out
= talloc_steal(mem_ctx
, resource_groups
);
1324 krb5_error_code
samba_kdc_get_user_info_dc(TALLOC_CTX
*mem_ctx
,
1325 krb5_context context
,
1326 struct ldb_context
*samdb
,
1327 const struct samba_kdc_entry_pac entry
,
1328 const struct auth_user_info_dc
**info_out
,
1329 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups_out
)
1331 const struct auth_user_info_dc
*info
= NULL
;
1332 struct auth_user_info_dc
*info_shallow_copy
= NULL
;
1333 bool pac_contains_asserted_identity
= false;
1334 krb5_error_code ret
= 0;
1338 if (resource_groups_out
!= NULL
) {
1339 *resource_groups_out
= NULL
;
1342 if (samba_krb5_pac_is_trusted(entry
)) {
1343 return samba_kdc_get_user_info_from_pac(mem_ctx
,
1348 resource_groups_out
);
1351 if (entry
.entry
== NULL
) {
1352 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1356 * In this case the RWDC discards the PAC an RODC generated.
1357 * Windows adds the asserted_identity in this case too.
1359 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1360 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1361 * So we can always use
1362 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1365 ret
= samba_kdc_get_user_info_from_db(mem_ctx
,
1371 const char *krb5err
= krb5_get_error_message(context
, ret
);
1372 DBG_ERR("samba_kdc_get_user_info_from_db: %s\n",
1373 krb5err
!= NULL
? krb5err
: "?");
1374 krb5_free_error_message(context
, krb5err
);
1376 return KRB5KDC_ERR_TGT_REVOKED
;
1379 /* Make a shallow copy of the user_info_dc structure. */
1380 nt_status
= authsam_shallow_copy_user_info_dc(mem_ctx
,
1382 &info_shallow_copy
);
1385 if (!NT_STATUS_IS_OK(nt_status
)) {
1386 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
1387 nt_errstr(nt_status
));
1388 return map_errno_from_nt_status(nt_status
);
1391 /* Determine whether the PAC contains the Asserted Identity SID. */
1392 ret
= samba_kdc_pac_contains_asserted_identity(
1393 context
, entry
, &pac_contains_asserted_identity
);
1398 if (pac_contains_asserted_identity
) {
1399 nt_status
= samba_kdc_add_asserted_identity(
1400 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
,
1402 if (!NT_STATUS_IS_OK(nt_status
)) {
1403 DBG_ERR("Failed to add asserted identity: %s\n",
1404 nt_errstr(nt_status
));
1405 TALLOC_FREE(info_shallow_copy
);
1406 return KRB5KDC_ERR_TGT_REVOKED
;
1410 nt_status
= samba_kdc_add_claims_valid(info_shallow_copy
);
1411 if (!NT_STATUS_IS_OK(nt_status
)) {
1412 DBG_ERR("Failed to add Claims Valid: %s\n",
1413 nt_errstr(nt_status
));
1414 TALLOC_FREE(info_shallow_copy
);
1415 return KRB5KDC_ERR_TGT_REVOKED
;
1418 *info_out
= info_shallow_copy
;
1423 static NTSTATUS
samba_kdc_update_delegation_info_blob(TALLOC_CTX
*mem_ctx
,
1424 krb5_context context
,
1425 const krb5_const_pac pac
,
1426 const krb5_const_principal server_principal
,
1427 const krb5_const_principal proxy_principal
,
1428 DATA_BLOB
*new_blob
)
1430 krb5_data old_data
= {};
1432 krb5_error_code ret
;
1433 NTSTATUS nt_status
= NT_STATUS_OK
;
1434 enum ndr_err_code ndr_err
;
1435 union PAC_INFO info
= {};
1436 struct PAC_CONSTRAINED_DELEGATION _d
= {};
1437 struct PAC_CONSTRAINED_DELEGATION
*d
= NULL
;
1438 char *server
= NULL
;
1441 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1443 if (tmp_ctx
== NULL
) {
1444 nt_status
= NT_STATUS_NO_MEMORY
;
1448 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_CONSTRAINED_DELEGATION
, &old_data
);
1449 if (ret
== ENOENT
) {
1452 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1456 old_blob
.length
= old_data
.length
;
1457 old_blob
.data
= (uint8_t *)old_data
.data
;
1459 if (old_blob
.length
> 0) {
1460 ndr_err
= ndr_pull_union_blob(&old_blob
, tmp_ctx
,
1461 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1462 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1463 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1464 smb_krb5_free_data_contents(context
, &old_data
);
1465 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1466 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1470 info
.constrained_delegation
.info
= &_d
;
1472 smb_krb5_free_data_contents(context
, &old_data
);
1474 ret
= krb5_unparse_name_flags(context
, server_principal
,
1475 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &server
);
1477 nt_status
= NT_STATUS_INTERNAL_ERROR
;
1481 ret
= krb5_unparse_name(context
, proxy_principal
, &proxy
);
1484 nt_status
= NT_STATUS_INTERNAL_ERROR
;
1488 d
= info
.constrained_delegation
.info
;
1489 i
= d
->num_transited_services
;
1490 d
->proxy_target
.string
= server
;
1491 d
->transited_services
= talloc_realloc(mem_ctx
, d
->transited_services
,
1492 struct lsa_String
, i
+ 1);
1493 if (d
->transited_services
== NULL
) {
1496 nt_status
= NT_STATUS_INTERNAL_ERROR
;
1499 d
->transited_services
[i
].string
= proxy
;
1500 d
->num_transited_services
= i
+ 1;
1502 ndr_err
= ndr_push_union_blob(new_blob
, mem_ctx
,
1503 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1504 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1507 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1508 smb_krb5_free_data_contents(context
, &old_data
);
1509 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1510 DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
));
1515 talloc_free(tmp_ctx
);
1519 /* function to map policy errors */
1520 krb5_error_code
samba_kdc_map_policy_err(NTSTATUS nt_status
)
1522 krb5_error_code ret
;
1524 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_MUST_CHANGE
))
1525 ret
= KRB5KDC_ERR_KEY_EXP
;
1526 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_EXPIRED
))
1527 ret
= KRB5KDC_ERR_KEY_EXP
;
1528 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_EXPIRED
))
1529 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1530 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_DISABLED
))
1531 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1532 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_LOGON_HOURS
))
1533 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1534 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_LOCKED_OUT
))
1535 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1536 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_WORKSTATION
))
1537 ret
= KRB5KDC_ERR_POLICY
;
1539 ret
= KRB5KDC_ERR_POLICY
;
1544 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1545 * for consistency */
1546 NTSTATUS
samba_kdc_check_client_access(struct samba_kdc_entry
*kdc_entry
,
1547 const char *client_name
,
1548 const char *workstation
,
1549 bool password_change
)
1551 TALLOC_CTX
*tmp_ctx
;
1554 tmp_ctx
= talloc_named(NULL
, 0, "samba_kdc_check_client_access");
1556 return NT_STATUS_NO_MEMORY
;
1559 /* we allow all kinds of trusts here */
1560 nt_status
= authsam_account_ok(tmp_ctx
,
1561 kdc_entry
->kdc_db_ctx
->samdb
,
1562 kdc_entry
->current_nttime
,
1563 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
1564 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
1565 kdc_entry
->realm_dn
, kdc_entry
->msg
,
1566 workstation
, client_name
,
1567 true, password_change
);
1569 kdc_entry
->reject_status
= nt_status
;
1570 talloc_free(tmp_ctx
);
1574 static krb5_error_code
samba_get_requester_sid(TALLOC_CTX
*mem_ctx
,
1576 krb5_context context
,
1577 struct dom_sid
*sid
)
1580 enum ndr_err_code ndr_err
;
1581 krb5_error_code ret
= 0;
1583 DATA_BLOB pac_requester_sid_in
;
1584 krb5_data k5pac_requester_sid_in
;
1586 union PAC_INFO info
;
1588 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1589 if (tmp_ctx
== NULL
) {
1594 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_REQUESTER_SID
,
1595 &k5pac_requester_sid_in
);
1600 pac_requester_sid_in
= data_blob_const(k5pac_requester_sid_in
.data
,
1601 k5pac_requester_sid_in
.length
);
1603 ndr_err
= ndr_pull_union_blob(&pac_requester_sid_in
, tmp_ctx
, &info
,
1604 PAC_TYPE_REQUESTER_SID
,
1605 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1606 smb_krb5_free_data_contents(context
, &k5pac_requester_sid_in
);
1607 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1608 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1609 DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status
));
1610 ret
= map_errno_from_nt_status(nt_status
);
1614 *sid
= info
.requester_sid
.sid
;
1617 talloc_free(tmp_ctx
);
1621 /* Does a parse and SID check, but no crypto. */
1622 static krb5_error_code
samba_kdc_validate_pac_blob(
1623 krb5_context context
,
1624 const struct samba_kdc_entry_pac client
)
1626 TALLOC_CTX
*frame
= talloc_stackframe();
1627 struct auth_user_info_dc
*pac_user_info
= NULL
;
1628 struct dom_sid client_sid
;
1629 struct dom_sid pac_sid
;
1630 krb5_error_code code
;
1634 * First, try to get the SID from the requester SID buffer in the PAC.
1636 code
= samba_get_requester_sid(frame
, client
.pac
, context
, &pac_sid
);
1638 if (code
== ENOENT
) {
1640 * If the requester SID buffer isn't present, fall back to the
1641 * SID in the LOGON_INFO PAC buffer.
1643 code
= kerberos_pac_to_user_info_dc(frame
,
1647 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1655 if (pac_user_info
->num_sids
== 0) {
1660 pac_sid
= pac_user_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1661 } else if (code
!= 0) {
1665 code
= samdb_result_dom_sid_buf(client
.entry
->msg
,
1672 ok
= dom_sid_equal(&pac_sid
, &client_sid
);
1674 struct dom_sid_buf buf1
;
1675 struct dom_sid_buf buf2
;
1677 DBG_ERR("SID mismatch between PAC and looked up client: "
1678 "PAC[%s] != CLI[%s]\n",
1679 dom_sid_str_buf(&pac_sid
, &buf1
),
1680 dom_sid_str_buf(&client_sid
, &buf2
));
1681 code
= KRB5KDC_ERR_TGT_REVOKED
;
1693 * In the RODC case, to confirm that the returned user is permitted to
1694 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1696 static WERROR
samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids
,
1697 const struct dom_sid
*object_sids
,
1698 const struct samba_kdc_entry
*rodc
,
1699 const struct samba_kdc_entry
*object
)
1703 TALLOC_CTX
*frame
= talloc_stackframe();
1704 const char *rodc_attrs
[] = { "msDS-KrbTgtLink",
1705 "msDS-NeverRevealGroup",
1706 "msDS-RevealOnDemandGroup",
1707 "userAccountControl",
1710 struct ldb_result
*rodc_machine_account
= NULL
;
1711 struct ldb_dn
*rodc_machine_account_dn
= samdb_result_dn(rodc
->kdc_db_ctx
->samdb
,
1714 "msDS-KrbTgtLinkBL",
1716 const struct dom_sid
*rodc_machine_account_sid
= NULL
;
1718 if (rodc_machine_account_dn
== NULL
) {
1719 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1720 ldb_dn_get_linearized(rodc
->msg
->dn
));
1722 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1726 * Follow the link and get the RODC account (the krbtgt
1727 * account is the krbtgt_XXX account, but the
1728 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1729 * the RODC$ account)
1731 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1732 * out of the extended DNs
1735 ret
= dsdb_search_dn(rodc
->kdc_db_ctx
->samdb
,
1737 &rodc_machine_account
,
1738 rodc_machine_account_dn
,
1740 DSDB_SEARCH_SHOW_EXTENDED_DN
);
1741 if (ret
!= LDB_SUCCESS
) {
1742 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1743 ldb_dn_get_linearized(rodc_machine_account_dn
),
1744 ldb_dn_get_linearized(rodc
->msg
->dn
),
1745 ldb_errstring(rodc
->kdc_db_ctx
->samdb
));
1747 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1750 if (rodc_machine_account
->count
!= 1) {
1751 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1752 ldb_dn_get_linearized(rodc_machine_account_dn
),
1753 ldb_dn_get_linearized(rodc
->msg
->dn
),
1754 rodc_machine_account
->count
);
1756 return WERR_DS_DRA_BAD_DN
;
1759 /* if the object SID is equal to the user_sid, allow */
1760 rodc_machine_account_sid
= samdb_result_dom_sid(frame
,
1761 rodc_machine_account
->msgs
[0],
1763 if (rodc_machine_account_sid
== NULL
) {
1765 return WERR_DS_DRA_BAD_DN
;
1768 werr
= samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc
->kdc_db_ctx
->samdb
,
1769 rodc_machine_account_sid
,
1770 rodc_machine_account
->msgs
[0],
1780 * Perform an access check for the client attempting to authenticate to the
1781 * server. ‘client_info’ must be talloc-allocated so that we can make a
1784 krb5_error_code
samba_kdc_allowed_to_authenticate_to(TALLOC_CTX
*mem_ctx
,
1785 struct ldb_context
*samdb
,
1786 struct loadparm_context
*lp_ctx
,
1787 const struct samba_kdc_entry
*client
,
1788 const struct auth_user_info_dc
*client_info
,
1789 const struct auth_user_info_dc
*device_info
,
1790 const struct auth_claims auth_claims
,
1791 const struct samba_kdc_entry
*server
,
1792 struct authn_audit_info
**server_audit_info_out
,
1793 NTSTATUS
*status_out
)
1795 krb5_error_code ret
= 0;
1797 _UNUSED_ NTSTATUS _status
;
1798 struct dom_sid server_sid
= {};
1799 const struct authn_server_policy
*server_policy
= server
->server_policy
;
1801 if (status_out
!= NULL
) {
1802 *status_out
= NT_STATUS_OK
;
1805 ret
= samdb_result_dom_sid_buf(server
->msg
, "objectSid", &server_sid
);
1808 * Ignore the return status — we are already in an error path,
1809 * and overwriting the real error code with the audit info
1810 * status is unhelpful.
1812 _status
= authn_server_policy_audit_info(mem_ctx
,
1815 AUTHN_AUDIT_EVENT_OTHER_ERROR
,
1816 AUTHN_AUDIT_REASON_NONE
,
1817 dsdb_ldb_err_to_ntstatus(ret
),
1818 server_audit_info_out
);
1822 if (dom_sid_equal(&client_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
, &server_sid
)) {
1823 /* Authenticating to ourselves is always allowed. */
1824 status
= authn_server_policy_audit_info(mem_ctx
,
1827 AUTHN_AUDIT_EVENT_OK
,
1828 AUTHN_AUDIT_REASON_NONE
,
1830 server_audit_info_out
);
1831 if (!NT_STATUS_IS_OK(status
)) {
1832 ret
= KRB5KRB_ERR_GENERIC
;
1837 status
= authn_policy_authenticate_to_service(mem_ctx
,
1840 AUTHN_POLICY_AUTH_TYPE_KERBEROS
,
1845 (struct authn_policy_flags
) { .force_compounded_authentication
= true },
1846 server_audit_info_out
);
1847 if (!NT_STATUS_IS_OK(status
)) {
1848 if (status_out
!= NULL
) {
1849 *status_out
= status
;
1851 if (NT_STATUS_EQUAL(status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
1852 ret
= KRB5KDC_ERR_POLICY
;
1853 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1854 ret
= KRB5KDC_ERR_POLICY
;
1856 ret
= KRB5KRB_ERR_GENERIC
;
1864 static krb5_error_code
samba_kdc_add_domain_group_sid(struct PAC_DEVICE_INFO
*info
,
1865 const struct netr_SidAttr
*sid
)
1871 uint32_t domain_group_count
= info
->domain_group_count
;
1872 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_group
= NULL
;
1873 struct samr_RidWithAttribute
*rids
= NULL
;
1875 for (i
= 0; i
< domain_group_count
; ++i
) {
1876 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*this_domain_group
1877 = &info
->domain_groups
[i
];
1879 if (dom_sid_in_domain(this_domain_group
->domain_sid
, sid
->sid
)) {
1880 domain_group
= this_domain_group
;
1885 if (domain_group
== NULL
) {
1886 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_groups
= NULL
;
1888 if (domain_group_count
== UINT32_MAX
) {
1892 domain_groups
= talloc_realloc(
1894 info
->domain_groups
,
1895 struct PAC_DOMAIN_GROUP_MEMBERSHIP
,
1896 domain_group_count
+ 1);
1897 if (domain_groups
== NULL
) {
1901 info
->domain_groups
= domain_groups
;
1903 domain_group
= &info
->domain_groups
[domain_group_count
++];
1904 *domain_group
= (struct PAC_DOMAIN_GROUP_MEMBERSHIP
) {};
1906 status
= dom_sid_split_rid(info
->domain_groups
,
1908 &domain_group
->domain_sid
,
1910 if (!NT_STATUS_IS_OK(status
)) {
1911 return map_errno_from_nt_status(status
);
1914 status
= dom_sid_split_rid(NULL
,
1918 if (!NT_STATUS_IS_OK(status
)) {
1919 return map_errno_from_nt_status(status
);
1923 if (domain_group
->groups
.count
== UINT32_MAX
) {
1927 rids
= talloc_realloc(info
->domain_groups
,
1928 domain_group
->groups
.rids
,
1929 struct samr_RidWithAttribute
,
1930 domain_group
->groups
.count
+ 1);
1935 domain_group
->groups
.rids
= rids
;
1937 domain_group
->groups
.rids
[domain_group
->groups
.count
] = (struct samr_RidWithAttribute
) {
1939 .attributes
= sid
->attributes
,
1942 ++domain_group
->groups
.count
;
1944 info
->domain_group_count
= domain_group_count
;
1949 static krb5_error_code
samba_kdc_make_device_info(TALLOC_CTX
*mem_ctx
,
1950 const struct netr_SamInfo3
*info3
,
1951 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
1952 union PAC_INFO
*info
)
1954 TALLOC_CTX
*tmp_ctx
= NULL
;
1955 struct PAC_DEVICE_INFO
*device_info
= NULL
;
1957 krb5_error_code ret
= 0;
1959 *info
= (union PAC_INFO
) {};
1961 info
->device_info
.info
= NULL
;
1963 tmp_ctx
= talloc_new(mem_ctx
);
1964 if (tmp_ctx
== NULL
) {
1968 device_info
= talloc(tmp_ctx
, struct PAC_DEVICE_INFO
);
1969 if (device_info
== NULL
) {
1974 device_info
->rid
= info3
->base
.rid
;
1975 device_info
->primary_gid
= info3
->base
.primary_gid
;
1976 device_info
->domain_sid
= info3
->base
.domain_sid
;
1977 device_info
->groups
= info3
->base
.groups
;
1979 device_info
->sid_count
= 0;
1980 device_info
->sids
= NULL
;
1982 if (resource_groups
!= NULL
) {
1984 * The account's resource groups all belong to the same domain,
1985 * so we can add them all in one go.
1987 device_info
->domain_group_count
= 1;
1988 device_info
->domain_groups
= talloc_move(device_info
, &resource_groups
);
1990 device_info
->domain_group_count
= 0;
1991 device_info
->domain_groups
= NULL
;
1994 for (i
= 0; i
< info3
->sidcount
; ++i
) {
1995 const struct netr_SidAttr
*device_sid
= &info3
->sids
[i
];
1997 if (dom_sid_has_account_domain(device_sid
->sid
)) {
1998 ret
= samba_kdc_add_domain_group_sid(device_info
, device_sid
);
2003 device_info
->sids
= talloc_realloc(device_info
, device_info
->sids
,
2004 struct netr_SidAttr
,
2005 device_info
->sid_count
+ 1);
2006 if (device_info
->sids
== NULL
) {
2011 device_info
->sids
[device_info
->sid_count
].sid
= dom_sid_dup(device_info
->sids
, device_sid
->sid
);
2012 if (device_info
->sids
[device_info
->sid_count
].sid
== NULL
) {
2017 device_info
->sids
[device_info
->sid_count
].attributes
= device_sid
->attributes
;
2019 ++device_info
->sid_count
;
2023 info
->device_info
.info
= talloc_steal(mem_ctx
, device_info
);
2026 talloc_free(tmp_ctx
);
2030 static krb5_error_code
samba_kdc_update_device_info(TALLOC_CTX
*mem_ctx
,
2031 struct ldb_context
*samdb
,
2032 const union PAC_INFO
*logon_info
,
2033 struct PAC_DEVICE_INFO
*device_info
)
2036 struct auth_user_info_dc
*device_info_dc
= NULL
;
2037 union netr_Validation validation
;
2039 uint32_t num_existing_sids
;
2042 * This does a bit of unnecessary work, setting up fields we don't care
2043 * about -- we only want the SIDs.
2045 validation
.sam3
= &logon_info
->logon_info
.info
->info3
;
2046 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
2047 true, /* This user was authenticated */
2049 if (!NT_STATUS_IS_OK(nt_status
)) {
2050 return map_errno_from_nt_status(nt_status
);
2053 num_existing_sids
= device_info_dc
->num_sids
;
2056 * We need to expand group memberships within our local domain,
2057 * as the token might be generated by a trusted domain.
2059 nt_status
= authsam_update_user_info_dc(mem_ctx
,
2062 if (!NT_STATUS_IS_OK(nt_status
)) {
2063 return map_errno_from_nt_status(nt_status
);
2066 for (i
= num_existing_sids
; i
< device_info_dc
->num_sids
; ++i
) {
2067 struct auth_SidAttr
*device_sid
= &device_info_dc
->sids
[i
];
2068 const struct netr_SidAttr sid
= (struct netr_SidAttr
) {
2069 .sid
= &device_sid
->sid
,
2070 .attributes
= device_sid
->attrs
,
2073 krb5_error_code ret
= samba_kdc_add_domain_group_sid(device_info
, &sid
);
2082 static krb5_error_code
samba_kdc_get_device_info_pac_blob(TALLOC_CTX
*mem_ctx
,
2083 union PAC_INFO
*info
,
2084 DATA_BLOB
**_device_info_blob
)
2086 DATA_BLOB
*device_info_blob
= NULL
;
2087 enum ndr_err_code ndr_err
;
2089 *_device_info_blob
= NULL
;
2091 device_info_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2092 if (device_info_blob
== NULL
) {
2093 DBG_ERR("Out of memory\n");
2097 ndr_err
= ndr_push_union_blob(device_info_blob
, device_info_blob
,
2098 info
, PAC_TYPE_DEVICE_INFO
,
2099 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
2100 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2101 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
2102 DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
2103 nt_errstr(nt_status
));
2104 talloc_free(device_info_blob
);
2105 return map_errno_from_nt_status(nt_status
);
2108 *_device_info_blob
= device_info_blob
;
2113 static krb5_error_code
samba_kdc_create_device_info_blob(TALLOC_CTX
*mem_ctx
,
2114 krb5_context context
,
2115 struct ldb_context
*samdb
,
2116 const krb5_const_pac device_pac
,
2117 DATA_BLOB
**device_info_blob
)
2119 TALLOC_CTX
*frame
= NULL
;
2120 krb5_data device_logon_info
;
2121 krb5_error_code code
= EINVAL
;
2124 union PAC_INFO info
;
2125 enum ndr_err_code ndr_err
;
2126 DATA_BLOB device_logon_info_blob
;
2128 union PAC_INFO logon_info
;
2130 code
= krb5_pac_get_buffer(context
, device_pac
,
2131 PAC_TYPE_LOGON_INFO
,
2132 &device_logon_info
);
2134 if (code
== ENOENT
) {
2135 DBG_ERR("Device PAC is missing LOGON_INFO\n");
2137 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
2142 frame
= talloc_stackframe();
2144 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
2145 device_logon_info
.length
);
2147 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &logon_info
,
2148 PAC_TYPE_LOGON_INFO
,
2149 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
2150 smb_krb5_free_data_contents(context
, &device_logon_info
);
2151 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2152 nt_status
= ndr_map_error2ntstatus(ndr_err
);
2153 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
2154 nt_errstr(nt_status
));
2156 return map_errno_from_nt_status(nt_status
);
2160 * When creating the device info structure, existing resource groups are
2163 code
= samba_kdc_make_device_info(frame
,
2164 &logon_info
.logon_info
.info
->info3
,
2165 NULL
, /* resource_groups */
2172 code
= samba_kdc_update_device_info(frame
,
2175 info
.device_info
.info
);
2181 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2189 static krb5_error_code
samba_kdc_get_device_info_blob(TALLOC_CTX
*mem_ctx
,
2190 krb5_context context
,
2191 struct ldb_context
*samdb
,
2192 const struct samba_kdc_entry_pac device
,
2193 DATA_BLOB
**device_info_blob
)
2195 TALLOC_CTX
*frame
= NULL
;
2196 krb5_error_code code
= EINVAL
;
2199 const struct auth_user_info_dc
*device_info
= NULL
;
2200 struct netr_SamInfo3
*info3
= NULL
;
2201 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
2203 union PAC_INFO info
;
2205 frame
= talloc_stackframe();
2207 code
= samba_kdc_get_user_info_dc(frame
,
2212 NULL
/* resource_groups_out */);
2214 const char *krb5_err
= krb5_get_error_message(context
, code
);
2215 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2216 krb5_err
!= NULL
? krb5_err
: "<unknown>");
2217 krb5_free_error_message(context
, krb5_err
);
2220 return KRB5KDC_ERR_TGT_REVOKED
;
2223 nt_status
= auth_convert_user_info_dc_saminfo3(frame
, device_info
,
2224 AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
,
2227 if (!NT_STATUS_IS_OK(nt_status
)) {
2228 DBG_WARNING("Getting Samba info failed: %s\n",
2229 nt_errstr(nt_status
));
2231 return nt_status_to_krb5(nt_status
);
2234 code
= samba_kdc_make_device_info(frame
,
2243 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2252 * @brief Verify a PAC
2254 * @param mem_ctx A talloc memory context
2256 * @param context A krb5 context
2258 * @param samdb An open samdb connection.
2260 * @param flags Bitwise OR'ed flags
2262 * @param client The client samba kdc PAC entry.
2264 * @param krbtgt The krbtgt samba kdc entry.
2266 * @return A Kerberos error code.
2268 krb5_error_code
samba_kdc_verify_pac(TALLOC_CTX
*mem_ctx
,
2269 krb5_context context
,
2270 struct ldb_context
*samdb
,
2272 const struct samba_kdc_entry_pac client
,
2273 const struct samba_kdc_entry
*krbtgt
)
2275 TALLOC_CTX
*tmp_ctx
= NULL
;
2276 struct pac_blobs
*pac_blobs
= NULL
;
2277 krb5_error_code code
= EINVAL
;
2279 tmp_ctx
= talloc_new(mem_ctx
);
2280 if (tmp_ctx
== NULL
) {
2285 if (client
.entry
!= NULL
) {
2287 * Check the objectSID of the client and pac data are the same.
2288 * Does a parse and SID check, but no crypto.
2290 code
= samba_kdc_validate_pac_blob(context
, client
);
2296 if (!samba_krb5_pac_is_trusted(client
)) {
2297 const struct auth_user_info_dc
*user_info_dc
= NULL
;
2300 struct dom_sid
*object_sids
= NULL
;
2303 if (client
.entry
== NULL
) {
2304 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2308 code
= samba_kdc_get_user_info_from_db(tmp_ctx
,
2314 const char *krb5_err
= krb5_get_error_message(context
, code
);
2315 DBG_ERR("Getting user info for PAC failed: %s\n",
2316 krb5_err
!= NULL
? krb5_err
: "<unknown>");
2317 krb5_free_error_message(context
, krb5_err
);
2319 code
= KRB5KDC_ERR_TGT_REVOKED
;
2324 * Check if the SID list in the user_info_dc intersects
2325 * correctly with the RODC allow/deny lists.
2327 object_sids
= talloc_array(tmp_ctx
, struct dom_sid
, user_info_dc
->num_sids
);
2328 if (object_sids
== NULL
) {
2333 for (j
= 0; j
< user_info_dc
->num_sids
; ++j
) {
2334 object_sids
[j
] = user_info_dc
->sids
[j
].sid
;
2337 werr
= samba_rodc_confirm_user_is_allowed(user_info_dc
->num_sids
,
2341 if (!W_ERROR_IS_OK(werr
)) {
2342 code
= KRB5KDC_ERR_TGT_REVOKED
;
2343 if (W_ERROR_EQUAL(werr
,
2344 WERR_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2345 code
= KRB5KDC_ERR_POLICY
;
2351 * The RODC PAC data isn't trusted for authorization as it may
2352 * be stale. The only thing meaningful we can do with an RODC
2353 * account on a full DC is exchange the RODC TGT for a 'real'
2356 * So we match Windows (at least server 2022) and
2357 * don't allow S4U2Self.
2359 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
2361 if (flags
& SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
) {
2362 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2367 /* Check the types of the given PAC */
2369 code
= pac_blobs_from_krb5_pac(tmp_ctx
,
2377 code
= pac_blobs_ensure_exists(pac_blobs
,
2378 PAC_TYPE_LOGON_INFO
);
2383 code
= pac_blobs_ensure_exists(pac_blobs
,
2384 PAC_TYPE_LOGON_NAME
);
2389 code
= pac_blobs_ensure_exists(pac_blobs
,
2390 PAC_TYPE_SRV_CHECKSUM
);
2395 code
= pac_blobs_ensure_exists(pac_blobs
,
2396 PAC_TYPE_KDC_CHECKSUM
);
2401 if (!(flags
& SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
)) {
2402 code
= pac_blobs_ensure_exists(pac_blobs
,
2403 PAC_TYPE_REQUESTER_SID
);
2405 code
= KRB5KDC_ERR_TGT_REVOKED
;
2413 talloc_free(tmp_ctx
);
2419 * @brief Update a PAC
2421 * @param mem_ctx A talloc memory context
2423 * @param context A krb5 context
2425 * @param samdb An open samdb connection.
2427 * @param lp_ctx A loadparm context.
2429 * @param flags Bitwise OR'ed flags
2431 * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
2432 * as opposed to an RODC.
2434 * @param client The client samba kdc PAC entry.
2436 * @param server_principal The server principal
2438 * @param server The server samba kdc entry.
2440 * @param delegated_proxy_principal The delegated proxy principal used for
2441 * updating the constrained delegation PAC
2444 * @param delegated_proxy The delegated proxy kdc PAC entry.
2446 * @param device The computer's samba kdc PAC entry; used for compound
2449 * @param new_pac The new already allocated PAC
2451 * @return A Kerberos error code. If no PAC should be returned, the code will be
2454 krb5_error_code
samba_kdc_update_pac(TALLOC_CTX
*mem_ctx
,
2455 krb5_context context
,
2456 struct ldb_context
*samdb
,
2457 struct loadparm_context
*lp_ctx
,
2459 const struct samba_kdc_entry_pac client
,
2460 const krb5_const_principal server_principal
,
2461 const struct samba_kdc_entry
*server
,
2462 const krb5_const_principal delegated_proxy_principal
,
2463 const struct samba_kdc_entry_pac delegated_proxy
,
2464 const struct samba_kdc_entry_pac device
,
2466 struct authn_audit_info
**server_audit_info_out
,
2467 NTSTATUS
*status_out
)
2469 TALLOC_CTX
*tmp_ctx
= NULL
;
2470 krb5_error_code code
= EINVAL
;
2472 DATA_BLOB
*pac_blob
= NULL
;
2473 DATA_BLOB
*upn_blob
= NULL
;
2474 DATA_BLOB
*deleg_blob
= NULL
;
2475 DATA_BLOB
*requester_sid_blob
= NULL
;
2476 const DATA_BLOB
*client_claims_blob
= NULL
;
2477 DATA_BLOB device_claims_blob
= {};
2478 const DATA_BLOB
*device_claims_blob_ptr
= NULL
;
2479 struct auth_claims auth_claims
= {};
2480 DATA_BLOB
*device_info_blob
= NULL
;
2481 bool is_tgs
= false;
2482 bool server_restrictions_present
= false;
2483 struct pac_blobs
*pac_blobs
= NULL
;
2484 const struct auth_user_info_dc
*user_info_dc_const
= NULL
;
2485 struct auth_user_info_dc
*user_info_dc_shallow_copy
= NULL
;
2486 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
2487 enum auth_group_inclusion group_inclusion
;
2488 bool compounded_auth
;
2491 if (server_audit_info_out
!= NULL
) {
2492 *server_audit_info_out
= NULL
;
2495 if (status_out
!= NULL
) {
2496 *status_out
= NT_STATUS_OK
;
2499 tmp_ctx
= talloc_new(mem_ctx
);
2500 if (tmp_ctx
== NULL
) {
2506 int result
= smb_krb5_principal_is_tgs(context
, server_principal
);
2515 server_restrictions_present
= !is_tgs
&& authn_policy_restrictions_present(server
->server_policy
);
2517 /* Only include resource groups in a service ticket. */
2519 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
2520 } else if (server
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
2521 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
2523 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
2526 compounded_auth
= device
.entry
!= NULL
&& !is_tgs
2527 && server
->supported_enctypes
& KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED
;
2529 if (compounded_auth
|| (server_restrictions_present
&& device
.entry
!= NULL
)) {
2531 * [MS-KILE] 3.3.5.7.4 Compound Identity: the client claims from
2532 * the device PAC become the device claims in the new PAC.
2534 code
= samba_kdc_get_claims_data(tmp_ctx
,
2538 &auth_claims
.device_claims
);
2543 if (compounded_auth
) {
2544 nt_status
= claims_data_encoded_claims_set(tmp_ctx
,
2545 auth_claims
.device_claims
,
2546 &device_claims_blob
);
2547 if (!NT_STATUS_IS_OK(nt_status
)) {
2548 DBG_ERR("claims_data_encoded_claims_set failed: %s\n",
2549 nt_errstr(nt_status
));
2550 code
= map_errno_from_nt_status(nt_status
);
2554 device_claims_blob_ptr
= &device_claims_blob
;
2556 if (samba_krb5_pac_is_trusted(device
)) {
2557 code
= samba_kdc_create_device_info_blob(tmp_ctx
,
2566 /* Don't trust an RODC‐issued PAC; regenerate the device info. */
2567 code
= samba_kdc_get_device_info_blob(tmp_ctx
,
2579 if (delegated_proxy_principal
!= NULL
) {
2580 deleg_blob
= talloc_zero(tmp_ctx
, DATA_BLOB
);
2581 if (deleg_blob
== NULL
) {
2586 nt_status
= samba_kdc_update_delegation_info_blob(
2591 delegated_proxy_principal
,
2593 if (!NT_STATUS_IS_OK(nt_status
)) {
2594 DBG_ERR("update delegation info blob failed: %s\n",
2595 nt_errstr(nt_status
));
2596 code
= map_errno_from_nt_status(nt_status
);
2602 * If we are creating a TGT, resource groups from our domain are not to
2603 * be put into the PAC. Instead, we take the resource groups directly
2604 * from the original PAC and copy them unmodified into the new one.
2606 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2610 &user_info_dc_const
,
2611 is_tgs
? &_resource_groups
: NULL
);
2613 const char *err_str
= krb5_get_error_message(context
, code
);
2614 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2615 err_str
!= NULL
? err_str
: "<unknown>");
2616 krb5_free_error_message(context
, err_str
);
2622 * Enforce the AllowedToAuthenticateTo part of an authentication policy,
2623 * if one is present.
2625 if (server_restrictions_present
) {
2626 struct samba_kdc_entry_pac auth_entry
;
2627 const struct auth_user_info_dc
*auth_user_info_dc
= NULL
;
2628 const struct auth_user_info_dc
*device_info
= NULL
;
2630 if (delegated_proxy
.entry
!= NULL
) {
2631 auth_entry
= delegated_proxy
;
2633 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2638 NULL
/* resource_groups_out */);
2643 auth_entry
= client
;
2644 auth_user_info_dc
= user_info_dc_const
;
2647 /* Fetch the user’s claims. */
2648 code
= samba_kdc_get_claims_data(tmp_ctx
,
2652 &auth_claims
.user_claims
);
2657 if (device
.entry
!= NULL
) {
2658 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2663 NULL
/* resource_groups_out */);
2670 * Allocate the audit info and output status on to the parent
2671 * mem_ctx, not the temporary context.
2673 code
= samba_kdc_allowed_to_authenticate_to(mem_ctx
,
2681 server_audit_info_out
,
2688 if (compounded_auth
) {
2689 /* Make a shallow copy of the user_info_dc structure. */
2690 nt_status
= authsam_shallow_copy_user_info_dc(tmp_ctx
,
2692 &user_info_dc_shallow_copy
);
2693 user_info_dc_const
= NULL
;
2695 if (!NT_STATUS_IS_OK(nt_status
)) {
2696 DBG_ERR("Failed to copy user_info_dc: %s\n",
2697 nt_errstr(nt_status
));
2699 code
= KRB5KDC_ERR_TGT_REVOKED
;
2703 nt_status
= samba_kdc_add_compounded_auth(user_info_dc_shallow_copy
);
2704 if (!NT_STATUS_IS_OK(nt_status
)) {
2705 DBG_ERR("Failed to add Compounded Authentication: %s\n",
2706 nt_errstr(nt_status
));
2708 code
= KRB5KDC_ERR_TGT_REVOKED
;
2712 /* We can now set back to the const, it will not be modified */
2713 user_info_dc_const
= user_info_dc_shallow_copy
;
2716 if (samba_krb5_pac_is_trusted(client
)) {
2717 pac_blob
= talloc_zero(tmp_ctx
, DATA_BLOB
);
2718 if (pac_blob
== NULL
) {
2723 nt_status
= samba_get_logon_info_pac_blob(tmp_ctx
,
2728 if (!NT_STATUS_IS_OK(nt_status
)) {
2729 DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
2730 nt_errstr(nt_status
));
2732 code
= map_errno_from_nt_status(nt_status
);
2737 * TODO: we need claim translation over trusts,
2738 * for now we just clear them...
2740 if (samba_kdc_entry_pac_issued_by_trust(client
)) {
2741 client_claims_blob
= &data_blob_null
;
2744 nt_status
= samba_kdc_get_logon_info_blob(tmp_ctx
,
2748 if (!NT_STATUS_IS_OK(nt_status
)) {
2749 DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
2750 nt_errstr(nt_status
));
2751 code
= KRB5KDC_ERR_TGT_REVOKED
;
2755 nt_status
= samba_kdc_get_upn_info_blob(tmp_ctx
,
2758 if (!NT_STATUS_IS_OK(nt_status
)) {
2759 DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
2760 nt_errstr(nt_status
));
2761 code
= KRB5KDC_ERR_TGT_REVOKED
;
2766 nt_status
= samba_kdc_get_requester_sid_blob(tmp_ctx
,
2768 &requester_sid_blob
);
2769 if (!NT_STATUS_IS_OK(nt_status
)) {
2770 DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
2771 nt_errstr(nt_status
));
2772 code
= KRB5KDC_ERR_TGT_REVOKED
;
2777 /* Don't trust RODC-issued claims. Regenerate them. */
2778 nt_status
= samba_kdc_get_claims_blob(tmp_ctx
,
2780 &client_claims_blob
);
2781 if (!NT_STATUS_IS_OK(nt_status
)) {
2782 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2783 nt_errstr(nt_status
));
2784 code
= map_errno_from_nt_status(nt_status
);
2789 /* Check the types of the given PAC */
2790 code
= pac_blobs_from_krb5_pac(tmp_ctx
,
2798 code
= pac_blobs_replace_existing(pac_blobs
,
2799 PAC_TYPE_LOGON_INFO
,
2805 #ifdef SAMBA4_USES_HEIMDAL
2806 /* Not needed with MIT Kerberos */
2807 code
= pac_blobs_replace_existing(pac_blobs
,
2808 PAC_TYPE_LOGON_NAME
,
2814 code
= pac_blobs_replace_existing(pac_blobs
,
2815 PAC_TYPE_SRV_CHECKSUM
,
2821 code
= pac_blobs_replace_existing(pac_blobs
,
2822 PAC_TYPE_KDC_CHECKSUM
,
2829 code
= pac_blobs_add_blob(pac_blobs
,
2830 PAC_TYPE_CONSTRAINED_DELEGATION
,
2836 code
= pac_blobs_add_blob(pac_blobs
,
2837 PAC_TYPE_UPN_DNS_INFO
,
2843 code
= pac_blobs_add_blob(pac_blobs
,
2844 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2845 client_claims_blob
);
2850 code
= pac_blobs_add_blob(pac_blobs
,
2851 PAC_TYPE_DEVICE_INFO
,
2857 code
= pac_blobs_add_blob(pac_blobs
,
2858 PAC_TYPE_DEVICE_CLAIMS_INFO
,
2859 device_claims_blob_ptr
);
2864 if (!samba_krb5_pac_is_trusted(client
) || !is_tgs
) {
2865 pac_blobs_remove_blob(pac_blobs
,
2866 PAC_TYPE_ATTRIBUTES_INFO
);
2870 pac_blobs_remove_blob(pac_blobs
,
2871 PAC_TYPE_REQUESTER_SID
);
2874 code
= pac_blobs_add_blob(pac_blobs
,
2875 PAC_TYPE_REQUESTER_SID
,
2876 requester_sid_blob
);
2882 * The server account may be set not to want the PAC.
2884 * While this is wasteful if the above calculations were done
2885 * and now thrown away, this is cleaner as we do any ticket
2886 * signature checking etc always.
2888 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
2889 * time (eg not accepting a ticket from the RODC) we do not
2890 * need to re-generate anything anyway.
2892 if (!samba_princ_needs_pac(server
)) {
2897 if (samba_krb5_pac_is_trusted(client
) && !is_tgs
) {
2899 * The client may have requested no PAC when obtaining the
2902 bool requested_pac
= false;
2904 code
= samba_client_requested_pac(context
,
2908 if (code
!= 0 || !requested_pac
) {
2909 if (!requested_pac
) {
2916 for (i
= 0; i
< pac_blobs
->num_types
; ++i
) {
2917 krb5_data type_data
;
2918 const DATA_BLOB
*type_blob
= pac_blobs
->type_blobs
[i
].data
;
2919 uint32_t type
= pac_blobs
->type_blobs
[i
].type
;
2921 static char null_byte
= '\0';
2922 const krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
2924 #ifndef SAMBA4_USES_HEIMDAL
2925 /* Not needed with MIT Kerberos */
2927 case PAC_TYPE_LOGON_NAME
:
2928 case PAC_TYPE_SRV_CHECKSUM
:
2929 case PAC_TYPE_KDC_CHECKSUM
:
2930 case PAC_TYPE_FULL_CHECKSUM
:
2937 if (type_blob
!= NULL
) {
2938 type_data
= smb_krb5_data_from_blob(*type_blob
);
2940 * Passing a NULL pointer into krb5_pac_add_buffer() is
2941 * not allowed, so pass null_data instead if needed.
2943 code
= krb5_pac_add_buffer(context
,
2946 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2950 } else if (samba_krb5_pac_is_trusted(client
)) {
2952 * Convey the buffer from the original PAC if we can
2956 code
= krb5_pac_get_buffer(context
,
2964 * Passing a NULL pointer into krb5_pac_add_buffer() is
2965 * not allowed, so pass null_data instead if needed.
2967 code
= krb5_pac_add_buffer(context
,
2970 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2971 smb_krb5_free_data_contents(context
, &type_data
);
2980 TALLOC_FREE(tmp_ctx
);
2984 krb5_error_code
samba_kdc_get_claims_data(TALLOC_CTX
*mem_ctx
,
2985 krb5_context context
,
2986 struct ldb_context
*samdb
,
2987 struct samba_kdc_entry_pac entry
,
2988 struct claims_data
**claims_data_out
)
2990 if (samba_kdc_entry_pac_issued_by_trust(entry
)) {
2994 * TODO: we need claim translation over trusts; for now we just
2997 status
= claims_data_from_encoded_claims_set(mem_ctx
,
3000 if (!NT_STATUS_IS_OK(status
)) {
3001 return map_errno_from_nt_status(status
);
3007 if (samba_krb5_pac_is_trusted(entry
)) {
3008 return samba_kdc_get_claims_data_from_pac(mem_ctx
,
3014 return samba_kdc_get_claims_data_from_db(samdb
,
3019 krb5_error_code
samba_kdc_get_claims_data_from_pac(TALLOC_CTX
*mem_ctx
,
3020 krb5_context context
,
3021 struct samba_kdc_entry_pac entry
,
3022 struct claims_data
**claims_data_out
)
3024 TALLOC_CTX
*frame
= NULL
;
3025 krb5_data claims_info
= {};
3026 struct claims_data
*claims_data
= NULL
;
3027 NTSTATUS status
= NT_STATUS_OK
;
3028 krb5_error_code code
;
3030 if (!samba_krb5_pac_is_trusted(entry
)) {
3035 if (samba_kdc_entry_pac_issued_by_trust(entry
)) {
3040 if (claims_data_out
== NULL
) {
3045 *claims_data_out
= NULL
;
3047 if (entry
.entry
!= NULL
&& entry
.entry
->claims_from_pac_are_initialized
) {
3048 /* Note: the caller does not own this! */
3049 *claims_data_out
= entry
.entry
->claims_from_pac
;
3053 frame
= talloc_stackframe();
3055 /* Fetch the claims from the PAC. */
3056 code
= krb5_pac_get_buffer(context
, entry
.pac
,
3057 PAC_TYPE_CLIENT_CLAIMS_INFO
,
3059 if (code
== ENOENT
) {
3061 } else if (code
!= 0) {
3062 DBG_ERR("Error getting CLIENT_CLAIMS_INFO from PAC\n");
3064 } else if (claims_info
.length
) {
3065 DATA_BLOB claims_blob
= data_blob_const(claims_info
.data
,
3066 claims_info
.length
);
3068 status
= claims_data_from_encoded_claims_set(frame
,
3071 if (!NT_STATUS_IS_OK(status
)) {
3072 code
= map_errno_from_nt_status(status
);
3077 if (entry
.entry
!= NULL
) {
3078 /* Note: the caller does not own this! */
3079 entry
.entry
->claims_from_pac
= talloc_steal(entry
.entry
,
3081 entry
.entry
->claims_from_pac_are_initialized
= true;
3083 talloc_steal(mem_ctx
, claims_data
);
3086 *claims_data_out
= claims_data
;
3089 smb_krb5_free_data_contents(context
, &claims_info
);
3094 krb5_error_code
samba_kdc_get_claims_data_from_db(struct ldb_context
*samdb
,
3095 struct samba_kdc_entry
*entry
,
3096 struct claims_data
**claims_data_out
)
3098 TALLOC_CTX
*frame
= NULL
;
3100 struct claims_data
*claims_data
= NULL
;
3101 struct CLAIMS_SET
*claims_set
= NULL
;
3102 NTSTATUS status
= NT_STATUS_OK
;
3103 krb5_error_code code
;
3105 if (samdb
== NULL
) {
3110 if (claims_data_out
== NULL
) {
3115 if (entry
== NULL
) {
3116 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
3120 *claims_data_out
= NULL
;
3122 if (entry
->claims_from_db_are_initialized
) {
3123 /* Note: the caller does not own this! */
3124 *claims_data_out
= entry
->claims_from_db
;
3128 frame
= talloc_stackframe();
3130 code
= get_claims_set_for_principal(samdb
,
3135 DBG_ERR("Failed to fetch claims\n");
3139 if (claims_set
!= NULL
) {
3140 status
= claims_data_from_claims_set(claims_data
,
3143 if (!NT_STATUS_IS_OK(status
)) {
3144 code
= map_errno_from_nt_status(status
);
3149 entry
->claims_from_db
= talloc_steal(entry
,
3151 entry
->claims_from_db_are_initialized
= true;
3153 /* Note: the caller does not own this! */
3154 *claims_data_out
= entry
->claims_from_db
;
3161 krb5_error_code
samba_kdc_check_device(TALLOC_CTX
*mem_ctx
,
3162 krb5_context context
,
3163 struct ldb_context
*samdb
,
3164 struct loadparm_context
*lp_ctx
,
3165 const struct samba_kdc_entry_pac device
,
3166 const struct authn_kerberos_client_policy
*client_policy
,
3167 struct authn_audit_info
**client_audit_info_out
,
3168 NTSTATUS
*status_out
)
3170 TALLOC_CTX
*frame
= NULL
;
3171 krb5_error_code code
= 0;
3173 const struct auth_user_info_dc
*device_info
= NULL
;
3174 struct authn_audit_info
*client_audit_info
= NULL
;
3175 struct auth_claims auth_claims
= {};
3177 if (status_out
!= NULL
) {
3178 *status_out
= NT_STATUS_OK
;
3181 if (!authn_policy_device_restrictions_present(client_policy
)) {
3185 if (device
.entry
== NULL
|| device
.pac
== NULL
) {
3186 NTSTATUS out_status
= NT_STATUS_INVALID_WORKSTATION
;
3188 nt_status
= authn_kerberos_client_policy_audit_info(mem_ctx
,
3190 NULL
/* client_info */,
3191 AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION
,
3192 AUTHN_AUDIT_REASON_FAST_REQUIRED
,
3194 client_audit_info_out
);
3195 if (!NT_STATUS_IS_OK(nt_status
)) {
3196 code
= KRB5KRB_ERR_GENERIC
;
3197 } else if (authn_kerberos_client_policy_is_enforced(client_policy
)) {
3198 code
= KRB5KDC_ERR_POLICY
;
3200 if (status_out
!= NULL
) {
3201 *status_out
= out_status
;
3211 frame
= talloc_stackframe();
3213 code
= samba_kdc_get_user_info_dc(frame
,
3224 * The device claims become the *user* claims for the purpose of
3225 * evaluating a conditional ACE expression.
3227 code
= samba_kdc_get_claims_data(frame
,
3231 &auth_claims
.user_claims
);
3236 nt_status
= authn_policy_authenticate_from_device(frame
,
3242 &client_audit_info
);
3243 if (client_audit_info
!= NULL
) {
3244 *client_audit_info_out
= talloc_move(mem_ctx
, &client_audit_info
);
3246 if (!NT_STATUS_IS_OK(nt_status
)) {
3247 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
3248 code
= KRB5KDC_ERR_POLICY
;
3250 code
= KRB5KRB_ERR_GENERIC
;