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"
37 bool ad_claims_are_issued(struct ldb_context
*samdb
)
40 * Claims aren’t issued by Samba unless the DC is at
41 * FL2012. This is to match Windows, which will offer
42 * this feature as soon as the DC is upgraded.
44 const int functional_level
= dsdb_dc_functional_level(samdb
);
45 return functional_level
>= DS_DOMAIN_FUNCTION_2012
;
48 static int acl_attr_cmp_fn(const char *a
, const char * const *b
)
50 return ldb_attr_cmp(a
, *b
);
54 * Add a single attribute to a list of attributes if it is not already
55 * present. The list is maintained in case-insensitive sorted order.
57 static int add_attr_unique(TALLOC_CTX
*mem_ctx
,
59 unsigned *ad_claim_attrs_count
,
62 const unsigned count
= *ad_claim_attrs_count
;
63 const char * const *exact
= NULL
;
64 const char * const *next
= NULL
;
66 BINARY_ARRAY_SEARCH_GTE(attrs
,
73 /* The attribute is already present; there's nothing to do. */
77 /* Make sure we don't overflow the array. */
78 SMB_ASSERT(count
< talloc_array_length(attrs
));
79 *ad_claim_attrs_count
= count
+ 1;
82 /* Just add the new element on the end. */
85 /* Shift all following elements over to make room. */
86 size_t next_idx
= next
- attrs
;
87 size_t bytes_to_move
= (count
- next_idx
) * sizeof (attrs
[0]);
88 memmove(&attrs
[next_idx
+ 1],
92 attrs
[next_idx
] = attr
;
99 * Return true if a data_blob, interpreted as a string, is equal to another
100 * string. This is more efficient than strcmp(), particularly when comparing
101 * against a string constant. This assumes the data_blob's length does not
102 * include the zero-terminator.
104 static inline bool data_blob_equals_str(const DATA_BLOB val
, const char *str
)
106 size_t len
= strlen(str
);
107 if (val
.length
!= len
) {
111 return memcmp(val
.data
, str
, len
) == 0;
114 static int fill_claim_int64(TALLOC_CTX
*mem_ctx
,
115 struct ldb_context
*ldb
,
116 const struct ldb_message_element
*principal_attribute
,
117 const struct ldb_val name
,
118 struct CLAIM_INT64
*claim
)
122 claim
->value_count
= 0;
123 claim
->values
= talloc_array(mem_ctx
,
125 principal_attribute
->num_values
);
126 if (claim
->values
== NULL
) {
130 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
131 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
132 int ret
= ldb_val_as_int64(value
, &claim
->values
[i
]);
135 const char *reason
= NULL
;
136 int err
= strerror_r(ret
, buf
, sizeof(buf
));
140 reason
= "Unknown error";
142 DBG_WARNING("Failed to interpret value %s as INT64 "
143 "while creating claim %s for attribute %s (%s); "
145 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
146 name
.data
, principal_attribute
->name
,
151 ++claim
->value_count
;
154 /* Shrink the array to fit. */
155 claim
->values
= talloc_realloc(mem_ctx
,
159 if (claim
->value_count
&& claim
->values
== NULL
) {
166 static int fill_claim_uint64(TALLOC_CTX
*mem_ctx
,
167 struct ldb_context
*ldb
,
168 const struct ldb_message_element
*principal_attribute
,
169 const struct ldb_val name
,
170 struct CLAIM_UINT64
*claim
)
174 claim
->value_count
= 0;
175 claim
->values
= talloc_array(mem_ctx
,
177 principal_attribute
->num_values
);
178 if (claim
->values
== NULL
) {
182 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
183 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
184 int ret
= ldb_val_as_uint64(value
, &claim
->values
[i
]);
187 const char *reason
= NULL
;
188 int err
= strerror_r(ret
, buf
, sizeof(buf
));
192 reason
= "Unknown error";
194 DBG_WARNING("Failed to interpret value %s as UINT64 "
195 "while creating claim %s for attribute %s (%s); "
197 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
198 name
.data
, principal_attribute
->name
,
203 ++claim
->value_count
;
206 /* Shrink the array to fit. */
207 claim
->values
= talloc_realloc(mem_ctx
,
211 if (claim
->value_count
&& claim
->values
== NULL
) {
218 static int fill_claim_uint64_oid_syntax(TALLOC_CTX
*mem_ctx
,
219 struct ldb_context
*ldb
,
220 const struct dsdb_schema
*schema
,
221 const struct ldb_message_element
*principal_attribute
,
222 const struct ldb_val name
,
223 struct CLAIM_UINT64
*claim
)
227 claim
->value_count
= 0;
228 claim
->values
= talloc_array(mem_ctx
,
230 principal_attribute
->num_values
);
231 if (claim
->values
== NULL
) {
235 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
236 const struct dsdb_class
*class_val
= NULL
;
239 * OID values for objectClass
240 * are presented in reverse
243 const struct ldb_val
*display_name
= &principal_attribute
->values
[
244 principal_attribute
->num_values
- 1 - i
];
246 class_val
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, display_name
);
247 if (class_val
== NULL
) {
248 DBG_WARNING("Failed to look up OID for value %s "
249 "while creating claim %s for attribute %s; "
251 (display_name
->data
!= NULL
) ? (const char *)display_name
->data
: "<unknown>",
252 name
.data
, principal_attribute
->name
);
256 claim
->values
[i
] = class_val
->governsID_id
;
257 ++claim
->value_count
;
260 /* Shrink the array to fit. */
261 claim
->values
= talloc_realloc(mem_ctx
,
265 if (claim
->value_count
&& claim
->values
== NULL
) {
272 static int fill_claim_boolean(TALLOC_CTX
*mem_ctx
,
273 struct ldb_context
*ldb
,
274 const struct ldb_message_element
*principal_attribute
,
275 const struct ldb_val name
,
276 struct CLAIM_UINT64
*claim
)
280 claim
->value_count
= 0;
281 claim
->values
= talloc_array(mem_ctx
,
283 principal_attribute
->num_values
);
284 if (claim
->values
== NULL
) {
288 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
289 const struct ldb_val
*value
= &principal_attribute
->values
[i
];
291 int ret
= ldb_val_as_bool(value
, &val
);
294 const char *reason
= NULL
;
295 int err
= strerror_r(ret
, buf
, sizeof(buf
));
299 reason
= "Unknown error";
301 DBG_WARNING("Failed to interpret value %s as BOOL "
302 "while creating claim %s for attribute %s (%s); "
304 (value
->data
!= NULL
) ? (const char *)value
->data
: "<unknown>",
305 name
.data
, principal_attribute
->name
,
310 claim
->values
[i
] = val
;
311 ++claim
->value_count
;
314 /* Shrink the array to fit. */
315 claim
->values
= talloc_realloc(mem_ctx
,
319 if (claim
->value_count
&& claim
->values
== NULL
) {
326 static int fill_claim_string(TALLOC_CTX
*mem_ctx
,
327 struct ldb_context
*ldb
,
328 const struct ldb_message_element
*principal_attribute
,
329 struct CLAIM_STRING
*claim
)
333 claim
->value_count
= 0;
334 claim
->values
= talloc_array(mem_ctx
,
336 principal_attribute
->num_values
);
337 if (claim
->values
== NULL
) {
341 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
342 const char *val
= NULL
;
343 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
345 if (v
== NULL
|| v
->data
== NULL
) {
349 val
= talloc_strndup(claim
->values
,
350 (const char *)v
->data
,
356 claim
->values
[i
] = val
;
357 ++claim
->value_count
;
360 /* Shrink the array to fit. */
361 claim
->values
= talloc_realloc(mem_ctx
,
365 if (claim
->value_count
&& claim
->values
== NULL
) {
372 static int fill_claim_string_sec_desc_syntax(TALLOC_CTX
*mem_ctx
,
373 struct ldb_context
*ldb
,
374 const struct ldb_message_element
*principal_attribute
,
375 struct CLAIM_STRING
*claim
)
377 TALLOC_CTX
*tmp_ctx
= NULL
;
378 const struct dom_sid
*domain_sid
= NULL
;
381 claim
->value_count
= 0;
382 claim
->values
= talloc_array(mem_ctx
,
384 principal_attribute
->num_values
);
385 if (claim
->values
== NULL
) {
389 domain_sid
= samdb_domain_sid(ldb
);
390 if (domain_sid
== NULL
) {
394 tmp_ctx
= talloc_new(mem_ctx
);
395 if (tmp_ctx
== NULL
) {
399 for (i
= 0; i
< principal_attribute
->num_values
; ++i
) {
400 const struct ldb_val
*v
= &principal_attribute
->values
[i
];
402 enum ndr_err_code ndr_err
;
403 struct security_descriptor desc
= {};
404 const char *sddl
= NULL
;
406 if (v
== NULL
|| v
->data
== NULL
) {
410 ndr_err
= ndr_pull_struct_blob(v
,
413 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
414 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
415 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
416 DBG_ERR("security_descriptor pull failed: %s\n",
417 nt_errstr(nt_status
));
418 talloc_free(tmp_ctx
);
419 return ldb_operr(ldb
);
422 sddl
= sddl_encode(mem_ctx
,
426 talloc_free(tmp_ctx
);
430 claim
->values
[i
] = sddl
;
431 ++claim
->value_count
;
434 talloc_free(tmp_ctx
);
436 /* Shrink the array to fit. */
437 claim
->values
= talloc_realloc(mem_ctx
,
441 if (claim
->value_count
&& claim
->values
== NULL
) {
448 static int fill_claim_entry(TALLOC_CTX
*mem_ctx
,
449 struct ldb_context
*ldb
,
450 const struct dsdb_schema
*schema
,
451 const struct ldb_message_element
*principal_attribute
,
452 const struct ldb_val name
,
453 const DATA_BLOB syntax
,
454 enum CLAIM_TYPE claim_type
,
455 struct CLAIM_ENTRY
*claim_entry
)
458 claim_entry
->id
= talloc_strndup(mem_ctx
,
459 (const char *)name
.data
,
461 if (claim_entry
->id
== NULL
) {
465 claim_entry
->type
= claim_type
;
467 switch (claim_type
) {
468 case CLAIM_TYPE_INT64
:
469 return fill_claim_int64(mem_ctx
,
473 &claim_entry
->values
.claim_int64
);
474 case CLAIM_TYPE_UINT64
:
475 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.2")) {
476 return fill_claim_uint64_oid_syntax(mem_ctx
,
481 &claim_entry
->values
.claim_uint64
);
483 return fill_claim_uint64(mem_ctx
,
487 &claim_entry
->values
.claim_uint64
);
489 case CLAIM_TYPE_BOOLEAN
:
490 return fill_claim_boolean(mem_ctx
,
494 &claim_entry
->values
.claim_boolean
);
495 case CLAIM_TYPE_STRING
:
497 if (syntax
.data
!= NULL
&& data_blob_equals_str(syntax
, "2.5.5.15")) {
498 return fill_claim_string_sec_desc_syntax(mem_ctx
,
501 &claim_entry
->values
.claim_string
);
503 return fill_claim_string(mem_ctx
,
506 &claim_entry
->values
.claim_string
);
512 * Determine whether a claim applies to the most specific objectClass of the
515 static int claim_applies_to_class(TALLOC_CTX
*mem_ctx
,
516 struct ldb_context
*ldb
,
517 const struct dsdb_schema
*schema
,
518 const struct ldb_message
*claim_msg
,
519 const uint32_t principal_class_id
,
522 struct ldb_message_element
*applies_to_class
= NULL
;
525 applies_to_class
= ldb_msg_find_element(claim_msg
,
526 "msDS-ClaimTypeAppliesToClass");
527 if (applies_to_class
== NULL
) {
532 for (i
= 0; i
< applies_to_class
->num_values
; ++i
) {
533 struct ldb_dn
*class_dn
= NULL
;
534 const struct dsdb_class
*class_val
= NULL
;
535 const struct ldb_val
*class_rdn
= NULL
;
537 class_dn
= ldb_dn_from_ldb_val(mem_ctx
,
539 &applies_to_class
->values
[i
]);
540 if (class_dn
== NULL
) {
544 class_rdn
= ldb_dn_get_rdn_val(class_dn
);
545 if (class_rdn
== NULL
) {
546 TALLOC_FREE(class_dn
);
550 class_val
= dsdb_class_by_cn_ldb_val(schema
, class_rdn
);
551 TALLOC_FREE(class_dn
);
552 if (class_val
== NULL
) {
556 if (class_val
->governsID_id
== principal_class_id
) {
566 struct assigned_silo
{
572 static struct assigned_silo
new_assigned_silo(void)
574 return (struct assigned_silo
) {
576 .is_initialised
= false,
577 .is_assigned
= false,
581 static bool silo_is_maybe_assigned(struct assigned_silo silo
)
583 return !silo
.is_initialised
|| silo
.is_assigned
;
586 static int get_assigned_silo(struct ldb_context
*ldb
,
588 const struct ldb_message
*principal
,
589 struct assigned_silo
*assigned_silo
)
591 TALLOC_CTX
*tmp_ctx
= NULL
;
594 const struct ldb_message
*silo_msg
= NULL
;
595 static const char * const silo_attrs
[] = {
596 "msDS-AuthNPolicySiloEnforced",
597 "msDS-AuthNPolicySiloMembers",
602 bool is_silo_enforced
= false;
603 const char *silo_name
= NULL
;
605 if (assigned_silo
->is_initialised
) {
609 tmp_ctx
= talloc_new(mem_ctx
);
610 if (tmp_ctx
== NULL
) {
614 if (!authn_policy_silos_and_policies_in_effect(ldb
)) {
615 /* No assigned silo. */
616 assigned_silo
->is_assigned
= false;
617 assigned_silo
->is_initialised
= true;
619 talloc_free(tmp_ctx
);
623 /* Check whether the user is assigned to an enforced silo. */
624 ret
= authn_policy_get_assigned_silo(ldb
,
631 talloc_free(tmp_ctx
);
635 if (silo_msg
== NULL
|| !is_silo_enforced
) {
636 /* No assigned silo. */
637 assigned_silo
->is_assigned
= false;
638 assigned_silo
->is_initialised
= true;
640 talloc_free(tmp_ctx
);
644 /* The user does belong to a silo, so return the name of the silo. */
645 silo_name
= ldb_msg_find_attr_as_string(silo_msg
,
648 assigned_silo
->name
= talloc_steal(mem_ctx
, silo_name
);
649 assigned_silo
->is_assigned
= true;
650 assigned_silo
->is_initialised
= true;
652 talloc_free(tmp_ctx
);
656 static inline struct ldb_val
talloc_steal_ldb_val(TALLOC_CTX
*mem_ctx
, struct ldb_val val
)
658 val
.data
= talloc_steal(mem_ctx
, val
.data
);
662 static uint32_t claim_get_value_count(const struct CLAIM_ENTRY
*claim
)
664 switch (claim
->type
) {
665 case CLAIM_TYPE_INT64
:
666 return claim
->values
.claim_int64
.value_count
;
667 case CLAIM_TYPE_UINT64
:
668 return claim
->values
.claim_uint64
.value_count
;
669 case CLAIM_TYPE_STRING
:
670 return claim
->values
.claim_string
.value_count
;
671 case CLAIM_TYPE_BOOLEAN
:
672 return claim
->values
.claim_boolean
.value_count
;
675 smb_panic(__location__
": unknown claim type");
679 static bool is_schema_dn(struct ldb_dn
*dn
,
680 struct ldb_dn
*schema_dn
)
682 if (ldb_dn_get_comp_num(dn
) != (ldb_dn_get_comp_num(schema_dn
) + 1)) {
686 return ldb_dn_compare_base(schema_dn
, dn
) == 0;
689 static bool is_valid_claim_attribute_syntax(const DATA_BLOB source_syntax
,
690 uint64_t claim_value_type
)
692 switch (claim_value_type
) {
693 case CLAIM_TYPE_STRING
:
694 if (data_blob_equals_str(source_syntax
, "2.5.5.1")) {
697 if (data_blob_equals_str(source_syntax
, "2.5.5.12")) {
700 if (data_blob_equals_str(source_syntax
, "2.5.5.15")) {
704 case CLAIM_TYPE_UINT64
:
705 if (data_blob_equals_str(source_syntax
, "2.5.5.2")) {
709 case CLAIM_TYPE_INT64
:
710 if (data_blob_equals_str(source_syntax
, "2.5.5.9")) {
713 if (data_blob_equals_str(source_syntax
, "2.5.5.16")) {
717 case CLAIM_TYPE_BOOLEAN
:
718 /* Note: MS-ADTS has a typo (2.2.5.8 instead of 2.5.5.8) */
719 if (data_blob_equals_str(source_syntax
, "2.5.5.8")) {
730 static int get_all_claims(struct ldb_context
*ldb
,
732 const struct ldb_message
*principal
,
733 uint32_t principal_class_id
,
734 struct CLAIMS_SET
**claims_set_out
)
736 TALLOC_CTX
*tmp_ctx
= NULL
;
738 const struct dsdb_schema
*schema
= NULL
;
740 struct ldb_dn
*claim_config_container
= NULL
;
741 struct ldb_dn
*claim_types_child
= NULL
;
742 struct ldb_dn
*config_dn
= ldb_get_config_basedn(ldb
);
743 struct ldb_dn
*schema_dn
= ldb_get_schema_basedn(ldb
);
746 struct ldb_result
*res
= NULL
;
747 static const char * const attrs
[] = {
749 "msDS-ClaimAttributeSource",
751 "msDS-ClaimSourceType",
752 "msDS-ClaimTypeAppliesToClass",
753 "msDS-ClaimValueType",
758 const char **ad_claim_attrs
= NULL
;
759 unsigned int ad_claim_attrs_count
;
760 struct ad_claim_info
{
763 const char *attribute
;
764 enum CLAIM_TYPE claim_type
;
766 unsigned ad_claims_count
;
770 /* The structure which we'll use to build up the claims. */
771 struct CLAIMS_SET
*claims_set
= NULL
;
773 struct CLAIMS_ARRAY
*ad_sourced_constructed
= NULL
;
775 struct assigned_silo assigned_silo
= new_assigned_silo();
777 *claims_set_out
= NULL
;
779 tmp_ctx
= talloc_new(mem_ctx
);
780 if (tmp_ctx
== NULL
) {
784 claims_set
= talloc_zero(tmp_ctx
, struct CLAIMS_SET
);
785 if (claims_set
== NULL
) {
786 talloc_free(tmp_ctx
);
790 schema
= dsdb_get_schema(ldb
, tmp_ctx
);
791 if (schema
== NULL
) {
792 talloc_free(tmp_ctx
);
793 return ldb_operr(ldb
);
796 /* Get the DN of the claims container. */
797 claim_config_container
= ldb_dn_copy(tmp_ctx
, config_dn
);
798 if (claim_config_container
== NULL
) {
799 talloc_free(tmp_ctx
);
803 claim_types_child
= ldb_dn_new(tmp_ctx
, ldb
,
804 "CN=Claim Types,CN=Claims Configuration,CN=Services");
805 if (claim_types_child
== NULL
) {
806 talloc_free(tmp_ctx
);
810 ok
= ldb_dn_add_child(claim_config_container
, claim_types_child
);
811 TALLOC_FREE(claim_types_child
);
813 talloc_free(tmp_ctx
);
814 return ldb_operr(ldb
);
817 /* Search for the claims container's children. */
818 ret
= ldb_search(ldb
, tmp_ctx
, &res
,
819 claim_config_container
,
823 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
827 talloc_free(tmp_ctx
);
832 * Allocate enough space for all AD claim attributes, followed by space
833 * for a NULL marker (so it can be passed as the attributes filter to an
836 ad_claim_attrs
= talloc_array(tmp_ctx
,
839 if (ad_claim_attrs
== NULL
) {
840 talloc_free(tmp_ctx
);
843 ad_claims
= talloc_array(tmp_ctx
,
844 struct ad_claim_info
,
846 if (ad_claims
== NULL
) {
847 talloc_free(tmp_ctx
);
850 ad_claims_count
= ad_claim_attrs_count
= 0;
852 /* Loop through each child of the claims container. */
853 for (i
= 0; i
< res
->count
; ++i
) {
854 bool claim_applies
= false;
857 uint64_t claim_value_type
;
859 const char *claim_source_type
= NULL
;
860 const struct ldb_val
*claim_attribute_source
= NULL
;
861 const char *claim_source
= NULL
;
864 * Does this claim apply to the most specific objectClass of the
867 ret
= claim_applies_to_class(tmp_ctx
,
874 talloc_free(tmp_ctx
);
877 if (!claim_applies
) {
878 /* If the claim doesn't apply, skip it. */
882 enabled
= ldb_msg_find_attr_as_bool(res
->msgs
[i
], "Enabled", 0);
884 /* If the claim isn't enabled, skip it. */
888 claim_value_type
= ldb_msg_find_attr_as_uint64(res
->msgs
[i
],
889 "msDS-ClaimValueType",
891 if (!claim_value_type
) {
895 claim_source_type
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
896 "msDS-ClaimSourceType",
899 /* Get the attribute used by the claim. */
900 claim_attribute_source
= ldb_msg_find_ldb_val(res
->msgs
[i
],
901 "msDS-ClaimAttributeSource");
903 claim_source
= ldb_msg_find_attr_as_string(res
->msgs
[i
],
907 if (strcasecmp(claim_source_type
, "AD") == 0) {
908 struct ldb_dn
*claim_attribute_source_dn
= NULL
;
909 const struct ldb_val
*claim_attribute_source_rdn
= NULL
;
910 const struct dsdb_attribute
*claim_attribute_source_class
= NULL
;
912 DATA_BLOB source_syntax
;
913 const char *attribute
= NULL
;
914 const struct ldb_val
*name
= NULL
;
916 if (claim_attribute_source
== NULL
) {
920 claim_attribute_source_dn
= ldb_val_as_dn(ldb
,
922 claim_attribute_source
);
923 if (claim_attribute_source_dn
== NULL
) {
924 talloc_free(tmp_ctx
);
925 return ldb_operr(ldb
);
928 if (!is_schema_dn(claim_attribute_source_dn
, schema_dn
)) {
929 /* This DN doesn't belong to the schema. */
933 claim_attribute_source_rdn
= ldb_dn_get_rdn_val(claim_attribute_source_dn
);
934 if (claim_attribute_source_rdn
== NULL
) {
935 /* No RDN, skip it. */
939 claim_attribute_source_class
= dsdb_attribute_by_cn_ldb_val(schema
,
940 claim_attribute_source_rdn
);
941 claim_attribute_source_rdn
= NULL
;
942 TALLOC_FREE(claim_attribute_source_dn
);
943 if (claim_attribute_source_class
== NULL
) {
947 source_syntax
= data_blob_string_const(claim_attribute_source_class
->attributeSyntax_oid
);
948 if (source_syntax
.data
== NULL
) {
952 if (!is_valid_claim_attribute_syntax(source_syntax
, claim_value_type
)) {
956 attribute
= claim_attribute_source_class
->lDAPDisplayName
;
957 if (attribute
== NULL
) {
961 ret
= add_attr_unique(tmp_ctx
,
963 &ad_claim_attrs_count
,
966 talloc_free(tmp_ctx
);
970 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
972 name
= &data_blob_null
;
975 ad_claims
[ad_claims_count
++] = (struct ad_claim_info
) {
977 .syntax
= source_syntax
,
978 .attribute
= attribute
,
979 .claim_type
= claim_value_type
,
981 } else if (silo_is_maybe_assigned(assigned_silo
)
982 && strcasecmp(claim_source_type
, "Constructed") == 0)
984 const struct ldb_val
*name
= NULL
;
985 struct CLAIM_STRING
*claim
= NULL
;
986 struct CLAIM_ENTRY
*claim_entry
= NULL
;
987 const char *claim_value
= NULL
;
989 if (claim_attribute_source
!= NULL
) {
993 if (claim_source
!= NULL
) {
997 name
= ldb_msg_find_ldb_val(res
->msgs
[i
], "name");
998 if (name
== NULL
|| name
->data
== NULL
) {
1001 /* Does the claim ID match exactly in case? */
1002 if (strcmp((const char *)name
->data
, "ad://ext/AuthenticationSilo") != 0) {
1006 ret
= get_assigned_silo(ldb
, tmp_ctx
, principal
, &assigned_silo
);
1008 talloc_free(tmp_ctx
);
1011 if (!assigned_silo
.is_assigned
) {
1015 if (ad_sourced_constructed
== NULL
) {
1016 claims_set
->claims_arrays
= talloc_realloc(claims_set
,
1017 claims_set
->claims_arrays
,
1018 struct CLAIMS_ARRAY
,
1019 claims_set
->claims_array_count
+ 1);
1020 if (claims_set
->claims_arrays
== NULL
) {
1021 talloc_free(tmp_ctx
);
1022 return ldb_oom(ldb
);
1025 ad_sourced_constructed
= &claims_set
->claims_arrays
[claims_set
->claims_array_count
++];
1026 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1027 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1031 /* Add the claim to the array. */
1032 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1033 claims_set
->claims_arrays
,
1034 ad_sourced_constructed
->claim_entries
,
1036 ad_sourced_constructed
->claims_count
+ 1);
1037 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1038 talloc_free(tmp_ctx
);
1039 return ldb_oom(ldb
);
1042 claim_entry
= &ad_sourced_constructed
->claim_entries
[ad_sourced_constructed
->claims_count
++];
1044 /* Fill in the claim details and return the claim. */
1045 claim_entry
->id
= "ad://ext/AuthenticationSilo";
1046 claim_entry
->type
= CLAIM_TYPE_STRING
;
1048 claim
= &claim_entry
->values
.claim_string
;
1050 claim
->value_count
= 1;
1051 claim
->values
= talloc_array(ad_sourced_constructed
->claim_entries
,
1053 claim
->value_count
);
1054 if (claim
->values
== NULL
) {
1055 talloc_free(tmp_ctx
);
1056 return ldb_oom(ldb
);
1059 claim_value
= talloc_strdup(claim
->values
, assigned_silo
.name
);
1060 if (claim_value
== NULL
) {
1061 talloc_free(tmp_ctx
);
1062 return ldb_oom(ldb
);
1065 claim
->values
[0] = claim_value
;
1069 if (ad_claims_count
) {
1070 struct ldb_message
*principal_msg
= NULL
;
1072 /* Shrink the arrays to remove any unused space. */
1073 ad_claim_attrs
= talloc_realloc(tmp_ctx
,
1076 ad_claim_attrs_count
+ 1);
1077 if (ad_claim_attrs
== NULL
) {
1078 talloc_free(tmp_ctx
);
1079 return ldb_oom(ldb
);
1081 ad_claim_attrs
[ad_claim_attrs_count
] = NULL
;
1083 ad_claims
= talloc_realloc(tmp_ctx
,
1085 struct ad_claim_info
,
1087 if (ad_claims
== NULL
) {
1088 talloc_free(tmp_ctx
);
1089 return ldb_oom(ldb
);
1092 ret
= dsdb_search_one(ldb
,
1100 if (ret
!= LDB_SUCCESS
) {
1101 const char *dn
= ldb_dn_get_linearized(principal
->dn
);
1102 DBG_ERR("Failed to find principal %s to construct claims\n",
1103 dn
!= NULL
? dn
: "<NULL>");
1104 talloc_free(tmp_ctx
);
1109 * Ensure that only the attrs we asked for end up in the results
1110 * (it's fine if some are missing)
1112 SMB_ASSERT(principal_msg
->num_elements
<= ad_claim_attrs_count
);
1114 for (i
= 0; i
< ad_claims_count
; ++i
) {
1115 const struct ldb_message_element
*principal_attribute
= NULL
;
1116 struct CLAIM_ENTRY
*claim_entry
= NULL
;
1117 uint32_t new_claims_array_count
= claims_set
->claims_array_count
;
1119 /* Get the value of the claim attribute for the principal. */
1120 principal_attribute
= ldb_msg_find_element(principal_msg
,
1121 ad_claims
[i
].attribute
);
1122 if (principal_attribute
== NULL
) {
1126 /* Add the claim to the array. */
1128 if (ad_sourced_constructed
== NULL
) {
1129 claims_set
->claims_arrays
= talloc_realloc(claims_set
,
1130 claims_set
->claims_arrays
,
1131 struct CLAIMS_ARRAY
,
1132 new_claims_array_count
+ 1);
1133 if (claims_set
->claims_arrays
== NULL
) {
1134 talloc_free(tmp_ctx
);
1135 return ldb_oom(ldb
);
1138 ad_sourced_constructed
= &claims_set
->claims_arrays
[new_claims_array_count
++];
1139 *ad_sourced_constructed
= (struct CLAIMS_ARRAY
) {
1140 .claims_source_type
= CLAIMS_SOURCE_TYPE_AD
,
1144 ad_sourced_constructed
->claim_entries
= talloc_realloc(
1145 claims_set
->claims_arrays
,
1146 ad_sourced_constructed
->claim_entries
,
1148 ad_sourced_constructed
->claims_count
+ 1);
1149 if (ad_sourced_constructed
->claim_entries
== NULL
) {
1150 talloc_free(tmp_ctx
);
1151 return ldb_oom(ldb
);
1154 claim_entry
= &ad_sourced_constructed
->claim_entries
[
1155 ad_sourced_constructed
->claims_count
];
1157 ret
= fill_claim_entry(ad_sourced_constructed
->claim_entries
,
1160 principal_attribute
,
1162 ad_claims
[i
].syntax
,
1163 ad_claims
[i
].claim_type
,
1165 if (ret
!= LDB_SUCCESS
) {
1166 talloc_free(tmp_ctx
);
1170 if (claim_get_value_count(claim_entry
) > 0) {
1172 * If the claim contains values, add it to the
1175 ++ad_sourced_constructed
->claims_count
;
1176 claims_set
->claims_array_count
= new_claims_array_count
;
1181 if (claims_set
->claims_array_count
) {
1182 *claims_set_out
= talloc_steal(mem_ctx
, claims_set
);
1185 talloc_free(tmp_ctx
);
1189 int get_claims_set_for_principal(struct ldb_context
*ldb
,
1190 TALLOC_CTX
*mem_ctx
,
1191 const struct ldb_message
*principal
,
1192 struct CLAIMS_SET
**claims_set_out
)
1194 struct ldb_message_element
*principal_class_el
= NULL
;
1195 struct dsdb_schema
*schema
= NULL
;
1196 const struct dsdb_class
*principal_class
= NULL
;
1198 *claims_set_out
= NULL
;
1200 if (!ad_claims_are_issued(ldb
)) {
1204 principal_class_el
= ldb_msg_find_element(principal
,
1206 if (principal_class_el
== NULL
) {
1207 return ldb_operr(ldb
);
1210 schema
= dsdb_get_schema(ldb
, mem_ctx
);
1211 if (schema
== NULL
) {
1212 return ldb_operr(ldb
);
1215 principal_class
= dsdb_get_last_structural_class(schema
, principal_class_el
);
1216 if (principal_class
== NULL
) {
1217 return ldb_operr(ldb
);
1220 return get_all_claims(ldb
,
1223 principal_class
->governsID_id
,