ctdb-scripts: Move connection tracking to 10.interface
[samba4-gss.git] / source4 / kdc / ad_claims.c
blob1f3df007f3634afbe403efe352b1210455cb9c39
1 /*
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"
36 #undef strcasecmp
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,
59 const char **attrs,
60 unsigned *ad_claim_attrs_count,
61 const char *attr)
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,
68 count,
69 attr,
70 acl_attr_cmp_fn,
71 exact,
72 next);
73 if (exact != NULL) {
74 /* The attribute is already present; there's nothing to do. */
75 return LDB_SUCCESS;
78 /* Make sure we don't overflow the array. */
79 SMB_ASSERT(count < talloc_array_length(attrs));
80 *ad_claim_attrs_count = count + 1;
82 if (next == NULL) {
83 /* Just add the new element on the end. */
84 attrs[count] = attr;
85 } else {
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],
90 &attrs[next_idx],
91 bytes_to_move);
93 attrs[next_idx] = attr;
96 return LDB_SUCCESS;
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) {
109 return false;
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)
121 uint32_t i;
123 claim->value_count = 0;
124 claim->values = talloc_array(mem_ctx,
125 int64_t,
126 principal_attribute->num_values);
127 if (claim->values == NULL) {
128 return ldb_oom(ldb);
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]);
134 if (ret) {
135 char buf[1024];
136 const char *reason = NULL;
137 int err = strerror_r(ret, buf, sizeof(buf));
138 if (err == 0) {
139 reason = buf;
140 } else {
141 reason = "Unknown error";
143 DBG_WARNING("Failed to interpret value %s as INT64 "
144 "while creating claim %s for attribute %s (%s); "
145 "skipping value\n",
146 (value->data != NULL) ? (const char *)value->data : "<unknown>",
147 name.data, principal_attribute->name,
148 reason);
149 continue;
152 ++claim->value_count;
155 /* Shrink the array to fit. */
156 claim->values = talloc_realloc(mem_ctx,
157 claim->values,
158 int64_t,
159 claim->value_count);
160 if (claim->value_count && claim->values == NULL) {
161 return ldb_oom(ldb);
164 return LDB_SUCCESS;
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)
173 uint32_t i;
175 claim->value_count = 0;
176 claim->values = talloc_array(mem_ctx,
177 uint64_t,
178 principal_attribute->num_values);
179 if (claim->values == NULL) {
180 return ldb_oom(ldb);
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]);
186 if (ret) {
187 char buf[1024];
188 const char *reason = NULL;
189 int err = strerror_r(ret, buf, sizeof(buf));
190 if (err == 0) {
191 reason = buf;
192 } else {
193 reason = "Unknown error";
195 DBG_WARNING("Failed to interpret value %s as UINT64 "
196 "while creating claim %s for attribute %s (%s); "
197 "skipping value\n",
198 (value->data != NULL) ? (const char *)value->data : "<unknown>",
199 name.data, principal_attribute->name,
200 reason);
201 continue;
204 ++claim->value_count;
207 /* Shrink the array to fit. */
208 claim->values = talloc_realloc(mem_ctx,
209 claim->values,
210 uint64_t,
211 claim->value_count);
212 if (claim->value_count && claim->values == NULL) {
213 return ldb_oom(ldb);
216 return LDB_SUCCESS;
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)
226 uint32_t i;
228 claim->value_count = 0;
229 claim->values = talloc_array(mem_ctx,
230 uint64_t,
231 principal_attribute->num_values);
232 if (claim->values == NULL) {
233 return ldb_oom(ldb);
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
242 * order.
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; "
251 "skipping value\n",
252 (display_name->data != NULL) ? (const char *)display_name->data : "<unknown>",
253 name.data, principal_attribute->name);
254 continue;
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,
263 claim->values,
264 uint64_t,
265 claim->value_count);
266 if (claim->value_count && claim->values == NULL) {
267 return ldb_oom(ldb);
270 return LDB_SUCCESS;
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)
279 uint32_t i;
281 claim->value_count = 0;
282 claim->values = talloc_array(mem_ctx,
283 uint64_t,
284 principal_attribute->num_values);
285 if (claim->values == NULL) {
286 return ldb_oom(ldb);
289 for (i = 0; i < principal_attribute->num_values; ++i) {
290 const struct ldb_val *value = &principal_attribute->values[i];
291 bool val = false;
292 int ret = ldb_val_as_bool(value, &val);
293 if (ret) {
294 char buf[1024];
295 const char *reason = NULL;
296 int err = strerror_r(ret, buf, sizeof(buf));
297 if (err == 0) {
298 reason = buf;
299 } else {
300 reason = "Unknown error";
302 DBG_WARNING("Failed to interpret value %s as BOOL "
303 "while creating claim %s for attribute %s (%s); "
304 "skipping value\n",
305 (value->data != NULL) ? (const char *)value->data : "<unknown>",
306 name.data, principal_attribute->name,
307 reason);
308 continue;
311 claim->values[i] = val;
312 ++claim->value_count;
315 /* Shrink the array to fit. */
316 claim->values = talloc_realloc(mem_ctx,
317 claim->values,
318 uint64_t,
319 claim->value_count);
320 if (claim->value_count && claim->values == NULL) {
321 return ldb_oom(ldb);
324 return LDB_SUCCESS;
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)
332 uint32_t i;
334 claim->value_count = 0;
335 claim->values = talloc_array(mem_ctx,
336 const char *,
337 principal_attribute->num_values);
338 if (claim->values == NULL) {
339 return ldb_oom(ldb);
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) {
347 continue;
350 val = talloc_strndup(claim->values,
351 (const char *)v->data,
352 v->length);
353 if (val == NULL) {
354 return ldb_oom(ldb);
357 claim->values[i] = val;
358 ++claim->value_count;
361 /* Shrink the array to fit. */
362 claim->values = talloc_realloc(mem_ctx,
363 claim->values,
364 const char *,
365 claim->value_count);
366 if (claim->value_count && claim->values == NULL) {
367 return ldb_oom(ldb);
370 return LDB_SUCCESS;
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;
380 uint32_t i;
382 claim->value_count = 0;
383 claim->values = talloc_array(mem_ctx,
384 const char *,
385 principal_attribute->num_values);
386 if (claim->values == NULL) {
387 return ldb_oom(ldb);
390 domain_sid = samdb_domain_sid(ldb);
391 if (domain_sid == NULL) {
392 return ldb_oom(ldb);
395 tmp_ctx = talloc_new(mem_ctx);
396 if (tmp_ctx == NULL) {
397 return ldb_oom(ldb);
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) {
408 continue;
411 ndr_err = ndr_pull_struct_blob(v,
412 tmp_ctx,
413 &desc,
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,
424 &desc,
425 domain_sid);
426 if (sddl == NULL) {
427 talloc_free(tmp_ctx);
428 return ldb_oom(ldb);
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,
439 claim->values,
440 const char *,
441 claim->value_count);
442 if (claim->value_count && claim->values == NULL) {
443 return ldb_oom(ldb);
446 return LDB_SUCCESS;
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,
461 name.length);
462 if (claim_entry->id == NULL) {
463 return ldb_oom(ldb);
466 claim_entry->type = claim_type;
468 switch (claim_type) {
469 case CLAIM_TYPE_INT64:
470 return fill_claim_int64(mem_ctx,
471 ldb,
472 principal_attribute,
473 name,
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,
478 ldb,
479 schema,
480 principal_attribute,
481 name,
482 &claim_entry->values.claim_uint64);
483 } else {
484 return fill_claim_uint64(mem_ctx,
485 ldb,
486 principal_attribute,
487 name,
488 &claim_entry->values.claim_uint64);
490 case CLAIM_TYPE_BOOLEAN:
491 return fill_claim_boolean(mem_ctx,
492 ldb,
493 principal_attribute,
494 name,
495 &claim_entry->values.claim_boolean);
496 case CLAIM_TYPE_STRING:
497 default:
498 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.15")) {
499 return fill_claim_string_sec_desc_syntax(mem_ctx,
500 ldb,
501 principal_attribute,
502 &claim_entry->values.claim_string);
503 } else {
504 return fill_claim_string(mem_ctx,
505 ldb,
506 principal_attribute,
507 &claim_entry->values.claim_string);
513 * Determine whether a claim applies to the most specific objectClass of the
514 * principal.
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,
521 bool *applies)
523 struct ldb_message_element *applies_to_class = NULL;
524 unsigned i;
526 applies_to_class = ldb_msg_find_element(claim_msg,
527 "msDS-ClaimTypeAppliesToClass");
528 if (applies_to_class == NULL) {
529 *applies = false;
530 return LDB_SUCCESS;
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,
539 ldb,
540 &applies_to_class->values[i]);
541 if (class_dn == NULL) {
542 return ldb_oom(ldb);
545 class_rdn = ldb_dn_get_rdn_val(class_dn);
546 if (class_rdn == NULL) {
547 TALLOC_FREE(class_dn);
548 continue;
551 class_val = dsdb_class_by_cn_ldb_val(schema, class_rdn);
552 TALLOC_FREE(class_dn);
553 if (class_val == NULL) {
554 continue;
557 if (class_val->governsID_id == principal_class_id) {
558 *applies = true;
559 return LDB_SUCCESS;
563 *applies = false;
564 return LDB_SUCCESS;
567 struct assigned_silo {
568 const char *name;
569 bool is_initialised;
570 bool is_assigned;
573 static struct assigned_silo new_assigned_silo(void)
575 return (struct assigned_silo) {
576 .name = NULL,
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,
588 TALLOC_CTX *mem_ctx,
589 const struct ldb_message *principal,
590 struct assigned_silo *assigned_silo)
592 TALLOC_CTX *tmp_ctx = NULL;
593 int ret;
595 const struct ldb_message *silo_msg = NULL;
596 static const char * const silo_attrs[] = {
597 "msDS-AuthNPolicySiloEnforced",
598 "msDS-AuthNPolicySiloMembers",
599 "name",
600 NULL
603 bool is_silo_enforced = false;
604 const char *silo_name = NULL;
606 if (assigned_silo->is_initialised) {
607 return LDB_SUCCESS;
610 tmp_ctx = talloc_new(mem_ctx);
611 if (tmp_ctx == NULL) {
612 return ldb_oom(ldb);
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);
621 return LDB_SUCCESS;
624 /* Check whether the user is assigned to an enforced silo. */
625 ret = authn_policy_get_assigned_silo(ldb,
626 tmp_ctx,
627 principal,
628 silo_attrs,
629 &silo_msg,
630 &is_silo_enforced);
631 if (ret) {
632 talloc_free(tmp_ctx);
633 return ret;
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);
642 return LDB_SUCCESS;
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,
647 "name",
648 NULL);
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);
654 return LDB_SUCCESS;
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);
660 return val;
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");
677 return 0;
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)) {
684 return false;
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")) {
696 return true;
698 if (data_blob_equals_str(source_syntax, "2.5.5.12")) {
699 return true;
701 if (data_blob_equals_str(source_syntax, "2.5.5.15")) {
702 return true;
704 break;
705 case CLAIM_TYPE_UINT64:
706 if (data_blob_equals_str(source_syntax, "2.5.5.2")) {
707 return true;
709 break;
710 case CLAIM_TYPE_INT64:
711 if (data_blob_equals_str(source_syntax, "2.5.5.9")) {
712 return true;
714 if (data_blob_equals_str(source_syntax, "2.5.5.16")) {
715 return true;
717 break;
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")) {
721 return true;
723 break;
724 default:
725 break;
728 return false;
731 static int get_all_claims(struct ldb_context *ldb,
732 TALLOC_CTX *mem_ctx,
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);
745 bool ok;
746 int ret;
747 struct ldb_result *res = NULL;
748 static const char * const attrs[] = {
749 "Enabled",
750 "msDS-ClaimAttributeSource",
751 "msDS-ClaimSource",
752 "msDS-ClaimSourceType",
753 "msDS-ClaimTypeAppliesToClass",
754 "msDS-ClaimValueType",
755 "name",
756 NULL
759 const char **ad_claim_attrs = NULL;
760 unsigned int ad_claim_attrs_count;
761 struct ad_claim_info {
762 struct ldb_val name;
763 DATA_BLOB syntax;
764 const char *attribute;
765 enum CLAIM_TYPE claim_type;
766 } *ad_claims = NULL;
767 unsigned ad_claims_count;
769 unsigned i;
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) {
782 return ldb_oom(ldb);
785 claims_set = talloc_zero(tmp_ctx, struct CLAIMS_SET);
786 if (claims_set == NULL) {
787 talloc_free(tmp_ctx);
788 return ldb_oom(ldb);
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);
801 return ldb_oom(ldb);
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);
808 return ldb_oom(ldb);
811 ok = ldb_dn_add_child(claim_config_container, claim_types_child);
812 TALLOC_FREE(claim_types_child);
813 if (!ok) {
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,
821 LDB_SCOPE_ONELEVEL,
822 attrs, NULL);
823 if (ret) {
824 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
825 ret = LDB_SUCCESS;
828 talloc_free(tmp_ctx);
829 return ret;
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
835 * LDB search).
837 ad_claim_attrs = talloc_array(tmp_ctx,
838 const char *,
839 res->count + 1);
840 if (ad_claim_attrs == NULL) {
841 talloc_free(tmp_ctx);
842 return ldb_oom(ldb);
844 ad_claims = talloc_array(tmp_ctx,
845 struct ad_claim_info,
846 res->count);
847 if (ad_claims == NULL) {
848 talloc_free(tmp_ctx);
849 return ldb_oom(ldb);
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;
857 int enabled;
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
866 * principal?
868 ret = claim_applies_to_class(tmp_ctx,
869 ldb,
870 schema,
871 res->msgs[i],
872 principal_class_id,
873 &claim_applies);
874 if (ret) {
875 talloc_free(tmp_ctx);
876 return ret;
878 if (!claim_applies) {
879 /* If the claim doesn't apply, skip it. */
880 continue;
883 enabled = ldb_msg_find_attr_as_bool(res->msgs[i], "Enabled", 0);
884 if (!enabled) {
885 /* If the claim isn't enabled, skip it. */
886 continue;
889 claim_value_type = ldb_msg_find_attr_as_uint64(res->msgs[i],
890 "msDS-ClaimValueType",
892 if (!claim_value_type) {
893 continue;
896 claim_source_type = ldb_msg_find_attr_as_string(res->msgs[i],
897 "msDS-ClaimSourceType",
898 "");
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],
905 "msDS-ClaimSource",
906 NULL);
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) {
918 continue;
921 claim_attribute_source_dn = ldb_val_as_dn(ldb,
922 tmp_ctx,
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. */
931 continue;
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. */
937 continue;
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) {
945 continue;
948 source_syntax = data_blob_string_const(claim_attribute_source_class->attributeSyntax_oid);
949 if (source_syntax.data == NULL) {
950 continue;
953 if (!is_valid_claim_attribute_syntax(source_syntax, claim_value_type)) {
954 continue;
957 attribute = claim_attribute_source_class->lDAPDisplayName;
958 if (attribute == NULL) {
959 continue;
962 ret = add_attr_unique(tmp_ctx,
963 ad_claim_attrs,
964 &ad_claim_attrs_count,
965 attribute);
966 if (ret) {
967 talloc_free(tmp_ctx);
968 return ret;
971 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
972 if (name == NULL) {
973 name = &data_blob_null;
976 ad_claims[ad_claims_count++] = (struct ad_claim_info) {
977 .name = *name,
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) {
991 continue;
994 if (claim_source != NULL) {
995 continue;
998 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
999 if (name == NULL || name->data == NULL) {
1000 continue;
1002 /* Does the claim ID match exactly in case? */
1003 if (strcmp((const char *)name->data, "ad://ext/AuthenticationSilo") != 0) {
1004 continue;
1007 ret = get_assigned_silo(ldb, tmp_ctx, principal, &assigned_silo);
1008 if (ret) {
1009 talloc_free(tmp_ctx);
1010 return ret;
1012 if (!assigned_silo.is_assigned) {
1013 continue;
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,
1036 struct CLAIM_ENTRY,
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,
1053 const char *,
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,
1075 ad_claim_attrs,
1076 const char *,
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,
1085 ad_claims,
1086 struct ad_claim_info,
1087 ad_claims_count);
1088 if (ad_claims == NULL) {
1089 talloc_free(tmp_ctx);
1090 return ldb_oom(ldb);
1093 ret = dsdb_search_one(ldb,
1094 tmp_ctx,
1095 &principal_msg,
1096 principal->dn,
1097 LDB_SCOPE_BASE,
1098 ad_claim_attrs,
1100 NULL);
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);
1106 return ret;
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) {
1124 continue;
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,
1148 struct CLAIM_ENTRY,
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,
1159 ldb,
1160 schema,
1161 principal_attribute,
1162 ad_claims[i].name,
1163 ad_claims[i].syntax,
1164 ad_claims[i].claim_type,
1165 claim_entry);
1166 if (ret != LDB_SUCCESS) {
1167 talloc_free(tmp_ctx);
1168 return ret;
1171 if (claim_get_value_count(claim_entry) > 0) {
1173 * If the claim contains values, add it to the
1174 * array(s).
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);
1187 return LDB_SUCCESS;
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)) {
1202 return LDB_SUCCESS;
1205 principal_class_el = ldb_msg_find_element(principal,
1206 "objectClass");
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,
1222 mem_ctx,
1223 principal,
1224 principal_class->governsID_id,
1225 claims_set_out);