2 Unix SMB/CIFS implementation.
3 Samba Active Directory claims utility functions
5 Copyright (C) Catalyst.Net Ltd 2023
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "lib/replace/replace.h"
22 #include "lib/util/debug.h"
23 #include "lib/util/samba_util.h"
24 #include "source4/kdc/ad_claims.h"
25 #include "source4/kdc/authn_policy_util.h"
26 #include "ldb_module.h"
27 #include "libcli/security/security.h"
28 #include "libcli/util/werror.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/samdb/ldb_modules/util.h"
31 #include "librpc/gen_ndr/claims.h"
32 #include "librpc/gen_ndr/ndr_claims.h"
33 #include "librpc/gen_ndr/krb5pac.h"
34 #include "librpc/gen_ndr/ndr_krb5pac.h"
35 #include "lzxpress_huffman.h"
36 #include "lib/util/binsearch.h"
40 bool ad_claims_are_issued(struct ldb_context
*samdb
)
43 * Claims aren’t issued by Samba unless the DC is at
44 * FL2012. This is to match Windows, which will offer
45 * this feature as soon as the DC is upgraded.
47 const int functional_level
= dsdb_dc_functional_level(samdb
);
48 return functional_level
>= DS_DOMAIN_FUNCTION_2012
;
51 static int acl_attr_cmp_fn(const char *a
, const char * const *b
)
53 return ldb_attr_cmp(a
, *b
);
57 * Add a single attribute to a list of attributes if it is not already
58 * present. The list is maintained in case-insensitive sorted order.
60 static int add_attr_unique(TALLOC_CTX
*mem_ctx
,
62 unsigned *ad_claim_attrs_count
,
65 const unsigned count
= *ad_claim_attrs_count
;
66 const char * const *exact
= NULL
;
67 const char * const *next
= NULL
;
69 BINARY_ARRAY_SEARCH_GTE(attrs
,
76 /* The attribute is already present; there's nothing to do. */
80 /* Make sure we don't overflow the array. */
81 SMB_ASSERT(count
< talloc_array_length(attrs
));
82 *ad_claim_attrs_count
= count
+ 1;
85 /* Just add the new element on the end. */
88 /* Shift all following elements over to make room. */
89 size_t next_idx
= next
- attrs
;
90 size_t bytes_to_move
= (count
- next_idx
) * sizeof (attrs
[0]);
91 memmove(&attrs
[next_idx
+ 1],
95 attrs
[next_idx
] = attr
;
102 * Return true if a data_blob, interpreted as a string, is equal to another
103 * string. This is more efficient than strcmp(), particularly when comparing
104 * against a string constant. This assumes the data_blob's length does not
105 * include the zero-terminator.
107 static inline bool data_blob_equals_str(const DATA_BLOB val
, const char *str
)
109 size_t len
= strlen(str
);
110 if (val
.length
!= len
) {
114 return memcmp(val
.data
, str
, len
) == 0;
117 static int fill_claim_int64(TALLOC_CTX
*mem_ctx
,
118 struct ldb_context
*ldb
,
119 const struct ldb_message_element
*principal_attribute
,
120 const struct ldb_val name
,
121 struct CLAIM_INT64
*claim
)
125 claim
->value_count
= 0;
126 claim
->values
= talloc_array(mem_ctx
,
128 principal_attribute
->num_values
);
129 if (claim
->values
== NULL
) {
133 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
134 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
135 int ret
= ldb_val_as_int64(value
, &claim
->values
[i
]);
138 const char *reason
= NULL
;
139 int err
= strerror_r(ret
, buf
, sizeof(buf
));
143 reason
= "Unknown error";
145 DBG_WARNING("Failed to interpret value %s as INT64 "
146 "while creating claim %s for attribute %s (%s); "
148 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
149 name
.data
, principal_attribute
->name
,
154 ++claim
->value_count
;
157 /* Shrink the array to fit. */
158 claim
->values
= talloc_realloc(mem_ctx
,
162 if (claim
->value_count
&& claim
->values
== NULL
) {
169 static int fill_claim_uint64(TALLOC_CTX
*mem_ctx
,
170 struct ldb_context
*ldb
,
171 const struct ldb_message_element
*principal_attribute
,
172 const struct ldb_val name
,
173 struct CLAIM_UINT64
*claim
)
177 claim
->value_count
= 0;
178 claim
->values
= talloc_array(mem_ctx
,
180 principal_attribute
->num_values
);
181 if (claim
->values
== NULL
) {
185 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
186 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
187 int ret
= ldb_val_as_uint64(value
, &claim
->values
[i
]);
190 const char *reason
= NULL
;
191 int err
= strerror_r(ret
, buf
, sizeof(buf
));
195 reason
= "Unknown error";
197 DBG_WARNING("Failed to interpret value %s as UINT64 "
198 "while creating claim %s for attribute %s (%s); "
200 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
201 name
.data
, principal_attribute
->name
,
206 ++claim
->value_count
;
209 /* Shrink the array to fit. */
210 claim
->values
= talloc_realloc(mem_ctx
,
214 if (claim
->value_count
&& claim
->values
== NULL
) {
221 static int fill_claim_uint64_oid_syntax(TALLOC_CTX
*mem_ctx
,
222 struct ldb_context
*ldb
,
223 const struct dsdb_schema
*schema
,
224 const struct ldb_message_element
*principal_attribute
,
225 const struct ldb_val name
,
226 struct CLAIM_UINT64
*claim
)
230 claim
->value_count
= 0;
231 claim
->values
= talloc_array(mem_ctx
,
233 principal_attribute
->num_values
);
234 if (claim
->values
== NULL
) {
238 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
239 const struct dsdb_class
*class_val
= NULL
;
242 * OID values for objectClass
243 * are presented in reverse
246 const struct ldb_val
*display_name
= &principal_attribute
->values
[
247 principal_attribute
->num_values
- 1 - i
];
249 class_val
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, display_name
);
250 if (class_val
== NULL
) {
251 DBG_WARNING("Failed to look up OID for value %s "
252 "while creating claim %s for attribute %s; "
254 (display_name
->data
!= NULL
) ? (const char *)display_name
->data
: "<unknown>",
255 name
.data
, principal_attribute
->name
);
259 claim
->values
[i
] = class_val
->governsID_id
;
260 ++claim
->value_count
;
263 /* Shrink the array to fit. */
264 claim
->values
= talloc_realloc(mem_ctx
,
268 if (claim
->value_count
&& claim
->values
== NULL
) {
275 static int fill_claim_boolean(TALLOC_CTX
*mem_ctx
,
276 struct ldb_context
*ldb
,
277 const struct ldb_message_element
*principal_attribute
,
278 const struct ldb_val name
,
279 struct CLAIM_UINT64
*claim
)
283 claim
->value_count
= 0;
284 claim
->values
= talloc_array(mem_ctx
,
286 principal_attribute
->num_values
);
287 if (claim
->values
== NULL
) {
291 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
292 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
294 int ret
= ldb_val_as_bool(value
, &val
);
297 const char *reason
= NULL
;
298 int err
= strerror_r(ret
, buf
, sizeof(buf
));
302 reason
= "Unknown error";
304 DBG_WARNING("Failed to interpret value %s as BOOL "
305 "while creating claim %s for attribute %s (%s); "
307 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
308 name
.data
, principal_attribute
->name
,
313 claim
->values
[i
] = val
;
314 ++claim
->value_count
;
317 /* Shrink the array to fit. */
318 claim
->values
= talloc_realloc(mem_ctx
,
322 if (claim
->value_count
&& claim
->values
== NULL
) {
329 static int fill_claim_string(TALLOC_CTX
*mem_ctx
,
330 struct ldb_context
*ldb
,
331 const struct ldb_message_element
*principal_attribute
,
332 struct CLAIM_STRING
*claim
)
336 claim
->value_count
= 0;
337 claim
->values
= talloc_array(mem_ctx
,
339 principal_attribute
->num_values
);
340 if (claim
->values
== NULL
) {
344 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
345 const char *val
= NULL
;
346 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
348 if (v
== NULL
|| v
->data
== NULL
) {
352 val
= talloc_strndup(claim
->values
,
353 (const char *)v
->data
,
359 claim
->values
[i
] = val
;
360 ++claim
->value_count
;
363 /* Shrink the array to fit. */
364 claim
->values
= talloc_realloc(mem_ctx
,
368 if (claim
->value_count
&& claim
->values
== NULL
) {
375 static int fill_claim_string_sec_desc_syntax(TALLOC_CTX
*mem_ctx
,
376 struct ldb_context
*ldb
,
377 const struct ldb_message_element
*principal_attribute
,
378 struct CLAIM_STRING
*claim
)
380 TALLOC_CTX
*tmp_ctx
= NULL
;
381 const struct dom_sid
*domain_sid
= NULL
;
384 claim
->value_count
= 0;
385 claim
->values
= talloc_array(mem_ctx
,
387 principal_attribute
->num_values
);
388 if (claim
->values
== NULL
) {
392 domain_sid
= samdb_domain_sid(ldb
);
393 if (domain_sid
== NULL
) {
397 tmp_ctx
= talloc_new(mem_ctx
);
398 if (tmp_ctx
== NULL
) {
402 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
403 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
405 enum ndr_err_code ndr_err
;
406 struct security_descriptor desc
= {};
407 const char *sddl
= NULL
;
409 if (v
== NULL
|| v
->data
== NULL
) {
413 ndr_err
= ndr_pull_struct_blob(v
,
416 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
417 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
418 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
419 DBG_ERR("security_descriptor pull failed: %s\n",
420 nt_errstr(nt_status
));
421 talloc_free(tmp_ctx
);
422 return ldb_operr(ldb
);
425 sddl
= sddl_encode(mem_ctx
,
429 talloc_free(tmp_ctx
);
433 claim
->values
[i
] = sddl
;
434 ++claim
->value_count
;
437 talloc_free(tmp_ctx
);
439 /* Shrink the array to fit. */
440 claim
->values
= talloc_realloc(mem_ctx
,
444 if (claim
->value_count
&& claim
->values
== NULL
) {
451 static int fill_claim_entry(TALLOC_CTX
*mem_ctx
,
452 struct ldb_context
*ldb
,
453 const struct dsdb_schema
*schema
,
454 const struct ldb_message_element
*principal_attribute
,
455 const struct ldb_val name
,
456 const DATA_BLOB syntax
,
457 enum CLAIM_TYPE claim_type
,
458 struct CLAIM_ENTRY
*claim_entry
)
461 claim_entry
->id
= (const char *)name
.data
;
462 claim_entry
->type
= claim_type
;
464 switch (claim_type
) {
465 case CLAIM_TYPE_INT64
:
466 return fill_claim_int64(mem_ctx
,
470 &claim_entry
->values
.claim_int64
);
471 case CLAIM_TYPE_UINT64
:
472 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.2")) {
473 return fill_claim_uint64_oid_syntax(mem_ctx
,
478 &claim_entry
->values
.claim_uint64
);
480 return fill_claim_uint64(mem_ctx
,
484 &claim_entry
->values
.claim_uint64
);
486 case CLAIM_TYPE_BOOLEAN
:
487 return fill_claim_boolean(mem_ctx
,
491 &claim_entry
->values
.claim_boolean
);
492 case CLAIM_TYPE_STRING
:
494 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.15")) {
495 return fill_claim_string_sec_desc_syntax(mem_ctx
,
498 &claim_entry
->values
.claim_string
);
500 return fill_claim_string(mem_ctx
,
503 &claim_entry
->values
.claim_string
);
509 * Determine wheter a claim applies to the most specific objectClass of the
512 static int claim_applies_to_class(TALLOC_CTX
*mem_ctx
,
513 struct ldb_context
*ldb
,
514 const struct dsdb_schema
*schema
,
515 const struct ldb_message
*claim_msg
,
516 const uint32_t principal_class_id
,
519 struct ldb_message_element
*applies_to_class
= NULL
;
522 applies_to_class
= ldb_msg_find_element(claim_msg
,
523 "msDS-ClaimTypeAppliesToClass");
524 if (applies_to_class
== NULL
) {
529 for (i
= 0; i
< applies_to_class
->num_values
; ++i
) {
530 struct ldb_dn
*class_dn
= NULL
;
531 const struct dsdb_class
*class_val
= NULL
;
532 const struct ldb_val
*class_rdn
= NULL
;
534 class_dn
= ldb_dn_from_ldb_val(mem_ctx
,
536 &applies_to_class
->values
[i
]);
537 if (class_dn
== NULL
) {
541 class_rdn
= ldb_dn_get_rdn_val(class_dn
);
542 if (class_rdn
== NULL
) {
543 TALLOC_FREE(class_dn
);
547 class_val
= dsdb_class_by_cn_ldb_val(schema
, class_rdn
);
548 TALLOC_FREE(class_dn
);
549 if (class_val
== NULL
) {
553 if (class_val
->governsID_id
== principal_class_id
) {
563 struct assigned_silo
{
569 static struct assigned_silo
new_assigned_silo(void)
571 return (struct assigned_silo
) {
573 .is_initialised
= false,
574 .is_assigned
= false,
578 static bool silo_is_maybe_assigned(struct assigned_silo silo
)
580 return !silo
.is_initialised
|| silo
.is_assigned
;
583 static int get_assigned_silo(struct ldb_context
*ldb
,
585 const struct ldb_message
*principal
,
586 struct assigned_silo
*assigned_silo
)
588 TALLOC_CTX
*tmp_ctx
= NULL
;
591 const struct ldb_message
*silo_msg
= NULL
;
592 static const char * const silo_attrs
[] = {
593 "msDS-AuthNPolicySiloEnforced",
594 "msDS-AuthNPolicySiloMembers",
599 bool is_silo_enforced
= false;
600 const char *silo_name
= NULL
;
602 if (assigned_silo
->is_initialised
) {
606 tmp_ctx
= talloc_new(mem_ctx
);
607 if (tmp_ctx
== NULL
) {
611 if (!authn_policy_silos_and_policies_in_effect(ldb
)) {
612 /* No assigned silo. */
613 assigned_silo
->is_assigned
= false;
614 assigned_silo
->is_initialised
= true;
616 talloc_free(tmp_ctx
);
620 /* Check whether the user is assigned to an enforced silo. */
621 ret
= authn_policy_get_assigned_silo(ldb
,
628 talloc_free(tmp_ctx
);
632 if (silo_msg
== NULL
|| !is_silo_enforced
) {
633 /* No assigned silo. */
634 assigned_silo
->is_assigned
= false;
635 assigned_silo
->is_initialised
= true;
637 talloc_free(tmp_ctx
);
641 /* The user does belong to a silo, so return the name of the silo. */
642 silo_name
= ldb_msg_find_attr_as_string(silo_msg
,
645 assigned_silo
->name
= talloc_steal(mem_ctx
, silo_name
);
646 assigned_silo
->is_assigned
= true;
647 assigned_silo
->is_initialised
= true;
649 talloc_free(tmp_ctx
);
653 static inline struct ldb_val
talloc_steal_ldb_val(TALLOC_CTX
*mem_ctx
, struct ldb_val val
)
655 val
.data
= talloc_steal(mem_ctx
, val
.data
);
659 static uint32_t claim_get_value_count(const struct CLAIM_ENTRY
*claim
)
661 switch (claim
->type
) {
662 case CLAIM_TYPE_INT64
:
663 return claim
->values
.claim_int64
.value_count
;
664 case CLAIM_TYPE_UINT64
:
665 return claim
->values
.claim_uint64
.value_count
;
666 case CLAIM_TYPE_STRING
:
667 return claim
->values
.claim_string
.value_count
;
668 case CLAIM_TYPE_BOOLEAN
:
669 return claim
->values
.claim_boolean
.value_count
;
672 smb_panic(__location__
": unknown claim type");
676 static int encode_claims_set(struct ldb_context
*ldb
,
678 struct CLAIMS_SET
*claims_set
,
679 DATA_BLOB
*claims_blob
)
681 TALLOC_CTX
*tmp_ctx
= NULL
;
682 enum ndr_err_code ndr_err
;
683 struct CLAIMS_SET_NDR
*claims_set_info
= NULL
;
684 struct CLAIMS_SET_METADATA
*metadata
= NULL
;
685 struct CLAIMS_SET_METADATA_NDR
*metadata_ndr
= NULL
;
687 tmp_ctx
= talloc_new(mem_ctx
);
688 if (tmp_ctx
== NULL
) {
692 metadata_ndr
= talloc_zero(tmp_ctx
, struct CLAIMS_SET_METADATA_NDR
);
693 if (metadata_ndr
== NULL
) {
694 talloc_free(tmp_ctx
);
698 metadata
= talloc_zero(metadata_ndr
, struct CLAIMS_SET_METADATA
);
699 if (metadata
== NULL
) {
700 talloc_free(tmp_ctx
);
704 claims_set_info
= talloc_zero(metadata
, struct CLAIMS_SET_NDR
);
705 if (claims_set_info
== NULL
) {
706 talloc_free(tmp_ctx
);
710 metadata_ndr
->claims
.metadata
= metadata
;
712 metadata
->claims_set
= claims_set_info
;
713 metadata
->compression_format
= CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF
;
715 claims_set_info
->claims
.claims
= claims_set
;
717 ndr_err
= ndr_push_struct_blob(claims_blob
, mem_ctx
, metadata_ndr
,
718 (ndr_push_flags_fn_t
)ndr_push_CLAIMS_SET_METADATA_NDR
);
719 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
720 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
721 DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
722 nt_errstr(nt_status
));
724 talloc_free(tmp_ctx
);
725 return ldb_operr(ldb
);
728 talloc_free(tmp_ctx
);
732 static bool is_schema_dn(struct ldb_dn
*dn
,
733 struct ldb_dn
*schema_dn
)
735 if (ldb_dn_get_comp_num(dn
) != (ldb_dn_get_comp_num(schema_dn
) + 1)) {
739 return ldb_dn_compare_base(schema_dn
, dn
) == 0;
742 static bool is_valid_claim_attribute_syntax(const DATA_BLOB source_syntax
,
743 uint64_t claim_value_type
)
745 switch (claim_value_type
) {
746 case CLAIM_TYPE_STRING
:
747 if (data_blob_equals_str(source_syntax
, "2.5.5.1")) {
750 if (data_blob_equals_str(source_syntax
, "2.5.5.12")) {
753 if (data_blob_equals_str(source_syntax
, "2.5.5.15")) {
757 case CLAIM_TYPE_UINT64
:
758 if (data_blob_equals_str(source_syntax
, "2.5.5.2")) {
762 case CLAIM_TYPE_INT64
:
763 if (data_blob_equals_str(source_syntax
, "2.5.5.9")) {
766 if (data_blob_equals_str(source_syntax
, "2.5.5.16")) {
770 case CLAIM_TYPE_BOOLEAN
:
771 /* Note: MS-ADTS has a typo (2.2.5.8 instead of 2.5.5.8) */
772 if (data_blob_equals_str(source_syntax
, "2.5.5.8")) {
783 static int get_all_claims(struct ldb_context
*ldb
,
785 const struct ldb_message
*principal
,
786 uint32_t principal_class_id
,
787 DATA_BLOB
*claims_blob
)
789 TALLOC_CTX
*tmp_ctx
= NULL
;
791 const struct dsdb_schema
*schema
= NULL
;
793 struct ldb_dn
*claim_config_container
= NULL
;
794 struct ldb_dn
*claim_types_child
= NULL
;
795 struct ldb_dn
*config_dn
= ldb_get_config_basedn(ldb
);
796 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(ldb
);
799 struct ldb_result
*res
= NULL
;
800 static const char * const attrs
[] = {
802 "msDS-ClaimAttributeSource",
804 "msDS-ClaimSourceType",
805 "msDS-ClaimTypeAppliesToClass",
806 "msDS-ClaimValueType",
811 const char **ad_claim_attrs
= NULL
;
812 unsigned int ad_claim_attrs_count
;
813 struct ad_claim_info
{
816 const char *attribute
;
817 enum CLAIM_TYPE claim_type
;
819 unsigned ad_claims_count
;
823 /* The structure which we'll use to build up the claims. */
824 struct CLAIMS_SET claims_set
= {};
826 struct CLAIMS_ARRAY
*ad_sourced_constructed
= NULL
;
828 struct assigned_silo assigned_silo
= new_assigned_silo();
830 *claims_blob
= data_blob_null
;
832 tmp_ctx
= talloc_new(mem_ctx
);
833 if (tmp_ctx
== NULL
) {
837 schema
= dsdb_get_schema(ldb
, tmp_ctx
);
838 if (schema
== NULL
) {
839 talloc_free(tmp_ctx
);
840 return ldb_operr(ldb
);
843 /* Get the DN of the claims container. */
844 claim_config_container
= ldb_dn_copy(tmp_ctx
, config_dn
);
845 if (claim_config_container
== NULL
) {
846 talloc_free(tmp_ctx
);
850 claim_types_child
= ldb_dn_new(tmp_ctx
, ldb
,
851 "CN=Claim Types,CN=Claims Configuration,CN=Services");
852 if (claim_types_child
== NULL
) {
853 talloc_free(tmp_ctx
);
857 ok
= ldb_dn_add_child(claim_config_container
, claim_types_child
);
858 TALLOC_FREE(claim_types_child
);
860 talloc_free(tmp_ctx
);
861 return ldb_operr(ldb
);
864 /* Search for the claims container's children. */
865 ret
= ldb_search(ldb
, tmp_ctx
, &res
,
866 claim_config_container
,
870 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
874 talloc_free(tmp_ctx
);
879 * Allocate enough space for all AD claim attributes, followed by space
880 * for a NULL marker (so it can be passed as the attributes filter to an
883 ad_claim_attrs
= talloc_array(tmp_ctx
,
886 if (ad_claim_attrs
== NULL
) {
887 talloc_free(tmp_ctx
);
890 ad_claims
= talloc_array(tmp_ctx
,
891 struct ad_claim_info
,
893 if (ad_claims
== NULL
) {
894 talloc_free(tmp_ctx
);
897 ad_claims_count
= ad_claim_attrs_count
= 0;
899 /* Loop through each child of the claims container. */
900 for (i
= 0; i
< res
->count
; ++i
) {
901 bool claim_applies
= false;
904 uint64_t claim_value_type
;
906 const char *claim_source_type
= NULL
;
907 const struct ldb_val
*claim_attribute_source
= NULL
;
908 const char *claim_source
= NULL
;
911 * Does this claim apply to the most specific objectClass of the
914 ret
= claim_applies_to_class(tmp_ctx
,
921 talloc_free(tmp_ctx
);
924 if (!claim_applies
) {
925 /* If the claim doesn't apply, skip it. */
929 enabled
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "Enabled", 0);
931 /* If the claim isn't enabled, skip it. */
935 claim_value_type
= ldb_msg_find_attr_as_uint64(res
->msgs
[i
],
936 "msDS-ClaimValueType",
938 if (!claim_value_type
) {
942 claim_source_type
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
943 "msDS-ClaimSourceType",
946 /* Get the attribute used by the claim. */
947 claim_attribute_source
= ldb_msg_find_ldb_val(res
->msgs
[i
],
948 "msDS-ClaimAttributeSource");
950 claim_source
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
954 if (strcasecmp(claim_source_type
, "AD") == 0) {
955 struct ldb_dn
*claim_attribute_source_dn
= NULL
;
956 const struct ldb_val
*claim_attribute_source_rdn
= NULL
;
957 const struct dsdb_attribute
*claim_attribute_source_class
= NULL
;
959 DATA_BLOB source_syntax
;
960 const char *attribute
= NULL
;
961 const struct ldb_val
*name
= NULL
;
963 if (claim_attribute_source
== NULL
) {
967 claim_attribute_source_dn
= ldb_val_as_dn(ldb
,
969 claim_attribute_source
);
970 if (claim_attribute_source_dn
== NULL
) {
971 talloc_free(tmp_ctx
);
972 return ldb_operr(ldb
);
975 if (!is_schema_dn(claim_attribute_source_dn
, schema_dn
)) {
976 /* This DN doesn't belong to the schema. */
980 claim_attribute_source_rdn
= ldb_dn_get_rdn_val(claim_attribute_source_dn
);
981 if (claim_attribute_source_rdn
== NULL
) {
982 /* No RDN, skip it. */
986 claim_attribute_source_class
= dsdb_attribute_by_cn_ldb_val(schema
,
987 claim_attribute_source_rdn
);
988 claim_attribute_source_rdn
= NULL
;
989 TALLOC_FREE(claim_attribute_source_dn
);
990 if (claim_attribute_source_class
== NULL
) {
994 source_syntax
= data_blob_string_const(claim_attribute_source_class
->attributeSyntax_oid
);
995 if (source_syntax
.data
== NULL
) {
999 if (!is_valid_claim_attribute_syntax(source_syntax
, claim_value_type
)) {
1003 attribute
= claim_attribute_source_class
->lDAPDisplayName
;
1004 if (attribute
== NULL
) {
1008 ret
= add_attr_unique(tmp_ctx
,
1010 &ad_claim_attrs_count
,
1013 talloc_free(tmp_ctx
);
1017 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
1019 name
= &data_blob_null
;
1022 ad_claims
[ad_claims_count
++] = (struct ad_claim_info
) {
1024 .syntax
= source_syntax
,
1025 .attribute
= attribute
,
1026 .claim_type
= claim_value_type
,
1028 } else if (silo_is_maybe_assigned(assigned_silo
)
1029 && strcasecmp(claim_source_type
, "Constructed") == 0)
1031 const struct ldb_val
*name
= NULL
;
1032 struct CLAIM_STRING
*claim
= NULL
;
1033 struct CLAIM_ENTRY
*claim_entry
= NULL
;
1034 const char *claim_value
= NULL
;
1036 if (claim_attribute_source
!= NULL
) {
1040 if (claim_source
!= NULL
) {
1044 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
1045 if (name
== NULL
|| name
->data
== NULL
) {
1048 /* Does the claim ID match exactly in case? */
1049 if (strcmp((const char *)name
->data
, "ad://ext/AuthenticationSilo") != 0) {
1053 ret
= get_assigned_silo(ldb
, tmp_ctx
, principal
, &assigned_silo
);
1055 talloc_free(tmp_ctx
);
1058 if (!assigned_silo
.is_assigned
) {
1062 if (ad_sourced_constructed
== NULL
) {
1063 claims_set
.claims_arrays
= talloc_realloc(tmp_ctx
,
1064 claims_set
.claims_arrays
,
1065 struct CLAIMS_ARRAY
,
1066 claims_set
.claims_array_count
+ 1);
1067 if (claims_set
.claims_arrays
== NULL
) {
1068 talloc_free(tmp_ctx
);
1069 return ldb_oom(ldb
);
1072 ad_sourced_constructed
= &claims_set
.claims_arrays
[claims_set
.claims_array_count
++];
1073 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1074 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1078 /* Add the claim to the array. */
1079 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1081 ad_sourced_constructed
->claim_entries
,
1083 ad_sourced_constructed
->claims_count
+ 1);
1084 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1085 talloc_free(tmp_ctx
);
1086 return ldb_oom(ldb
);
1089 claim_entry
= &ad_sourced_constructed
->claim_entries
[ad_sourced_constructed
->claims_count
++];
1091 /* Fill in the claim details and return the claim. */
1092 claim_entry
->id
= "ad://ext/AuthenticationSilo";
1093 claim_entry
->type
= CLAIM_TYPE_STRING
;
1095 claim
= &claim_entry
->values
.claim_string
;
1097 claim
->value_count
= 1;
1098 claim
->values
= talloc_array(ad_sourced_constructed
->claim_entries
,
1100 claim
->value_count
);
1101 if (claim
->values
== NULL
) {
1102 talloc_free(tmp_ctx
);
1103 return ldb_oom(ldb
);
1106 claim_value
= talloc_strdup(claim
->values
, assigned_silo
.name
);
1107 if (claim_value
== NULL
) {
1108 talloc_free(tmp_ctx
);
1109 return ldb_oom(ldb
);
1112 claim
->values
[0] = claim_value
;
1116 if (ad_claims_count
) {
1117 struct ldb_message
*principal_msg
= NULL
;
1119 /* Shrink the arrays to remove any unused space. */
1120 ad_claim_attrs
= talloc_realloc(tmp_ctx
,
1123 ad_claim_attrs_count
+ 1);
1124 if (ad_claim_attrs
== NULL
) {
1125 talloc_free(tmp_ctx
);
1126 return ldb_oom(ldb
);
1128 ad_claim_attrs
[ad_claim_attrs_count
] = NULL
;
1130 ad_claims
= talloc_realloc(tmp_ctx
,
1132 struct ad_claim_info
,
1134 if (ad_claims
== NULL
) {
1135 talloc_free(tmp_ctx
);
1136 return ldb_oom(ldb
);
1139 ret
= dsdb_search_one(ldb
,
1147 if (ret
!= LDB_SUCCESS
) {
1148 const char *dn
= ldb_dn_get_linearized(principal
->dn
);
1149 DBG_ERR("Failed to find principal %s to construct claims\n",
1150 dn
!= NULL
? dn
: "<NULL>");
1151 talloc_free(tmp_ctx
);
1156 * Ensure that only the attrs we asked for end up in the results
1157 * (it's fine if some are missing)
1159 SMB_ASSERT(principal_msg
->num_elements
<= ad_claim_attrs_count
);
1161 for (i
= 0; i
< ad_claims_count
; ++i
) {
1162 const struct ldb_message_element
*principal_attribute
= NULL
;
1163 struct CLAIM_ENTRY
*claim_entry
= NULL
;
1164 uint32_t new_claims_array_count
= claims_set
.claims_array_count
;
1166 /* Get the value of the claim attribute for the principal. */
1167 principal_attribute
= ldb_msg_find_element(principal_msg
,
1168 ad_claims
[i
].attribute
);
1169 if (principal_attribute
== NULL
) {
1173 /* Add the claim to the array. */
1175 if (ad_sourced_constructed
== NULL
) {
1176 claims_set
.claims_arrays
= talloc_realloc(tmp_ctx
,
1177 claims_set
.claims_arrays
,
1178 struct CLAIMS_ARRAY
,
1179 new_claims_array_count
+ 1);
1180 if (claims_set
.claims_arrays
== NULL
) {
1181 talloc_free(tmp_ctx
);
1182 return ldb_oom(ldb
);
1185 ad_sourced_constructed
= &claims_set
.claims_arrays
[new_claims_array_count
++];
1186 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1187 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1191 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1193 ad_sourced_constructed
->claim_entries
,
1195 ad_sourced_constructed
->claims_count
+ 1);
1196 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1197 talloc_free(tmp_ctx
);
1198 return ldb_oom(ldb
);
1201 claim_entry
= &ad_sourced_constructed
->claim_entries
[
1202 ad_sourced_constructed
->claims_count
];
1204 ret
= fill_claim_entry(ad_sourced_constructed
->claim_entries
,
1207 principal_attribute
,
1209 ad_claims
[i
].syntax
,
1210 ad_claims
[i
].claim_type
,
1212 if (ret
!= LDB_SUCCESS
) {
1213 talloc_free(tmp_ctx
);
1217 if (claim_get_value_count(claim_entry
) > 0) {
1219 * If the claim contains values, add it to the
1222 ++ad_sourced_constructed
->claims_count
;
1223 claims_set
.claims_array_count
= new_claims_array_count
;
1228 if (claims_set
.claims_array_count
== 0) {
1229 /* If we have no claims, we're done. */
1230 talloc_free(tmp_ctx
);
1234 /* Encode the claims ready to go into a PAC buffer. */
1235 ret
= encode_claims_set(ldb
, mem_ctx
, &claims_set
, claims_blob
);
1237 talloc_free(tmp_ctx
);
1241 int get_claims_for_principal(struct ldb_context
*ldb
,
1242 TALLOC_CTX
*mem_ctx
,
1243 const struct ldb_message
*principal
,
1244 DATA_BLOB
*claims_blob
)
1246 struct ldb_message_element
*principal_class_el
= NULL
;
1247 struct dsdb_schema
*schema
= NULL
;
1248 const struct dsdb_class
*principal_class
= NULL
;
1250 *claims_blob
= data_blob_null
;
1252 if (!ad_claims_are_issued(ldb
)) {
1256 principal_class_el
= ldb_msg_find_element(principal
,
1258 if (principal_class_el
== NULL
) {
1259 return ldb_operr(ldb
);
1262 schema
= dsdb_get_schema(ldb
, mem_ctx
);
1263 if (schema
== NULL
) {
1264 return ldb_operr(ldb
);
1267 principal_class
= dsdb_get_last_structural_class(schema
, principal_class_el
);
1268 if (principal_class
== NULL
) {
1269 return ldb_operr(ldb
);
1272 return get_all_claims(ldb
,
1275 principal_class
->governsID_id
,