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 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
1563 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
1564 kdc_entry
->realm_dn
, kdc_entry
->msg
,
1565 workstation
, client_name
,
1566 true, password_change
);
1568 kdc_entry
->reject_status
= nt_status
;
1569 talloc_free(tmp_ctx
);
1573 static krb5_error_code
samba_get_requester_sid(TALLOC_CTX
*mem_ctx
,
1575 krb5_context context
,
1576 struct dom_sid
*sid
)
1579 enum ndr_err_code ndr_err
;
1580 krb5_error_code ret
= 0;
1582 DATA_BLOB pac_requester_sid_in
;
1583 krb5_data k5pac_requester_sid_in
;
1585 union PAC_INFO info
;
1587 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1588 if (tmp_ctx
== NULL
) {
1593 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_REQUESTER_SID
,
1594 &k5pac_requester_sid_in
);
1599 pac_requester_sid_in
= data_blob_const(k5pac_requester_sid_in
.data
,
1600 k5pac_requester_sid_in
.length
);
1602 ndr_err
= ndr_pull_union_blob(&pac_requester_sid_in
, tmp_ctx
, &info
,
1603 PAC_TYPE_REQUESTER_SID
,
1604 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1605 smb_krb5_free_data_contents(context
, &k5pac_requester_sid_in
);
1606 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1607 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1608 DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status
));
1609 ret
= map_errno_from_nt_status(nt_status
);
1613 *sid
= info
.requester_sid
.sid
;
1616 talloc_free(tmp_ctx
);
1620 /* Does a parse and SID check, but no crypto. */
1621 static krb5_error_code
samba_kdc_validate_pac_blob(
1622 krb5_context context
,
1623 const struct samba_kdc_entry_pac client
)
1625 TALLOC_CTX
*frame
= talloc_stackframe();
1626 struct auth_user_info_dc
*pac_user_info
= NULL
;
1627 struct dom_sid client_sid
;
1628 struct dom_sid pac_sid
;
1629 krb5_error_code code
;
1633 * First, try to get the SID from the requester SID buffer in the PAC.
1635 code
= samba_get_requester_sid(frame
, client
.pac
, context
, &pac_sid
);
1637 if (code
== ENOENT
) {
1639 * If the requester SID buffer isn't present, fall back to the
1640 * SID in the LOGON_INFO PAC buffer.
1642 code
= kerberos_pac_to_user_info_dc(frame
,
1646 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1654 if (pac_user_info
->num_sids
== 0) {
1659 pac_sid
= pac_user_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1660 } else if (code
!= 0) {
1664 code
= samdb_result_dom_sid_buf(client
.entry
->msg
,
1671 ok
= dom_sid_equal(&pac_sid
, &client_sid
);
1673 struct dom_sid_buf buf1
;
1674 struct dom_sid_buf buf2
;
1676 DBG_ERR("SID mismatch between PAC and looked up client: "
1677 "PAC[%s] != CLI[%s]\n",
1678 dom_sid_str_buf(&pac_sid
, &buf1
),
1679 dom_sid_str_buf(&client_sid
, &buf2
));
1680 code
= KRB5KDC_ERR_TGT_REVOKED
;
1692 * In the RODC case, to confirm that the returned user is permitted to
1693 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1695 static WERROR
samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids
,
1696 const struct dom_sid
*object_sids
,
1697 const struct samba_kdc_entry
*rodc
,
1698 const struct samba_kdc_entry
*object
)
1702 TALLOC_CTX
*frame
= talloc_stackframe();
1703 const char *rodc_attrs
[] = { "msDS-KrbTgtLink",
1704 "msDS-NeverRevealGroup",
1705 "msDS-RevealOnDemandGroup",
1706 "userAccountControl",
1709 struct ldb_result
*rodc_machine_account
= NULL
;
1710 struct ldb_dn
*rodc_machine_account_dn
= samdb_result_dn(rodc
->kdc_db_ctx
->samdb
,
1713 "msDS-KrbTgtLinkBL",
1715 const struct dom_sid
*rodc_machine_account_sid
= NULL
;
1717 if (rodc_machine_account_dn
== NULL
) {
1718 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1719 ldb_dn_get_linearized(rodc
->msg
->dn
));
1721 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1725 * Follow the link and get the RODC account (the krbtgt
1726 * account is the krbtgt_XXX account, but the
1727 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1728 * the RODC$ account)
1730 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1731 * out of the extended DNs
1734 ret
= dsdb_search_dn(rodc
->kdc_db_ctx
->samdb
,
1736 &rodc_machine_account
,
1737 rodc_machine_account_dn
,
1739 DSDB_SEARCH_SHOW_EXTENDED_DN
);
1740 if (ret
!= LDB_SUCCESS
) {
1741 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1742 ldb_dn_get_linearized(rodc_machine_account_dn
),
1743 ldb_dn_get_linearized(rodc
->msg
->dn
),
1744 ldb_errstring(rodc
->kdc_db_ctx
->samdb
));
1746 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1749 if (rodc_machine_account
->count
!= 1) {
1750 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1751 ldb_dn_get_linearized(rodc_machine_account_dn
),
1752 ldb_dn_get_linearized(rodc
->msg
->dn
),
1753 rodc_machine_account
->count
);
1755 return WERR_DS_DRA_BAD_DN
;
1758 /* if the object SID is equal to the user_sid, allow */
1759 rodc_machine_account_sid
= samdb_result_dom_sid(frame
,
1760 rodc_machine_account
->msgs
[0],
1762 if (rodc_machine_account_sid
== NULL
) {
1764 return WERR_DS_DRA_BAD_DN
;
1767 werr
= samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc
->kdc_db_ctx
->samdb
,
1768 rodc_machine_account_sid
,
1769 rodc_machine_account
->msgs
[0],
1779 * Perform an access check for the client attempting to authenticate to the
1780 * server. ‘client_info’ must be talloc-allocated so that we can make a
1783 krb5_error_code
samba_kdc_allowed_to_authenticate_to(TALLOC_CTX
*mem_ctx
,
1784 struct ldb_context
*samdb
,
1785 struct loadparm_context
*lp_ctx
,
1786 const struct samba_kdc_entry
*client
,
1787 const struct auth_user_info_dc
*client_info
,
1788 const struct auth_user_info_dc
*device_info
,
1789 const struct auth_claims auth_claims
,
1790 const struct samba_kdc_entry
*server
,
1791 struct authn_audit_info
**server_audit_info_out
,
1792 NTSTATUS
*status_out
)
1794 krb5_error_code ret
= 0;
1796 _UNUSED_ NTSTATUS _status
;
1797 struct dom_sid server_sid
= {};
1798 const struct authn_server_policy
*server_policy
= server
->server_policy
;
1800 if (status_out
!= NULL
) {
1801 *status_out
= NT_STATUS_OK
;
1804 ret
= samdb_result_dom_sid_buf(server
->msg
, "objectSid", &server_sid
);
1807 * Ignore the return status — we are already in an error path,
1808 * and overwriting the real error code with the audit info
1809 * status is unhelpful.
1811 _status
= authn_server_policy_audit_info(mem_ctx
,
1814 AUTHN_AUDIT_EVENT_OTHER_ERROR
,
1815 AUTHN_AUDIT_REASON_NONE
,
1816 dsdb_ldb_err_to_ntstatus(ret
),
1817 server_audit_info_out
);
1821 if (dom_sid_equal(&client_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
, &server_sid
)) {
1822 /* Authenticating to ourselves is always allowed. */
1823 status
= authn_server_policy_audit_info(mem_ctx
,
1826 AUTHN_AUDIT_EVENT_OK
,
1827 AUTHN_AUDIT_REASON_NONE
,
1829 server_audit_info_out
);
1830 if (!NT_STATUS_IS_OK(status
)) {
1831 ret
= KRB5KRB_ERR_GENERIC
;
1836 status
= authn_policy_authenticate_to_service(mem_ctx
,
1839 AUTHN_POLICY_AUTH_TYPE_KERBEROS
,
1844 (struct authn_policy_flags
) { .force_compounded_authentication
= true },
1845 server_audit_info_out
);
1846 if (!NT_STATUS_IS_OK(status
)) {
1847 if (status_out
!= NULL
) {
1848 *status_out
= status
;
1850 if (NT_STATUS_EQUAL(status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
1851 ret
= KRB5KDC_ERR_POLICY
;
1852 } else if (NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
1853 ret
= KRB5KDC_ERR_POLICY
;
1855 ret
= KRB5KRB_ERR_GENERIC
;
1863 static krb5_error_code
samba_kdc_add_domain_group_sid(struct PAC_DEVICE_INFO
*info
,
1864 const struct netr_SidAttr
*sid
)
1870 uint32_t domain_group_count
= info
->domain_group_count
;
1871 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_group
= NULL
;
1872 struct samr_RidWithAttribute
*rids
= NULL
;
1874 for (i
= 0; i
< domain_group_count
; ++i
) {
1875 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*this_domain_group
1876 = &info
->domain_groups
[i
];
1878 if (dom_sid_in_domain(this_domain_group
->domain_sid
, sid
->sid
)) {
1879 domain_group
= this_domain_group
;
1884 if (domain_group
== NULL
) {
1885 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*domain_groups
= NULL
;
1887 if (domain_group_count
== UINT32_MAX
) {
1891 domain_groups
= talloc_realloc(
1893 info
->domain_groups
,
1894 struct PAC_DOMAIN_GROUP_MEMBERSHIP
,
1895 domain_group_count
+ 1);
1896 if (domain_groups
== NULL
) {
1900 info
->domain_groups
= domain_groups
;
1902 domain_group
= &info
->domain_groups
[domain_group_count
++];
1903 *domain_group
= (struct PAC_DOMAIN_GROUP_MEMBERSHIP
) {};
1905 status
= dom_sid_split_rid(info
->domain_groups
,
1907 &domain_group
->domain_sid
,
1909 if (!NT_STATUS_IS_OK(status
)) {
1910 return map_errno_from_nt_status(status
);
1913 status
= dom_sid_split_rid(NULL
,
1917 if (!NT_STATUS_IS_OK(status
)) {
1918 return map_errno_from_nt_status(status
);
1922 if (domain_group
->groups
.count
== UINT32_MAX
) {
1926 rids
= talloc_realloc(info
->domain_groups
,
1927 domain_group
->groups
.rids
,
1928 struct samr_RidWithAttribute
,
1929 domain_group
->groups
.count
+ 1);
1934 domain_group
->groups
.rids
= rids
;
1936 domain_group
->groups
.rids
[domain_group
->groups
.count
] = (struct samr_RidWithAttribute
) {
1938 .attributes
= sid
->attributes
,
1941 ++domain_group
->groups
.count
;
1943 info
->domain_group_count
= domain_group_count
;
1948 static krb5_error_code
samba_kdc_make_device_info(TALLOC_CTX
*mem_ctx
,
1949 const struct netr_SamInfo3
*info3
,
1950 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
,
1951 union PAC_INFO
*info
)
1953 TALLOC_CTX
*tmp_ctx
= NULL
;
1954 struct PAC_DEVICE_INFO
*device_info
= NULL
;
1956 krb5_error_code ret
= 0;
1958 *info
= (union PAC_INFO
) {};
1960 info
->device_info
.info
= NULL
;
1962 tmp_ctx
= talloc_new(mem_ctx
);
1963 if (tmp_ctx
== NULL
) {
1967 device_info
= talloc(tmp_ctx
, struct PAC_DEVICE_INFO
);
1968 if (device_info
== NULL
) {
1973 device_info
->rid
= info3
->base
.rid
;
1974 device_info
->primary_gid
= info3
->base
.primary_gid
;
1975 device_info
->domain_sid
= info3
->base
.domain_sid
;
1976 device_info
->groups
= info3
->base
.groups
;
1978 device_info
->sid_count
= 0;
1979 device_info
->sids
= NULL
;
1981 if (resource_groups
!= NULL
) {
1983 * The account's resource groups all belong to the same domain,
1984 * so we can add them all in one go.
1986 device_info
->domain_group_count
= 1;
1987 device_info
->domain_groups
= talloc_move(device_info
, &resource_groups
);
1989 device_info
->domain_group_count
= 0;
1990 device_info
->domain_groups
= NULL
;
1993 for (i
= 0; i
< info3
->sidcount
; ++i
) {
1994 const struct netr_SidAttr
*device_sid
= &info3
->sids
[i
];
1996 if (dom_sid_has_account_domain(device_sid
->sid
)) {
1997 ret
= samba_kdc_add_domain_group_sid(device_info
, device_sid
);
2002 device_info
->sids
= talloc_realloc(device_info
, device_info
->sids
,
2003 struct netr_SidAttr
,
2004 device_info
->sid_count
+ 1);
2005 if (device_info
->sids
== NULL
) {
2010 device_info
->sids
[device_info
->sid_count
].sid
= dom_sid_dup(device_info
->sids
, device_sid
->sid
);
2011 if (device_info
->sids
[device_info
->sid_count
].sid
== NULL
) {
2016 device_info
->sids
[device_info
->sid_count
].attributes
= device_sid
->attributes
;
2018 ++device_info
->sid_count
;
2022 info
->device_info
.info
= talloc_steal(mem_ctx
, device_info
);
2025 talloc_free(tmp_ctx
);
2029 static krb5_error_code
samba_kdc_update_device_info(TALLOC_CTX
*mem_ctx
,
2030 struct ldb_context
*samdb
,
2031 const union PAC_INFO
*logon_info
,
2032 struct PAC_DEVICE_INFO
*device_info
)
2035 struct auth_user_info_dc
*device_info_dc
= NULL
;
2036 union netr_Validation validation
;
2038 uint32_t num_existing_sids
;
2041 * This does a bit of unnecessary work, setting up fields we don't care
2042 * about -- we only want the SIDs.
2044 validation
.sam3
= &logon_info
->logon_info
.info
->info3
;
2045 nt_status
= make_user_info_dc_netlogon_validation(mem_ctx
, "", 3, &validation
,
2046 true, /* This user was authenticated */
2048 if (!NT_STATUS_IS_OK(nt_status
)) {
2049 return map_errno_from_nt_status(nt_status
);
2052 num_existing_sids
= device_info_dc
->num_sids
;
2055 * We need to expand group memberships within our local domain,
2056 * as the token might be generated by a trusted domain.
2058 nt_status
= authsam_update_user_info_dc(mem_ctx
,
2061 if (!NT_STATUS_IS_OK(nt_status
)) {
2062 return map_errno_from_nt_status(nt_status
);
2065 for (i
= num_existing_sids
; i
< device_info_dc
->num_sids
; ++i
) {
2066 struct auth_SidAttr
*device_sid
= &device_info_dc
->sids
[i
];
2067 const struct netr_SidAttr sid
= (struct netr_SidAttr
) {
2068 .sid
= &device_sid
->sid
,
2069 .attributes
= device_sid
->attrs
,
2072 krb5_error_code ret
= samba_kdc_add_domain_group_sid(device_info
, &sid
);
2081 static krb5_error_code
samba_kdc_get_device_info_pac_blob(TALLOC_CTX
*mem_ctx
,
2082 union PAC_INFO
*info
,
2083 DATA_BLOB
**_device_info_blob
)
2085 DATA_BLOB
*device_info_blob
= NULL
;
2086 enum ndr_err_code ndr_err
;
2088 *_device_info_blob
= NULL
;
2090 device_info_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
2091 if (device_info_blob
== NULL
) {
2092 DBG_ERR("Out of memory\n");
2096 ndr_err
= ndr_push_union_blob(device_info_blob
, device_info_blob
,
2097 info
, PAC_TYPE_DEVICE_INFO
,
2098 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
2099 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2100 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
2101 DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
2102 nt_errstr(nt_status
));
2103 talloc_free(device_info_blob
);
2104 return map_errno_from_nt_status(nt_status
);
2107 *_device_info_blob
= device_info_blob
;
2112 static krb5_error_code
samba_kdc_create_device_info_blob(TALLOC_CTX
*mem_ctx
,
2113 krb5_context context
,
2114 struct ldb_context
*samdb
,
2115 const krb5_const_pac device_pac
,
2116 DATA_BLOB
**device_info_blob
)
2118 TALLOC_CTX
*frame
= NULL
;
2119 krb5_data device_logon_info
;
2120 krb5_error_code code
= EINVAL
;
2123 union PAC_INFO info
;
2124 enum ndr_err_code ndr_err
;
2125 DATA_BLOB device_logon_info_blob
;
2127 union PAC_INFO logon_info
;
2129 code
= krb5_pac_get_buffer(context
, device_pac
,
2130 PAC_TYPE_LOGON_INFO
,
2131 &device_logon_info
);
2133 if (code
== ENOENT
) {
2134 DBG_ERR("Device PAC is missing LOGON_INFO\n");
2136 DBG_ERR("Error getting LOGON_INFO from device PAC\n");
2141 frame
= talloc_stackframe();
2143 device_logon_info_blob
= data_blob_const(device_logon_info
.data
,
2144 device_logon_info
.length
);
2146 ndr_err
= ndr_pull_union_blob(&device_logon_info_blob
, frame
, &logon_info
,
2147 PAC_TYPE_LOGON_INFO
,
2148 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
2149 smb_krb5_free_data_contents(context
, &device_logon_info
);
2150 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2151 nt_status
= ndr_map_error2ntstatus(ndr_err
);
2152 DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
2153 nt_errstr(nt_status
));
2155 return map_errno_from_nt_status(nt_status
);
2159 * When creating the device info structure, existing resource groups are
2162 code
= samba_kdc_make_device_info(frame
,
2163 &logon_info
.logon_info
.info
->info3
,
2164 NULL
, /* resource_groups */
2171 code
= samba_kdc_update_device_info(frame
,
2174 info
.device_info
.info
);
2180 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2188 static krb5_error_code
samba_kdc_get_device_info_blob(TALLOC_CTX
*mem_ctx
,
2189 krb5_context context
,
2190 struct ldb_context
*samdb
,
2191 const struct samba_kdc_entry_pac device
,
2192 DATA_BLOB
**device_info_blob
)
2194 TALLOC_CTX
*frame
= NULL
;
2195 krb5_error_code code
= EINVAL
;
2198 const struct auth_user_info_dc
*device_info
= NULL
;
2199 struct netr_SamInfo3
*info3
= NULL
;
2200 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*resource_groups
= NULL
;
2202 union PAC_INFO info
;
2204 frame
= talloc_stackframe();
2206 code
= samba_kdc_get_user_info_dc(frame
,
2211 NULL
/* resource_groups_out */);
2213 const char *krb5_err
= krb5_get_error_message(context
, code
);
2214 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2215 krb5_err
!= NULL
? krb5_err
: "<unknown>");
2216 krb5_free_error_message(context
, krb5_err
);
2219 return KRB5KDC_ERR_TGT_REVOKED
;
2222 nt_status
= auth_convert_user_info_dc_saminfo3(frame
, device_info
,
2223 AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
,
2226 if (!NT_STATUS_IS_OK(nt_status
)) {
2227 DBG_WARNING("Getting Samba info failed: %s\n",
2228 nt_errstr(nt_status
));
2230 return nt_status_to_krb5(nt_status
);
2233 code
= samba_kdc_make_device_info(frame
,
2242 code
= samba_kdc_get_device_info_pac_blob(mem_ctx
,
2251 * @brief Verify a PAC
2253 * @param mem_ctx A talloc memory context
2255 * @param context A krb5 context
2257 * @param samdb An open samdb connection.
2259 * @param flags Bitwise OR'ed flags
2261 * @param client The client samba kdc PAC entry.
2263 * @param krbtgt The krbtgt samba kdc entry.
2265 * @return A Kerberos error code.
2267 krb5_error_code
samba_kdc_verify_pac(TALLOC_CTX
*mem_ctx
,
2268 krb5_context context
,
2269 struct ldb_context
*samdb
,
2271 const struct samba_kdc_entry_pac client
,
2272 const struct samba_kdc_entry
*krbtgt
)
2274 TALLOC_CTX
*tmp_ctx
= NULL
;
2275 struct pac_blobs
*pac_blobs
= NULL
;
2276 krb5_error_code code
= EINVAL
;
2278 tmp_ctx
= talloc_new(mem_ctx
);
2279 if (tmp_ctx
== NULL
) {
2284 if (client
.entry
!= NULL
) {
2286 * Check the objectSID of the client and pac data are the same.
2287 * Does a parse and SID check, but no crypto.
2289 code
= samba_kdc_validate_pac_blob(context
, client
);
2295 if (!samba_krb5_pac_is_trusted(client
)) {
2296 const struct auth_user_info_dc
*user_info_dc
= NULL
;
2299 struct dom_sid
*object_sids
= NULL
;
2302 if (client
.entry
== NULL
) {
2303 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2307 code
= samba_kdc_get_user_info_from_db(tmp_ctx
,
2313 const char *krb5_err
= krb5_get_error_message(context
, code
);
2314 DBG_ERR("Getting user info for PAC failed: %s\n",
2315 krb5_err
!= NULL
? krb5_err
: "<unknown>");
2316 krb5_free_error_message(context
, krb5_err
);
2318 code
= KRB5KDC_ERR_TGT_REVOKED
;
2323 * Check if the SID list in the user_info_dc intersects
2324 * correctly with the RODC allow/deny lists.
2326 object_sids
= talloc_array(tmp_ctx
, struct dom_sid
, user_info_dc
->num_sids
);
2327 if (object_sids
== NULL
) {
2332 for (j
= 0; j
< user_info_dc
->num_sids
; ++j
) {
2333 object_sids
[j
] = user_info_dc
->sids
[j
].sid
;
2336 werr
= samba_rodc_confirm_user_is_allowed(user_info_dc
->num_sids
,
2340 if (!W_ERROR_IS_OK(werr
)) {
2341 code
= KRB5KDC_ERR_TGT_REVOKED
;
2342 if (W_ERROR_EQUAL(werr
,
2343 WERR_DOMAIN_CONTROLLER_NOT_FOUND
)) {
2344 code
= KRB5KDC_ERR_POLICY
;
2350 * The RODC PAC data isn't trusted for authorization as it may
2351 * be stale. The only thing meaningful we can do with an RODC
2352 * account on a full DC is exchange the RODC TGT for a 'real'
2355 * So we match Windows (at least server 2022) and
2356 * don't allow S4U2Self.
2358 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
2360 if (flags
& SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
) {
2361 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
2366 /* Check the types of the given PAC */
2368 code
= pac_blobs_from_krb5_pac(tmp_ctx
,
2376 code
= pac_blobs_ensure_exists(pac_blobs
,
2377 PAC_TYPE_LOGON_INFO
);
2382 code
= pac_blobs_ensure_exists(pac_blobs
,
2383 PAC_TYPE_LOGON_NAME
);
2388 code
= pac_blobs_ensure_exists(pac_blobs
,
2389 PAC_TYPE_SRV_CHECKSUM
);
2394 code
= pac_blobs_ensure_exists(pac_blobs
,
2395 PAC_TYPE_KDC_CHECKSUM
);
2400 if (!(flags
& SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
)) {
2401 code
= pac_blobs_ensure_exists(pac_blobs
,
2402 PAC_TYPE_REQUESTER_SID
);
2404 code
= KRB5KDC_ERR_TGT_REVOKED
;
2412 talloc_free(tmp_ctx
);
2418 * @brief Update a PAC
2420 * @param mem_ctx A talloc memory context
2422 * @param context A krb5 context
2424 * @param samdb An open samdb connection.
2426 * @param lp_ctx A loadparm context.
2428 * @param flags Bitwise OR'ed flags
2430 * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
2431 * as opposed to an RODC.
2433 * @param client The client samba kdc PAC entry.
2435 * @param server_principal The server principal
2437 * @param server The server samba kdc entry.
2439 * @param delegated_proxy_principal The delegated proxy principal used for
2440 * updating the constrained delegation PAC
2443 * @param delegated_proxy The delegated proxy kdc PAC entry.
2445 * @param device The computer's samba kdc PAC entry; used for compound
2448 * @param new_pac The new already allocated PAC
2450 * @return A Kerberos error code. If no PAC should be returned, the code will be
2453 krb5_error_code
samba_kdc_update_pac(TALLOC_CTX
*mem_ctx
,
2454 krb5_context context
,
2455 struct ldb_context
*samdb
,
2456 struct loadparm_context
*lp_ctx
,
2458 const struct samba_kdc_entry_pac client
,
2459 const krb5_const_principal server_principal
,
2460 const struct samba_kdc_entry
*server
,
2461 const krb5_const_principal delegated_proxy_principal
,
2462 const struct samba_kdc_entry_pac delegated_proxy
,
2463 const struct samba_kdc_entry_pac device
,
2465 struct authn_audit_info
**server_audit_info_out
,
2466 NTSTATUS
*status_out
)
2468 TALLOC_CTX
*tmp_ctx
= NULL
;
2469 krb5_error_code code
= EINVAL
;
2471 DATA_BLOB
*pac_blob
= NULL
;
2472 DATA_BLOB
*upn_blob
= NULL
;
2473 DATA_BLOB
*deleg_blob
= NULL
;
2474 DATA_BLOB
*requester_sid_blob
= NULL
;
2475 const DATA_BLOB
*client_claims_blob
= NULL
;
2476 DATA_BLOB device_claims_blob
= {};
2477 const DATA_BLOB
*device_claims_blob_ptr
= NULL
;
2478 struct auth_claims auth_claims
= {};
2479 DATA_BLOB
*device_info_blob
= NULL
;
2480 bool is_tgs
= false;
2481 bool server_restrictions_present
= false;
2482 struct pac_blobs
*pac_blobs
= NULL
;
2483 const struct auth_user_info_dc
*user_info_dc_const
= NULL
;
2484 struct auth_user_info_dc
*user_info_dc_shallow_copy
= NULL
;
2485 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
2486 enum auth_group_inclusion group_inclusion
;
2487 bool compounded_auth
;
2490 if (server_audit_info_out
!= NULL
) {
2491 *server_audit_info_out
= NULL
;
2494 if (status_out
!= NULL
) {
2495 *status_out
= NT_STATUS_OK
;
2498 tmp_ctx
= talloc_new(mem_ctx
);
2499 if (tmp_ctx
== NULL
) {
2505 int result
= smb_krb5_principal_is_tgs(context
, server_principal
);
2514 server_restrictions_present
= !is_tgs
&& authn_policy_restrictions_present(server
->server_policy
);
2516 /* Only include resource groups in a service ticket. */
2518 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
2519 } else if (server
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
2520 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
2522 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
2525 compounded_auth
= device
.entry
!= NULL
&& !is_tgs
2526 && server
->supported_enctypes
& KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED
;
2528 if (compounded_auth
|| (server_restrictions_present
&& device
.entry
!= NULL
)) {
2530 * [MS-KILE] 3.3.5.7.4 Compound Identity: the client claims from
2531 * the device PAC become the device claims in the new PAC.
2533 code
= samba_kdc_get_claims_data(tmp_ctx
,
2537 &auth_claims
.device_claims
);
2542 if (compounded_auth
) {
2543 nt_status
= claims_data_encoded_claims_set(tmp_ctx
,
2544 auth_claims
.device_claims
,
2545 &device_claims_blob
);
2546 if (!NT_STATUS_IS_OK(nt_status
)) {
2547 DBG_ERR("claims_data_encoded_claims_set failed: %s\n",
2548 nt_errstr(nt_status
));
2549 code
= map_errno_from_nt_status(nt_status
);
2553 device_claims_blob_ptr
= &device_claims_blob
;
2555 if (samba_krb5_pac_is_trusted(device
)) {
2556 code
= samba_kdc_create_device_info_blob(tmp_ctx
,
2565 /* Don't trust an RODC‐issued PAC; regenerate the device info. */
2566 code
= samba_kdc_get_device_info_blob(tmp_ctx
,
2578 if (delegated_proxy_principal
!= NULL
) {
2579 deleg_blob
= talloc_zero(tmp_ctx
, DATA_BLOB
);
2580 if (deleg_blob
== NULL
) {
2585 nt_status
= samba_kdc_update_delegation_info_blob(
2590 delegated_proxy_principal
,
2592 if (!NT_STATUS_IS_OK(nt_status
)) {
2593 DBG_ERR("update delegation info blob failed: %s\n",
2594 nt_errstr(nt_status
));
2595 code
= map_errno_from_nt_status(nt_status
);
2601 * If we are creating a TGT, resource groups from our domain are not to
2602 * be put into the PAC. Instead, we take the resource groups directly
2603 * from the original PAC and copy them unmodified into the new one.
2605 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2609 &user_info_dc_const
,
2610 is_tgs
? &_resource_groups
: NULL
);
2612 const char *err_str
= krb5_get_error_message(context
, code
);
2613 DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2614 err_str
!= NULL
? err_str
: "<unknown>");
2615 krb5_free_error_message(context
, err_str
);
2621 * Enforce the AllowedToAuthenticateTo part of an authentication policy,
2622 * if one is present.
2624 if (server_restrictions_present
) {
2625 struct samba_kdc_entry_pac auth_entry
;
2626 const struct auth_user_info_dc
*auth_user_info_dc
= NULL
;
2627 const struct auth_user_info_dc
*device_info
= NULL
;
2629 if (delegated_proxy
.entry
!= NULL
) {
2630 auth_entry
= delegated_proxy
;
2632 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2637 NULL
/* resource_groups_out */);
2642 auth_entry
= client
;
2643 auth_user_info_dc
= user_info_dc_const
;
2646 /* Fetch the user’s claims. */
2647 code
= samba_kdc_get_claims_data(tmp_ctx
,
2651 &auth_claims
.user_claims
);
2656 if (device
.entry
!= NULL
) {
2657 code
= samba_kdc_get_user_info_dc(tmp_ctx
,
2662 NULL
/* resource_groups_out */);
2669 * Allocate the audit info and output status on to the parent
2670 * mem_ctx, not the temporary context.
2672 code
= samba_kdc_allowed_to_authenticate_to(mem_ctx
,
2680 server_audit_info_out
,
2687 if (compounded_auth
) {
2688 /* Make a shallow copy of the user_info_dc structure. */
2689 nt_status
= authsam_shallow_copy_user_info_dc(tmp_ctx
,
2691 &user_info_dc_shallow_copy
);
2692 user_info_dc_const
= NULL
;
2694 if (!NT_STATUS_IS_OK(nt_status
)) {
2695 DBG_ERR("Failed to copy user_info_dc: %s\n",
2696 nt_errstr(nt_status
));
2698 code
= KRB5KDC_ERR_TGT_REVOKED
;
2702 nt_status
= samba_kdc_add_compounded_auth(user_info_dc_shallow_copy
);
2703 if (!NT_STATUS_IS_OK(nt_status
)) {
2704 DBG_ERR("Failed to add Compounded Authentication: %s\n",
2705 nt_errstr(nt_status
));
2707 code
= KRB5KDC_ERR_TGT_REVOKED
;
2711 /* We can now set back to the const, it will not be modified */
2712 user_info_dc_const
= user_info_dc_shallow_copy
;
2715 if (samba_krb5_pac_is_trusted(client
)) {
2716 pac_blob
= talloc_zero(tmp_ctx
, DATA_BLOB
);
2717 if (pac_blob
== NULL
) {
2722 nt_status
= samba_get_logon_info_pac_blob(tmp_ctx
,
2727 if (!NT_STATUS_IS_OK(nt_status
)) {
2728 DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
2729 nt_errstr(nt_status
));
2731 code
= map_errno_from_nt_status(nt_status
);
2736 * TODO: we need claim translation over trusts,
2737 * for now we just clear them...
2739 if (samba_kdc_entry_pac_issued_by_trust(client
)) {
2740 client_claims_blob
= &data_blob_null
;
2743 nt_status
= samba_kdc_get_logon_info_blob(tmp_ctx
,
2747 if (!NT_STATUS_IS_OK(nt_status
)) {
2748 DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
2749 nt_errstr(nt_status
));
2750 code
= KRB5KDC_ERR_TGT_REVOKED
;
2754 nt_status
= samba_kdc_get_upn_info_blob(tmp_ctx
,
2757 if (!NT_STATUS_IS_OK(nt_status
)) {
2758 DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
2759 nt_errstr(nt_status
));
2760 code
= KRB5KDC_ERR_TGT_REVOKED
;
2765 nt_status
= samba_kdc_get_requester_sid_blob(tmp_ctx
,
2767 &requester_sid_blob
);
2768 if (!NT_STATUS_IS_OK(nt_status
)) {
2769 DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
2770 nt_errstr(nt_status
));
2771 code
= KRB5KDC_ERR_TGT_REVOKED
;
2776 /* Don't trust RODC-issued claims. Regenerate them. */
2777 nt_status
= samba_kdc_get_claims_blob(tmp_ctx
,
2779 &client_claims_blob
);
2780 if (!NT_STATUS_IS_OK(nt_status
)) {
2781 DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2782 nt_errstr(nt_status
));
2783 code
= map_errno_from_nt_status(nt_status
);
2788 /* Check the types of the given PAC */
2789 code
= pac_blobs_from_krb5_pac(tmp_ctx
,
2797 code
= pac_blobs_replace_existing(pac_blobs
,
2798 PAC_TYPE_LOGON_INFO
,
2804 #ifdef SAMBA4_USES_HEIMDAL
2805 /* Not needed with MIT Kerberos */
2806 code
= pac_blobs_replace_existing(pac_blobs
,
2807 PAC_TYPE_LOGON_NAME
,
2813 code
= pac_blobs_replace_existing(pac_blobs
,
2814 PAC_TYPE_SRV_CHECKSUM
,
2820 code
= pac_blobs_replace_existing(pac_blobs
,
2821 PAC_TYPE_KDC_CHECKSUM
,
2828 code
= pac_blobs_add_blob(pac_blobs
,
2829 PAC_TYPE_CONSTRAINED_DELEGATION
,
2835 code
= pac_blobs_add_blob(pac_blobs
,
2836 PAC_TYPE_UPN_DNS_INFO
,
2842 code
= pac_blobs_add_blob(pac_blobs
,
2843 PAC_TYPE_CLIENT_CLAIMS_INFO
,
2844 client_claims_blob
);
2849 code
= pac_blobs_add_blob(pac_blobs
,
2850 PAC_TYPE_DEVICE_INFO
,
2856 code
= pac_blobs_add_blob(pac_blobs
,
2857 PAC_TYPE_DEVICE_CLAIMS_INFO
,
2858 device_claims_blob_ptr
);
2863 if (!samba_krb5_pac_is_trusted(client
) || !is_tgs
) {
2864 pac_blobs_remove_blob(pac_blobs
,
2865 PAC_TYPE_ATTRIBUTES_INFO
);
2869 pac_blobs_remove_blob(pac_blobs
,
2870 PAC_TYPE_REQUESTER_SID
);
2873 code
= pac_blobs_add_blob(pac_blobs
,
2874 PAC_TYPE_REQUESTER_SID
,
2875 requester_sid_blob
);
2881 * The server account may be set not to want the PAC.
2883 * While this is wasteful if the above calculations were done
2884 * and now thrown away, this is cleaner as we do any ticket
2885 * signature checking etc always.
2887 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
2888 * time (eg not accepting a ticket from the RODC) we do not
2889 * need to re-generate anything anyway.
2891 if (!samba_princ_needs_pac(server
)) {
2896 if (samba_krb5_pac_is_trusted(client
) && !is_tgs
) {
2898 * The client may have requested no PAC when obtaining the
2901 bool requested_pac
= false;
2903 code
= samba_client_requested_pac(context
,
2907 if (code
!= 0 || !requested_pac
) {
2908 if (!requested_pac
) {
2915 for (i
= 0; i
< pac_blobs
->num_types
; ++i
) {
2916 krb5_data type_data
;
2917 const DATA_BLOB
*type_blob
= pac_blobs
->type_blobs
[i
].data
;
2918 uint32_t type
= pac_blobs
->type_blobs
[i
].type
;
2920 static char null_byte
= '\0';
2921 const krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
2923 #ifndef SAMBA4_USES_HEIMDAL
2924 /* Not needed with MIT Kerberos */
2926 case PAC_TYPE_LOGON_NAME
:
2927 case PAC_TYPE_SRV_CHECKSUM
:
2928 case PAC_TYPE_KDC_CHECKSUM
:
2929 case PAC_TYPE_FULL_CHECKSUM
:
2936 if (type_blob
!= NULL
) {
2937 type_data
= smb_krb5_data_from_blob(*type_blob
);
2939 * Passing a NULL pointer into krb5_pac_add_buffer() is
2940 * not allowed, so pass null_data instead if needed.
2942 code
= krb5_pac_add_buffer(context
,
2945 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2949 } else if (samba_krb5_pac_is_trusted(client
)) {
2951 * Convey the buffer from the original PAC if we can
2955 code
= krb5_pac_get_buffer(context
,
2963 * Passing a NULL pointer into krb5_pac_add_buffer() is
2964 * not allowed, so pass null_data instead if needed.
2966 code
= krb5_pac_add_buffer(context
,
2969 (type_data
.data
!= NULL
) ? &type_data
: &null_data
);
2970 smb_krb5_free_data_contents(context
, &type_data
);
2979 TALLOC_FREE(tmp_ctx
);
2983 krb5_error_code
samba_kdc_get_claims_data(TALLOC_CTX
*mem_ctx
,
2984 krb5_context context
,
2985 struct ldb_context
*samdb
,
2986 struct samba_kdc_entry_pac entry
,
2987 struct claims_data
**claims_data_out
)
2989 if (samba_kdc_entry_pac_issued_by_trust(entry
)) {
2993 * TODO: we need claim translation over trusts; for now we just
2996 status
= claims_data_from_encoded_claims_set(mem_ctx
,
2999 if (!NT_STATUS_IS_OK(status
)) {
3000 return map_errno_from_nt_status(status
);
3006 if (samba_krb5_pac_is_trusted(entry
)) {
3007 return samba_kdc_get_claims_data_from_pac(mem_ctx
,
3013 return samba_kdc_get_claims_data_from_db(samdb
,
3018 krb5_error_code
samba_kdc_get_claims_data_from_pac(TALLOC_CTX
*mem_ctx
,
3019 krb5_context context
,
3020 struct samba_kdc_entry_pac entry
,
3021 struct claims_data
**claims_data_out
)
3023 TALLOC_CTX
*frame
= NULL
;
3024 krb5_data claims_info
= {};
3025 struct claims_data
*claims_data
= NULL
;
3026 NTSTATUS status
= NT_STATUS_OK
;
3027 krb5_error_code code
;
3029 if (!samba_krb5_pac_is_trusted(entry
)) {
3034 if (samba_kdc_entry_pac_issued_by_trust(entry
)) {
3039 if (claims_data_out
== NULL
) {
3044 *claims_data_out
= NULL
;
3046 if (entry
.entry
!= NULL
&& entry
.entry
->claims_from_pac_are_initialized
) {
3047 /* Note: the caller does not own this! */
3048 *claims_data_out
= entry
.entry
->claims_from_pac
;
3052 frame
= talloc_stackframe();
3054 /* Fetch the claims from the PAC. */
3055 code
= krb5_pac_get_buffer(context
, entry
.pac
,
3056 PAC_TYPE_CLIENT_CLAIMS_INFO
,
3058 if (code
== ENOENT
) {
3060 } else if (code
!= 0) {
3061 DBG_ERR("Error getting CLIENT_CLAIMS_INFO from PAC\n");
3063 } else if (claims_info
.length
) {
3064 DATA_BLOB claims_blob
= data_blob_const(claims_info
.data
,
3065 claims_info
.length
);
3067 status
= claims_data_from_encoded_claims_set(frame
,
3070 if (!NT_STATUS_IS_OK(status
)) {
3071 code
= map_errno_from_nt_status(status
);
3076 if (entry
.entry
!= NULL
) {
3077 /* Note: the caller does not own this! */
3078 entry
.entry
->claims_from_pac
= talloc_steal(entry
.entry
,
3080 entry
.entry
->claims_from_pac_are_initialized
= true;
3082 talloc_steal(mem_ctx
, claims_data
);
3085 *claims_data_out
= claims_data
;
3088 smb_krb5_free_data_contents(context
, &claims_info
);
3093 krb5_error_code
samba_kdc_get_claims_data_from_db(struct ldb_context
*samdb
,
3094 struct samba_kdc_entry
*entry
,
3095 struct claims_data
**claims_data_out
)
3097 TALLOC_CTX
*frame
= NULL
;
3099 struct claims_data
*claims_data
= NULL
;
3100 struct CLAIMS_SET
*claims_set
= NULL
;
3101 NTSTATUS status
= NT_STATUS_OK
;
3102 krb5_error_code code
;
3104 if (samdb
== NULL
) {
3109 if (claims_data_out
== NULL
) {
3114 if (entry
== NULL
) {
3115 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
3119 *claims_data_out
= NULL
;
3121 if (entry
->claims_from_db_are_initialized
) {
3122 /* Note: the caller does not own this! */
3123 *claims_data_out
= entry
->claims_from_db
;
3127 frame
= talloc_stackframe();
3129 code
= get_claims_set_for_principal(samdb
,
3134 DBG_ERR("Failed to fetch claims\n");
3138 if (claims_set
!= NULL
) {
3139 status
= claims_data_from_claims_set(claims_data
,
3142 if (!NT_STATUS_IS_OK(status
)) {
3143 code
= map_errno_from_nt_status(status
);
3148 entry
->claims_from_db
= talloc_steal(entry
,
3150 entry
->claims_from_db_are_initialized
= true;
3152 /* Note: the caller does not own this! */
3153 *claims_data_out
= entry
->claims_from_db
;
3160 krb5_error_code
samba_kdc_check_device(TALLOC_CTX
*mem_ctx
,
3161 krb5_context context
,
3162 struct ldb_context
*samdb
,
3163 struct loadparm_context
*lp_ctx
,
3164 const struct samba_kdc_entry_pac device
,
3165 const struct authn_kerberos_client_policy
*client_policy
,
3166 struct authn_audit_info
**client_audit_info_out
,
3167 NTSTATUS
*status_out
)
3169 TALLOC_CTX
*frame
= NULL
;
3170 krb5_error_code code
= 0;
3172 const struct auth_user_info_dc
*device_info
= NULL
;
3173 struct authn_audit_info
*client_audit_info
= NULL
;
3174 struct auth_claims auth_claims
= {};
3176 if (status_out
!= NULL
) {
3177 *status_out
= NT_STATUS_OK
;
3180 if (!authn_policy_device_restrictions_present(client_policy
)) {
3184 if (device
.entry
== NULL
|| device
.pac
== NULL
) {
3185 NTSTATUS out_status
= NT_STATUS_INVALID_WORKSTATION
;
3187 nt_status
= authn_kerberos_client_policy_audit_info(mem_ctx
,
3189 NULL
/* client_info */,
3190 AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION
,
3191 AUTHN_AUDIT_REASON_FAST_REQUIRED
,
3193 client_audit_info_out
);
3194 if (!NT_STATUS_IS_OK(nt_status
)) {
3195 code
= KRB5KRB_ERR_GENERIC
;
3196 } else if (authn_kerberos_client_policy_is_enforced(client_policy
)) {
3197 code
= KRB5KDC_ERR_POLICY
;
3199 if (status_out
!= NULL
) {
3200 *status_out
= out_status
;
3210 frame
= talloc_stackframe();
3212 code
= samba_kdc_get_user_info_dc(frame
,
3223 * The device claims become the *user* claims for the purpose of
3224 * evaluating a conditional ACE expression.
3226 code
= samba_kdc_get_claims_data(frame
,
3230 &auth_claims
.user_claims
);
3235 nt_status
= authn_policy_authenticate_from_device(frame
,
3241 &client_audit_info
);
3242 if (client_audit_info
!= NULL
) {
3243 *client_audit_info_out
= talloc_move(mem_ctx
, &client_audit_info
);
3245 if (!NT_STATUS_IS_OK(nt_status
)) {
3246 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED
)) {
3247 code
= KRB5KDC_ERR_POLICY
;
3249 code
= KRB5KRB_ERR_GENERIC
;