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 "dsdb/samdb/samdb.h"
28 #include "dsdb/samdb/ldb_modules/util.h"
29 #include "librpc/gen_ndr/claims.h"
30 #include "librpc/gen_ndr/ndr_claims.h"
31 #include "librpc/gen_ndr/ndr_krb5pac.h"
32 #include "lib/util/binsearch.h"
33 #include "auth/session.h"
34 #include "libcli/security/sddl.h"
38 bool ad_claims_are_issued(struct ldb_context
*samdb
)
41 * Claims aren’t issued by Samba unless the DC is at
42 * FL2012. This is to match Windows, which will offer
43 * this feature as soon as the DC is upgraded.
45 const int functional_level
= dsdb_dc_functional_level(samdb
);
46 return functional_level
>= DS_DOMAIN_FUNCTION_2012
;
49 static int acl_attr_cmp_fn(const char *a
, const char * const *b
)
51 return ldb_attr_cmp(a
, *b
);
55 * Add a single attribute to a list of attributes if it is not already
56 * present. The list is maintained in case-insensitive sorted order.
58 static int add_attr_unique(TALLOC_CTX
*mem_ctx
,
60 unsigned *ad_claim_attrs_count
,
63 const unsigned count
= *ad_claim_attrs_count
;
64 const char * const *exact
= NULL
;
65 const char * const *next
= NULL
;
67 BINARY_ARRAY_SEARCH_GTE(attrs
,
74 /* The attribute is already present; there's nothing to do. */
78 /* Make sure we don't overflow the array. */
79 SMB_ASSERT(count
< talloc_array_length(attrs
));
80 *ad_claim_attrs_count
= count
+ 1;
83 /* Just add the new element on the end. */
86 /* Shift all following elements over to make room. */
87 size_t next_idx
= next
- attrs
;
88 size_t bytes_to_move
= (count
- next_idx
) * sizeof (attrs
[0]);
89 memmove(&attrs
[next_idx
+ 1],
93 attrs
[next_idx
] = attr
;
100 * Return true if a data_blob, interpreted as a string, is equal to another
101 * string. This is more efficient than strcmp(), particularly when comparing
102 * against a string constant. This assumes the data_blob's length does not
103 * include the zero-terminator.
105 static inline bool data_blob_equals_str(const DATA_BLOB val
, const char *str
)
107 size_t len
= strlen(str
);
108 if (val
.length
!= len
) {
112 return memcmp(val
.data
, str
, len
) == 0;
115 static int fill_claim_int64(TALLOC_CTX
*mem_ctx
,
116 struct ldb_context
*ldb
,
117 const struct ldb_message_element
*principal_attribute
,
118 const struct ldb_val name
,
119 struct CLAIM_INT64
*claim
)
123 claim
->value_count
= 0;
124 claim
->values
= talloc_array(mem_ctx
,
126 principal_attribute
->num_values
);
127 if (claim
->values
== NULL
) {
131 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
132 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
133 int ret
= ldb_val_as_int64(value
, &claim
->values
[i
]);
136 const char *reason
= NULL
;
137 int err
= strerror_r(ret
, buf
, sizeof(buf
));
141 reason
= "Unknown error";
143 DBG_WARNING("Failed to interpret value %s as INT64 "
144 "while creating claim %s for attribute %s (%s); "
146 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
147 name
.data
, principal_attribute
->name
,
152 ++claim
->value_count
;
155 /* Shrink the array to fit. */
156 claim
->values
= talloc_realloc(mem_ctx
,
160 if (claim
->value_count
&& claim
->values
== NULL
) {
167 static int fill_claim_uint64(TALLOC_CTX
*mem_ctx
,
168 struct ldb_context
*ldb
,
169 const struct ldb_message_element
*principal_attribute
,
170 const struct ldb_val name
,
171 struct CLAIM_UINT64
*claim
)
175 claim
->value_count
= 0;
176 claim
->values
= talloc_array(mem_ctx
,
178 principal_attribute
->num_values
);
179 if (claim
->values
== NULL
) {
183 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
184 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
185 int ret
= ldb_val_as_uint64(value
, &claim
->values
[i
]);
188 const char *reason
= NULL
;
189 int err
= strerror_r(ret
, buf
, sizeof(buf
));
193 reason
= "Unknown error";
195 DBG_WARNING("Failed to interpret value %s as UINT64 "
196 "while creating claim %s for attribute %s (%s); "
198 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
199 name
.data
, principal_attribute
->name
,
204 ++claim
->value_count
;
207 /* Shrink the array to fit. */
208 claim
->values
= talloc_realloc(mem_ctx
,
212 if (claim
->value_count
&& claim
->values
== NULL
) {
219 static int fill_claim_uint64_oid_syntax(TALLOC_CTX
*mem_ctx
,
220 struct ldb_context
*ldb
,
221 const struct dsdb_schema
*schema
,
222 const struct ldb_message_element
*principal_attribute
,
223 const struct ldb_val name
,
224 struct CLAIM_UINT64
*claim
)
228 claim
->value_count
= 0;
229 claim
->values
= talloc_array(mem_ctx
,
231 principal_attribute
->num_values
);
232 if (claim
->values
== NULL
) {
236 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
237 const struct dsdb_class
*class_val
= NULL
;
240 * OID values for objectClass
241 * are presented in reverse
244 const struct ldb_val
*display_name
= &principal_attribute
->values
[
245 principal_attribute
->num_values
- 1 - i
];
247 class_val
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, display_name
);
248 if (class_val
== NULL
) {
249 DBG_WARNING("Failed to look up OID for value %s "
250 "while creating claim %s for attribute %s; "
252 (display_name
->data
!= NULL
) ? (const char *)display_name
->data
: "<unknown>",
253 name
.data
, principal_attribute
->name
);
257 claim
->values
[i
] = class_val
->governsID_id
;
258 ++claim
->value_count
;
261 /* Shrink the array to fit. */
262 claim
->values
= talloc_realloc(mem_ctx
,
266 if (claim
->value_count
&& claim
->values
== NULL
) {
273 static int fill_claim_boolean(TALLOC_CTX
*mem_ctx
,
274 struct ldb_context
*ldb
,
275 const struct ldb_message_element
*principal_attribute
,
276 const struct ldb_val name
,
277 struct CLAIM_UINT64
*claim
)
281 claim
->value_count
= 0;
282 claim
->values
= talloc_array(mem_ctx
,
284 principal_attribute
->num_values
);
285 if (claim
->values
== NULL
) {
289 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
290 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
292 int ret
= ldb_val_as_bool(value
, &val
);
295 const char *reason
= NULL
;
296 int err
= strerror_r(ret
, buf
, sizeof(buf
));
300 reason
= "Unknown error";
302 DBG_WARNING("Failed to interpret value %s as BOOL "
303 "while creating claim %s for attribute %s (%s); "
305 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
306 name
.data
, principal_attribute
->name
,
311 claim
->values
[i
] = val
;
312 ++claim
->value_count
;
315 /* Shrink the array to fit. */
316 claim
->values
= talloc_realloc(mem_ctx
,
320 if (claim
->value_count
&& claim
->values
== NULL
) {
327 static int fill_claim_string(TALLOC_CTX
*mem_ctx
,
328 struct ldb_context
*ldb
,
329 const struct ldb_message_element
*principal_attribute
,
330 struct CLAIM_STRING
*claim
)
334 claim
->value_count
= 0;
335 claim
->values
= talloc_array(mem_ctx
,
337 principal_attribute
->num_values
);
338 if (claim
->values
== NULL
) {
342 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
343 const char *val
= NULL
;
344 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
346 if (v
== NULL
|| v
->data
== NULL
) {
350 val
= talloc_strndup(claim
->values
,
351 (const char *)v
->data
,
357 claim
->values
[i
] = val
;
358 ++claim
->value_count
;
361 /* Shrink the array to fit. */
362 claim
->values
= talloc_realloc(mem_ctx
,
366 if (claim
->value_count
&& claim
->values
== NULL
) {
373 static int fill_claim_string_sec_desc_syntax(TALLOC_CTX
*mem_ctx
,
374 struct ldb_context
*ldb
,
375 const struct ldb_message_element
*principal_attribute
,
376 struct CLAIM_STRING
*claim
)
378 TALLOC_CTX
*tmp_ctx
= NULL
;
379 const struct dom_sid
*domain_sid
= NULL
;
382 claim
->value_count
= 0;
383 claim
->values
= talloc_array(mem_ctx
,
385 principal_attribute
->num_values
);
386 if (claim
->values
== NULL
) {
390 domain_sid
= samdb_domain_sid(ldb
);
391 if (domain_sid
== NULL
) {
395 tmp_ctx
= talloc_new(mem_ctx
);
396 if (tmp_ctx
== NULL
) {
400 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
401 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
403 enum ndr_err_code ndr_err
;
404 struct security_descriptor desc
= {};
405 const char *sddl
= NULL
;
407 if (v
== NULL
|| v
->data
== NULL
) {
411 ndr_err
= ndr_pull_struct_blob(v
,
414 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
415 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
416 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
417 DBG_ERR("security_descriptor pull failed: %s\n",
418 nt_errstr(nt_status
));
419 talloc_free(tmp_ctx
);
420 return ldb_operr(ldb
);
423 sddl
= sddl_encode(mem_ctx
,
427 talloc_free(tmp_ctx
);
431 claim
->values
[i
] = sddl
;
432 ++claim
->value_count
;
435 talloc_free(tmp_ctx
);
437 /* Shrink the array to fit. */
438 claim
->values
= talloc_realloc(mem_ctx
,
442 if (claim
->value_count
&& claim
->values
== NULL
) {
449 static int fill_claim_entry(TALLOC_CTX
*mem_ctx
,
450 struct ldb_context
*ldb
,
451 const struct dsdb_schema
*schema
,
452 const struct ldb_message_element
*principal_attribute
,
453 const struct ldb_val name
,
454 const DATA_BLOB syntax
,
455 enum CLAIM_TYPE claim_type
,
456 struct CLAIM_ENTRY
*claim_entry
)
459 claim_entry
->id
= talloc_strndup(mem_ctx
,
460 (const char *)name
.data
,
462 if (claim_entry
->id
== NULL
) {
466 claim_entry
->type
= claim_type
;
468 switch (claim_type
) {
469 case CLAIM_TYPE_INT64
:
470 return fill_claim_int64(mem_ctx
,
474 &claim_entry
->values
.claim_int64
);
475 case CLAIM_TYPE_UINT64
:
476 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.2")) {
477 return fill_claim_uint64_oid_syntax(mem_ctx
,
482 &claim_entry
->values
.claim_uint64
);
484 return fill_claim_uint64(mem_ctx
,
488 &claim_entry
->values
.claim_uint64
);
490 case CLAIM_TYPE_BOOLEAN
:
491 return fill_claim_boolean(mem_ctx
,
495 &claim_entry
->values
.claim_boolean
);
496 case CLAIM_TYPE_STRING
:
498 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.15")) {
499 return fill_claim_string_sec_desc_syntax(mem_ctx
,
502 &claim_entry
->values
.claim_string
);
504 return fill_claim_string(mem_ctx
,
507 &claim_entry
->values
.claim_string
);
513 * Determine whether a claim applies to the most specific objectClass of the
516 static int claim_applies_to_class(TALLOC_CTX
*mem_ctx
,
517 struct ldb_context
*ldb
,
518 const struct dsdb_schema
*schema
,
519 const struct ldb_message
*claim_msg
,
520 const uint32_t principal_class_id
,
523 struct ldb_message_element
*applies_to_class
= NULL
;
526 applies_to_class
= ldb_msg_find_element(claim_msg
,
527 "msDS-ClaimTypeAppliesToClass");
528 if (applies_to_class
== NULL
) {
533 for (i
= 0; i
< applies_to_class
->num_values
; ++i
) {
534 struct ldb_dn
*class_dn
= NULL
;
535 const struct dsdb_class
*class_val
= NULL
;
536 const struct ldb_val
*class_rdn
= NULL
;
538 class_dn
= ldb_dn_from_ldb_val(mem_ctx
,
540 &applies_to_class
->values
[i
]);
541 if (class_dn
== NULL
) {
545 class_rdn
= ldb_dn_get_rdn_val(class_dn
);
546 if (class_rdn
== NULL
) {
547 TALLOC_FREE(class_dn
);
551 class_val
= dsdb_class_by_cn_ldb_val(schema
, class_rdn
);
552 TALLOC_FREE(class_dn
);
553 if (class_val
== NULL
) {
557 if (class_val
->governsID_id
== principal_class_id
) {
567 struct assigned_silo
{
573 static struct assigned_silo
new_assigned_silo(void)
575 return (struct assigned_silo
) {
577 .is_initialised
= false,
578 .is_assigned
= false,
582 static bool silo_is_maybe_assigned(struct assigned_silo silo
)
584 return !silo
.is_initialised
|| silo
.is_assigned
;
587 static int get_assigned_silo(struct ldb_context
*ldb
,
589 const struct ldb_message
*principal
,
590 struct assigned_silo
*assigned_silo
)
592 TALLOC_CTX
*tmp_ctx
= NULL
;
595 const struct ldb_message
*silo_msg
= NULL
;
596 static const char * const silo_attrs
[] = {
597 "msDS-AuthNPolicySiloEnforced",
598 "msDS-AuthNPolicySiloMembers",
603 bool is_silo_enforced
= false;
604 const char *silo_name
= NULL
;
606 if (assigned_silo
->is_initialised
) {
610 tmp_ctx
= talloc_new(mem_ctx
);
611 if (tmp_ctx
== NULL
) {
615 if (!authn_policy_silos_and_policies_in_effect(ldb
)) {
616 /* No assigned silo. */
617 assigned_silo
->is_assigned
= false;
618 assigned_silo
->is_initialised
= true;
620 talloc_free(tmp_ctx
);
624 /* Check whether the user is assigned to an enforced silo. */
625 ret
= authn_policy_get_assigned_silo(ldb
,
632 talloc_free(tmp_ctx
);
636 if (silo_msg
== NULL
|| !is_silo_enforced
) {
637 /* No assigned silo. */
638 assigned_silo
->is_assigned
= false;
639 assigned_silo
->is_initialised
= true;
641 talloc_free(tmp_ctx
);
645 /* The user does belong to a silo, so return the name of the silo. */
646 silo_name
= ldb_msg_find_attr_as_string(silo_msg
,
649 assigned_silo
->name
= talloc_steal(mem_ctx
, silo_name
);
650 assigned_silo
->is_assigned
= true;
651 assigned_silo
->is_initialised
= true;
653 talloc_free(tmp_ctx
);
657 static inline struct ldb_val
talloc_steal_ldb_val(TALLOC_CTX
*mem_ctx
, struct ldb_val val
)
659 val
.data
= talloc_steal(mem_ctx
, val
.data
);
663 static uint32_t claim_get_value_count(const struct CLAIM_ENTRY
*claim
)
665 switch (claim
->type
) {
666 case CLAIM_TYPE_INT64
:
667 return claim
->values
.claim_int64
.value_count
;
668 case CLAIM_TYPE_UINT64
:
669 return claim
->values
.claim_uint64
.value_count
;
670 case CLAIM_TYPE_STRING
:
671 return claim
->values
.claim_string
.value_count
;
672 case CLAIM_TYPE_BOOLEAN
:
673 return claim
->values
.claim_boolean
.value_count
;
676 smb_panic(__location__
": unknown claim type");
680 static bool is_schema_dn(struct ldb_dn
*dn
,
681 struct ldb_dn
*schema_dn
)
683 if (ldb_dn_get_comp_num(dn
) != (ldb_dn_get_comp_num(schema_dn
) + 1)) {
687 return ldb_dn_compare_base(schema_dn
, dn
) == 0;
690 static bool is_valid_claim_attribute_syntax(const DATA_BLOB source_syntax
,
691 uint64_t claim_value_type
)
693 switch (claim_value_type
) {
694 case CLAIM_TYPE_STRING
:
695 if (data_blob_equals_str(source_syntax
, "2.5.5.1")) {
698 if (data_blob_equals_str(source_syntax
, "2.5.5.12")) {
701 if (data_blob_equals_str(source_syntax
, "2.5.5.15")) {
705 case CLAIM_TYPE_UINT64
:
706 if (data_blob_equals_str(source_syntax
, "2.5.5.2")) {
710 case CLAIM_TYPE_INT64
:
711 if (data_blob_equals_str(source_syntax
, "2.5.5.9")) {
714 if (data_blob_equals_str(source_syntax
, "2.5.5.16")) {
718 case CLAIM_TYPE_BOOLEAN
:
719 /* Note: MS-ADTS has a typo (2.2.5.8 instead of 2.5.5.8) */
720 if (data_blob_equals_str(source_syntax
, "2.5.5.8")) {
731 static int get_all_claims(struct ldb_context
*ldb
,
733 const struct ldb_message
*principal
,
734 uint32_t principal_class_id
,
735 struct CLAIMS_SET
**claims_set_out
)
737 TALLOC_CTX
*tmp_ctx
= NULL
;
739 const struct dsdb_schema
*schema
= NULL
;
741 struct ldb_dn
*claim_config_container
= NULL
;
742 struct ldb_dn
*claim_types_child
= NULL
;
743 struct ldb_dn
*config_dn
= ldb_get_config_basedn(ldb
);
744 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(ldb
);
747 struct ldb_result
*res
= NULL
;
748 static const char * const attrs
[] = {
750 "msDS-ClaimAttributeSource",
752 "msDS-ClaimSourceType",
753 "msDS-ClaimTypeAppliesToClass",
754 "msDS-ClaimValueType",
759 const char **ad_claim_attrs
= NULL
;
760 unsigned int ad_claim_attrs_count
;
761 struct ad_claim_info
{
764 const char *attribute
;
765 enum CLAIM_TYPE claim_type
;
767 unsigned ad_claims_count
;
771 /* The structure which we'll use to build up the claims. */
772 struct CLAIMS_SET
*claims_set
= NULL
;
774 struct CLAIMS_ARRAY
*ad_sourced_constructed
= NULL
;
776 struct assigned_silo assigned_silo
= new_assigned_silo();
778 *claims_set_out
= NULL
;
780 tmp_ctx
= talloc_new(mem_ctx
);
781 if (tmp_ctx
== NULL
) {
785 claims_set
= talloc_zero(tmp_ctx
, struct CLAIMS_SET
);
786 if (claims_set
== NULL
) {
787 talloc_free(tmp_ctx
);
791 schema
= dsdb_get_schema(ldb
, tmp_ctx
);
792 if (schema
== NULL
) {
793 talloc_free(tmp_ctx
);
794 return ldb_operr(ldb
);
797 /* Get the DN of the claims container. */
798 claim_config_container
= ldb_dn_copy(tmp_ctx
, config_dn
);
799 if (claim_config_container
== NULL
) {
800 talloc_free(tmp_ctx
);
804 claim_types_child
= ldb_dn_new(tmp_ctx
, ldb
,
805 "CN=Claim Types,CN=Claims Configuration,CN=Services");
806 if (claim_types_child
== NULL
) {
807 talloc_free(tmp_ctx
);
811 ok
= ldb_dn_add_child(claim_config_container
, claim_types_child
);
812 TALLOC_FREE(claim_types_child
);
814 talloc_free(tmp_ctx
);
815 return ldb_operr(ldb
);
818 /* Search for the claims container's children. */
819 ret
= ldb_search(ldb
, tmp_ctx
, &res
,
820 claim_config_container
,
824 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
828 talloc_free(tmp_ctx
);
833 * Allocate enough space for all AD claim attributes, followed by space
834 * for a NULL marker (so it can be passed as the attributes filter to an
837 ad_claim_attrs
= talloc_array(tmp_ctx
,
840 if (ad_claim_attrs
== NULL
) {
841 talloc_free(tmp_ctx
);
844 ad_claims
= talloc_array(tmp_ctx
,
845 struct ad_claim_info
,
847 if (ad_claims
== NULL
) {
848 talloc_free(tmp_ctx
);
851 ad_claims_count
= ad_claim_attrs_count
= 0;
853 /* Loop through each child of the claims container. */
854 for (i
= 0; i
< res
->count
; ++i
) {
855 bool claim_applies
= false;
858 uint64_t claim_value_type
;
860 const char *claim_source_type
= NULL
;
861 const struct ldb_val
*claim_attribute_source
= NULL
;
862 const char *claim_source
= NULL
;
865 * Does this claim apply to the most specific objectClass of the
868 ret
= claim_applies_to_class(tmp_ctx
,
875 talloc_free(tmp_ctx
);
878 if (!claim_applies
) {
879 /* If the claim doesn't apply, skip it. */
883 enabled
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "Enabled", 0);
885 /* If the claim isn't enabled, skip it. */
889 claim_value_type
= ldb_msg_find_attr_as_uint64(res
->msgs
[i
],
890 "msDS-ClaimValueType",
892 if (!claim_value_type
) {
896 claim_source_type
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
897 "msDS-ClaimSourceType",
900 /* Get the attribute used by the claim. */
901 claim_attribute_source
= ldb_msg_find_ldb_val(res
->msgs
[i
],
902 "msDS-ClaimAttributeSource");
904 claim_source
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
908 if (strcasecmp(claim_source_type
, "AD") == 0) {
909 struct ldb_dn
*claim_attribute_source_dn
= NULL
;
910 const struct ldb_val
*claim_attribute_source_rdn
= NULL
;
911 const struct dsdb_attribute
*claim_attribute_source_class
= NULL
;
913 DATA_BLOB source_syntax
;
914 const char *attribute
= NULL
;
915 const struct ldb_val
*name
= NULL
;
917 if (claim_attribute_source
== NULL
) {
921 claim_attribute_source_dn
= ldb_val_as_dn(ldb
,
923 claim_attribute_source
);
924 if (claim_attribute_source_dn
== NULL
) {
925 talloc_free(tmp_ctx
);
926 return ldb_operr(ldb
);
929 if (!is_schema_dn(claim_attribute_source_dn
, schema_dn
)) {
930 /* This DN doesn't belong to the schema. */
934 claim_attribute_source_rdn
= ldb_dn_get_rdn_val(claim_attribute_source_dn
);
935 if (claim_attribute_source_rdn
== NULL
) {
936 /* No RDN, skip it. */
940 claim_attribute_source_class
= dsdb_attribute_by_cn_ldb_val(schema
,
941 claim_attribute_source_rdn
);
942 claim_attribute_source_rdn
= NULL
;
943 TALLOC_FREE(claim_attribute_source_dn
);
944 if (claim_attribute_source_class
== NULL
) {
948 source_syntax
= data_blob_string_const(claim_attribute_source_class
->attributeSyntax_oid
);
949 if (source_syntax
.data
== NULL
) {
953 if (!is_valid_claim_attribute_syntax(source_syntax
, claim_value_type
)) {
957 attribute
= claim_attribute_source_class
->lDAPDisplayName
;
958 if (attribute
== NULL
) {
962 ret
= add_attr_unique(tmp_ctx
,
964 &ad_claim_attrs_count
,
967 talloc_free(tmp_ctx
);
971 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
973 name
= &data_blob_null
;
976 ad_claims
[ad_claims_count
++] = (struct ad_claim_info
) {
978 .syntax
= source_syntax
,
979 .attribute
= attribute
,
980 .claim_type
= claim_value_type
,
982 } else if (silo_is_maybe_assigned(assigned_silo
)
983 && strcasecmp(claim_source_type
, "Constructed") == 0)
985 const struct ldb_val
*name
= NULL
;
986 struct CLAIM_STRING
*claim
= NULL
;
987 struct CLAIM_ENTRY
*claim_entry
= NULL
;
988 const char *claim_value
= NULL
;
990 if (claim_attribute_source
!= NULL
) {
994 if (claim_source
!= NULL
) {
998 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
999 if (name
== NULL
|| name
->data
== NULL
) {
1002 /* Does the claim ID match exactly in case? */
1003 if (strcmp((const char *)name
->data
, "ad://ext/AuthenticationSilo") != 0) {
1007 ret
= get_assigned_silo(ldb
, tmp_ctx
, principal
, &assigned_silo
);
1009 talloc_free(tmp_ctx
);
1012 if (!assigned_silo
.is_assigned
) {
1016 if (ad_sourced_constructed
== NULL
) {
1017 claims_set
->claims_arrays
= talloc_realloc(claims_set
,
1018 claims_set
->claims_arrays
,
1019 struct CLAIMS_ARRAY
,
1020 claims_set
->claims_array_count
+ 1);
1021 if (claims_set
->claims_arrays
== NULL
) {
1022 talloc_free(tmp_ctx
);
1023 return ldb_oom(ldb
);
1026 ad_sourced_constructed
= &claims_set
->claims_arrays
[claims_set
->claims_array_count
++];
1027 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1028 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1032 /* Add the claim to the array. */
1033 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1034 claims_set
->claims_arrays
,
1035 ad_sourced_constructed
->claim_entries
,
1037 ad_sourced_constructed
->claims_count
+ 1);
1038 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1039 talloc_free(tmp_ctx
);
1040 return ldb_oom(ldb
);
1043 claim_entry
= &ad_sourced_constructed
->claim_entries
[ad_sourced_constructed
->claims_count
++];
1045 /* Fill in the claim details and return the claim. */
1046 claim_entry
->id
= "ad://ext/AuthenticationSilo";
1047 claim_entry
->type
= CLAIM_TYPE_STRING
;
1049 claim
= &claim_entry
->values
.claim_string
;
1051 claim
->value_count
= 1;
1052 claim
->values
= talloc_array(ad_sourced_constructed
->claim_entries
,
1054 claim
->value_count
);
1055 if (claim
->values
== NULL
) {
1056 talloc_free(tmp_ctx
);
1057 return ldb_oom(ldb
);
1060 claim_value
= talloc_strdup(claim
->values
, assigned_silo
.name
);
1061 if (claim_value
== NULL
) {
1062 talloc_free(tmp_ctx
);
1063 return ldb_oom(ldb
);
1066 claim
->values
[0] = claim_value
;
1070 if (ad_claims_count
) {
1071 struct ldb_message
*principal_msg
= NULL
;
1073 /* Shrink the arrays to remove any unused space. */
1074 ad_claim_attrs
= talloc_realloc(tmp_ctx
,
1077 ad_claim_attrs_count
+ 1);
1078 if (ad_claim_attrs
== NULL
) {
1079 talloc_free(tmp_ctx
);
1080 return ldb_oom(ldb
);
1082 ad_claim_attrs
[ad_claim_attrs_count
] = NULL
;
1084 ad_claims
= talloc_realloc(tmp_ctx
,
1086 struct ad_claim_info
,
1088 if (ad_claims
== NULL
) {
1089 talloc_free(tmp_ctx
);
1090 return ldb_oom(ldb
);
1093 ret
= dsdb_search_one(ldb
,
1101 if (ret
!= LDB_SUCCESS
) {
1102 const char *dn
= ldb_dn_get_linearized(principal
->dn
);
1103 DBG_ERR("Failed to find principal %s to construct claims\n",
1104 dn
!= NULL
? dn
: "<NULL>");
1105 talloc_free(tmp_ctx
);
1110 * Ensure that only the attrs we asked for end up in the results
1111 * (it's fine if some are missing)
1113 SMB_ASSERT(principal_msg
->num_elements
<= ad_claim_attrs_count
);
1115 for (i
= 0; i
< ad_claims_count
; ++i
) {
1116 const struct ldb_message_element
*principal_attribute
= NULL
;
1117 struct CLAIM_ENTRY
*claim_entry
= NULL
;
1118 uint32_t new_claims_array_count
= claims_set
->claims_array_count
;
1120 /* Get the value of the claim attribute for the principal. */
1121 principal_attribute
= ldb_msg_find_element(principal_msg
,
1122 ad_claims
[i
].attribute
);
1123 if (principal_attribute
== NULL
) {
1127 /* Add the claim to the array. */
1129 if (ad_sourced_constructed
== NULL
) {
1130 claims_set
->claims_arrays
= talloc_realloc(claims_set
,
1131 claims_set
->claims_arrays
,
1132 struct CLAIMS_ARRAY
,
1133 new_claims_array_count
+ 1);
1134 if (claims_set
->claims_arrays
== NULL
) {
1135 talloc_free(tmp_ctx
);
1136 return ldb_oom(ldb
);
1139 ad_sourced_constructed
= &claims_set
->claims_arrays
[new_claims_array_count
++];
1140 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1141 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1145 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1146 claims_set
->claims_arrays
,
1147 ad_sourced_constructed
->claim_entries
,
1149 ad_sourced_constructed
->claims_count
+ 1);
1150 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1151 talloc_free(tmp_ctx
);
1152 return ldb_oom(ldb
);
1155 claim_entry
= &ad_sourced_constructed
->claim_entries
[
1156 ad_sourced_constructed
->claims_count
];
1158 ret
= fill_claim_entry(ad_sourced_constructed
->claim_entries
,
1161 principal_attribute
,
1163 ad_claims
[i
].syntax
,
1164 ad_claims
[i
].claim_type
,
1166 if (ret
!= LDB_SUCCESS
) {
1167 talloc_free(tmp_ctx
);
1171 if (claim_get_value_count(claim_entry
) > 0) {
1173 * If the claim contains values, add it to the
1176 ++ad_sourced_constructed
->claims_count
;
1177 claims_set
->claims_array_count
= new_claims_array_count
;
1182 if (claims_set
->claims_array_count
) {
1183 *claims_set_out
= talloc_steal(mem_ctx
, claims_set
);
1186 talloc_free(tmp_ctx
);
1190 int get_claims_set_for_principal(struct ldb_context
*ldb
,
1191 TALLOC_CTX
*mem_ctx
,
1192 const struct ldb_message
*principal
,
1193 struct CLAIMS_SET
**claims_set_out
)
1195 struct ldb_message_element
*principal_class_el
= NULL
;
1196 struct dsdb_schema
*schema
= NULL
;
1197 const struct dsdb_class
*principal_class
= NULL
;
1199 *claims_set_out
= NULL
;
1201 if (!ad_claims_are_issued(ldb
)) {
1205 principal_class_el
= ldb_msg_find_element(principal
,
1207 if (principal_class_el
== NULL
) {
1208 return ldb_operr(ldb
);
1211 schema
= dsdb_get_schema(ldb
, mem_ctx
);
1212 if (schema
== NULL
) {
1213 return ldb_operr(ldb
);
1216 principal_class
= dsdb_get_last_structural_class(schema
, principal_class_el
);
1217 if (principal_class
== NULL
) {
1218 return ldb_operr(ldb
);
1221 return get_all_claims(ldb
,
1224 principal_class
->governsID_id
,