pylibsmb: clang-format for the calls to Py_BuildValue()
[Samba.git] / source4 / kdc / ad_claims.c
blobb9a417c809a7e43679c5182bdb777661647e71fa
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"
35 #undef strcasecmp
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,
58 const char **attrs,
59 unsigned *ad_claim_attrs_count,
60 const char *attr)
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,
67 count,
68 attr,
69 acl_attr_cmp_fn,
70 exact,
71 next);
72 if (exact != NULL) {
73 /* The attribute is already present; there's nothing to do. */
74 return LDB_SUCCESS;
77 /* Make sure we don't overflow the array. */
78 SMB_ASSERT(count < talloc_array_length(attrs));
79 *ad_claim_attrs_count = count + 1;
81 if (next == NULL) {
82 /* Just add the new element on the end. */
83 attrs[count] = attr;
84 } else {
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],
89 &attrs[next_idx],
90 bytes_to_move);
92 attrs[next_idx] = attr;
95 return LDB_SUCCESS;
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) {
108 return false;
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)
120 uint32_t i;
122 claim->value_count = 0;
123 claim->values = talloc_array(mem_ctx,
124 int64_t,
125 principal_attribute->num_values);
126 if (claim->values == NULL) {
127 return ldb_oom(ldb);
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]);
133 if (ret) {
134 char buf[1024];
135 const char *reason = NULL;
136 int err = strerror_r(ret, buf, sizeof(buf));
137 if (err == 0) {
138 reason = buf;
139 } else {
140 reason = "Unknown error";
142 DBG_WARNING("Failed to interpret value %s as INT64 "
143 "while creating claim %s for attribute %s (%s); "
144 "skipping value\n",
145 (value->data != NULL) ? (const char *)value->data : "<unknown>",
146 name.data, principal_attribute->name,
147 reason);
148 continue;
151 ++claim->value_count;
154 /* Shrink the array to fit. */
155 claim->values = talloc_realloc(mem_ctx,
156 claim->values,
157 int64_t,
158 claim->value_count);
159 if (claim->value_count && claim->values == NULL) {
160 return ldb_oom(ldb);
163 return LDB_SUCCESS;
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)
172 uint32_t i;
174 claim->value_count = 0;
175 claim->values = talloc_array(mem_ctx,
176 uint64_t,
177 principal_attribute->num_values);
178 if (claim->values == NULL) {
179 return ldb_oom(ldb);
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]);
185 if (ret) {
186 char buf[1024];
187 const char *reason = NULL;
188 int err = strerror_r(ret, buf, sizeof(buf));
189 if (err == 0) {
190 reason = buf;
191 } else {
192 reason = "Unknown error";
194 DBG_WARNING("Failed to interpret value %s as UINT64 "
195 "while creating claim %s for attribute %s (%s); "
196 "skipping value\n",
197 (value->data != NULL) ? (const char *)value->data : "<unknown>",
198 name.data, principal_attribute->name,
199 reason);
200 continue;
203 ++claim->value_count;
206 /* Shrink the array to fit. */
207 claim->values = talloc_realloc(mem_ctx,
208 claim->values,
209 uint64_t,
210 claim->value_count);
211 if (claim->value_count && claim->values == NULL) {
212 return ldb_oom(ldb);
215 return LDB_SUCCESS;
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)
225 uint32_t i;
227 claim->value_count = 0;
228 claim->values = talloc_array(mem_ctx,
229 uint64_t,
230 principal_attribute->num_values);
231 if (claim->values == NULL) {
232 return ldb_oom(ldb);
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
241 * order.
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; "
250 "skipping value\n",
251 (display_name->data != NULL) ? (const char *)display_name->data : "<unknown>",
252 name.data, principal_attribute->name);
253 continue;
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,
262 claim->values,
263 uint64_t,
264 claim->value_count);
265 if (claim->value_count && claim->values == NULL) {
266 return ldb_oom(ldb);
269 return LDB_SUCCESS;
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)
278 uint32_t i;
280 claim->value_count = 0;
281 claim->values = talloc_array(mem_ctx,
282 uint64_t,
283 principal_attribute->num_values);
284 if (claim->values == NULL) {
285 return ldb_oom(ldb);
288 for (i = 0; i < principal_attribute->num_values; ++i) {
289 const struct ldb_val *value = &principal_attribute->values[i];
290 bool val = false;
291 int ret = ldb_val_as_bool(value, &val);
292 if (ret) {
293 char buf[1024];
294 const char *reason = NULL;
295 int err = strerror_r(ret, buf, sizeof(buf));
296 if (err == 0) {
297 reason = buf;
298 } else {
299 reason = "Unknown error";
301 DBG_WARNING("Failed to interpret value %s as BOOL "
302 "while creating claim %s for attribute %s (%s); "
303 "skipping value\n",
304 (value->data != NULL) ? (const char *)value->data : "<unknown>",
305 name.data, principal_attribute->name,
306 reason);
307 continue;
310 claim->values[i] = val;
311 ++claim->value_count;
314 /* Shrink the array to fit. */
315 claim->values = talloc_realloc(mem_ctx,
316 claim->values,
317 uint64_t,
318 claim->value_count);
319 if (claim->value_count && claim->values == NULL) {
320 return ldb_oom(ldb);
323 return LDB_SUCCESS;
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)
331 uint32_t i;
333 claim->value_count = 0;
334 claim->values = talloc_array(mem_ctx,
335 const char *,
336 principal_attribute->num_values);
337 if (claim->values == NULL) {
338 return ldb_oom(ldb);
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) {
346 continue;
349 val = talloc_strndup(claim->values,
350 (const char *)v->data,
351 v->length);
352 if (val == NULL) {
353 return ldb_oom(ldb);
356 claim->values[i] = val;
357 ++claim->value_count;
360 /* Shrink the array to fit. */
361 claim->values = talloc_realloc(mem_ctx,
362 claim->values,
363 const char *,
364 claim->value_count);
365 if (claim->value_count && claim->values == NULL) {
366 return ldb_oom(ldb);
369 return LDB_SUCCESS;
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;
379 uint32_t i;
381 claim->value_count = 0;
382 claim->values = talloc_array(mem_ctx,
383 const char *,
384 principal_attribute->num_values);
385 if (claim->values == NULL) {
386 return ldb_oom(ldb);
389 domain_sid = samdb_domain_sid(ldb);
390 if (domain_sid == NULL) {
391 return ldb_oom(ldb);
394 tmp_ctx = talloc_new(mem_ctx);
395 if (tmp_ctx == NULL) {
396 return ldb_oom(ldb);
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) {
407 continue;
410 ndr_err = ndr_pull_struct_blob(v,
411 tmp_ctx,
412 &desc,
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,
423 &desc,
424 domain_sid);
425 if (sddl == NULL) {
426 talloc_free(tmp_ctx);
427 return ldb_oom(ldb);
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,
438 claim->values,
439 const char *,
440 claim->value_count);
441 if (claim->value_count && claim->values == NULL) {
442 return ldb_oom(ldb);
445 return LDB_SUCCESS;
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,
460 name.length);
461 if (claim_entry->id == NULL) {
462 return ldb_oom(ldb);
465 claim_entry->type = claim_type;
467 switch (claim_type) {
468 case CLAIM_TYPE_INT64:
469 return fill_claim_int64(mem_ctx,
470 ldb,
471 principal_attribute,
472 name,
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,
477 ldb,
478 schema,
479 principal_attribute,
480 name,
481 &claim_entry->values.claim_uint64);
482 } else {
483 return fill_claim_uint64(mem_ctx,
484 ldb,
485 principal_attribute,
486 name,
487 &claim_entry->values.claim_uint64);
489 case CLAIM_TYPE_BOOLEAN:
490 return fill_claim_boolean(mem_ctx,
491 ldb,
492 principal_attribute,
493 name,
494 &claim_entry->values.claim_boolean);
495 case CLAIM_TYPE_STRING:
496 default:
497 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.15")) {
498 return fill_claim_string_sec_desc_syntax(mem_ctx,
499 ldb,
500 principal_attribute,
501 &claim_entry->values.claim_string);
502 } else {
503 return fill_claim_string(mem_ctx,
504 ldb,
505 principal_attribute,
506 &claim_entry->values.claim_string);
512 * Determine whether a claim applies to the most specific objectClass of the
513 * principal.
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,
520 bool *applies)
522 struct ldb_message_element *applies_to_class = NULL;
523 unsigned i;
525 applies_to_class = ldb_msg_find_element(claim_msg,
526 "msDS-ClaimTypeAppliesToClass");
527 if (applies_to_class == NULL) {
528 *applies = false;
529 return LDB_SUCCESS;
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,
538 ldb,
539 &applies_to_class->values[i]);
540 if (class_dn == NULL) {
541 return ldb_oom(ldb);
544 class_rdn = ldb_dn_get_rdn_val(class_dn);
545 if (class_rdn == NULL) {
546 TALLOC_FREE(class_dn);
547 continue;
550 class_val = dsdb_class_by_cn_ldb_val(schema, class_rdn);
551 TALLOC_FREE(class_dn);
552 if (class_val == NULL) {
553 continue;
556 if (class_val->governsID_id == principal_class_id) {
557 *applies = true;
558 return LDB_SUCCESS;
562 *applies = false;
563 return LDB_SUCCESS;
566 struct assigned_silo {
567 const char *name;
568 bool is_initialised;
569 bool is_assigned;
572 static struct assigned_silo new_assigned_silo(void)
574 return (struct assigned_silo) {
575 .name = NULL,
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,
587 TALLOC_CTX *mem_ctx,
588 const struct ldb_message *principal,
589 struct assigned_silo *assigned_silo)
591 TALLOC_CTX *tmp_ctx = NULL;
592 int ret;
594 const struct ldb_message *silo_msg = NULL;
595 static const char * const silo_attrs[] = {
596 "msDS-AuthNPolicySiloEnforced",
597 "msDS-AuthNPolicySiloMembers",
598 "name",
599 NULL
602 bool is_silo_enforced = false;
603 const char *silo_name = NULL;
605 if (assigned_silo->is_initialised) {
606 return LDB_SUCCESS;
609 tmp_ctx = talloc_new(mem_ctx);
610 if (tmp_ctx == NULL) {
611 return ldb_oom(ldb);
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);
620 return LDB_SUCCESS;
623 /* Check whether the user is assigned to an enforced silo. */
624 ret = authn_policy_get_assigned_silo(ldb,
625 tmp_ctx,
626 principal,
627 silo_attrs,
628 &silo_msg,
629 &is_silo_enforced);
630 if (ret) {
631 talloc_free(tmp_ctx);
632 return ret;
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);
641 return LDB_SUCCESS;
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,
646 "name",
647 NULL);
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);
653 return LDB_SUCCESS;
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);
659 return val;
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");
676 return 0;
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)) {
683 return false;
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")) {
695 return true;
697 if (data_blob_equals_str(source_syntax, "2.5.5.12")) {
698 return true;
700 if (data_blob_equals_str(source_syntax, "2.5.5.15")) {
701 return true;
703 break;
704 case CLAIM_TYPE_UINT64:
705 if (data_blob_equals_str(source_syntax, "2.5.5.2")) {
706 return true;
708 break;
709 case CLAIM_TYPE_INT64:
710 if (data_blob_equals_str(source_syntax, "2.5.5.9")) {
711 return true;
713 if (data_blob_equals_str(source_syntax, "2.5.5.16")) {
714 return true;
716 break;
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")) {
720 return true;
722 break;
723 default:
724 break;
727 return false;
730 static int get_all_claims(struct ldb_context *ldb,
731 TALLOC_CTX *mem_ctx,
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);
744 bool ok;
745 int ret;
746 struct ldb_result *res = NULL;
747 static const char * const attrs[] = {
748 "Enabled",
749 "msDS-ClaimAttributeSource",
750 "msDS-ClaimSource",
751 "msDS-ClaimSourceType",
752 "msDS-ClaimTypeAppliesToClass",
753 "msDS-ClaimValueType",
754 "name",
755 NULL
758 const char **ad_claim_attrs = NULL;
759 unsigned int ad_claim_attrs_count;
760 struct ad_claim_info {
761 struct ldb_val name;
762 DATA_BLOB syntax;
763 const char *attribute;
764 enum CLAIM_TYPE claim_type;
765 } *ad_claims = NULL;
766 unsigned ad_claims_count;
768 unsigned i;
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) {
781 return ldb_oom(ldb);
784 claims_set = talloc_zero(tmp_ctx, struct CLAIMS_SET);
785 if (claims_set == NULL) {
786 talloc_free(tmp_ctx);
787 return ldb_oom(ldb);
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);
800 return ldb_oom(ldb);
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);
807 return ldb_oom(ldb);
810 ok = ldb_dn_add_child(claim_config_container, claim_types_child);
811 TALLOC_FREE(claim_types_child);
812 if (!ok) {
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,
820 LDB_SCOPE_ONELEVEL,
821 attrs, NULL);
822 if (ret) {
823 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
824 ret = LDB_SUCCESS;
827 talloc_free(tmp_ctx);
828 return ret;
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
834 * LDB search).
836 ad_claim_attrs = talloc_array(tmp_ctx,
837 const char *,
838 res->count + 1);
839 if (ad_claim_attrs == NULL) {
840 talloc_free(tmp_ctx);
841 return ldb_oom(ldb);
843 ad_claims = talloc_array(tmp_ctx,
844 struct ad_claim_info,
845 res->count);
846 if (ad_claims == NULL) {
847 talloc_free(tmp_ctx);
848 return ldb_oom(ldb);
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;
856 int enabled;
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
865 * principal?
867 ret = claim_applies_to_class(tmp_ctx,
868 ldb,
869 schema,
870 res->msgs[i],
871 principal_class_id,
872 &claim_applies);
873 if (ret) {
874 talloc_free(tmp_ctx);
875 return ret;
877 if (!claim_applies) {
878 /* If the claim doesn't apply, skip it. */
879 continue;
882 enabled = ldb_msg_find_attr_as_bool(res->msgs[i], "Enabled", 0);
883 if (!enabled) {
884 /* If the claim isn't enabled, skip it. */
885 continue;
888 claim_value_type = ldb_msg_find_attr_as_uint64(res->msgs[i],
889 "msDS-ClaimValueType",
891 if (!claim_value_type) {
892 continue;
895 claim_source_type = ldb_msg_find_attr_as_string(res->msgs[i],
896 "msDS-ClaimSourceType",
897 "");
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],
904 "msDS-ClaimSource",
905 NULL);
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) {
917 continue;
920 claim_attribute_source_dn = ldb_val_as_dn(ldb,
921 tmp_ctx,
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. */
930 continue;
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. */
936 continue;
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) {
944 continue;
947 source_syntax = data_blob_string_const(claim_attribute_source_class->attributeSyntax_oid);
948 if (source_syntax.data == NULL) {
949 continue;
952 if (!is_valid_claim_attribute_syntax(source_syntax, claim_value_type)) {
953 continue;
956 attribute = claim_attribute_source_class->lDAPDisplayName;
957 if (attribute == NULL) {
958 continue;
961 ret = add_attr_unique(tmp_ctx,
962 ad_claim_attrs,
963 &ad_claim_attrs_count,
964 attribute);
965 if (ret) {
966 talloc_free(tmp_ctx);
967 return ret;
970 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
971 if (name == NULL) {
972 name = &data_blob_null;
975 ad_claims[ad_claims_count++] = (struct ad_claim_info) {
976 .name = *name,
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) {
990 continue;
993 if (claim_source != NULL) {
994 continue;
997 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
998 if (name == NULL || name->data == NULL) {
999 continue;
1001 /* Does the claim ID match exactly in case? */
1002 if (strcmp((const char *)name->data, "ad://ext/AuthenticationSilo") != 0) {
1003 continue;
1006 ret = get_assigned_silo(ldb, tmp_ctx, principal, &assigned_silo);
1007 if (ret) {
1008 talloc_free(tmp_ctx);
1009 return ret;
1011 if (!assigned_silo.is_assigned) {
1012 continue;
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,
1035 struct CLAIM_ENTRY,
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,
1052 const char *,
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,
1074 ad_claim_attrs,
1075 const char *,
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,
1084 ad_claims,
1085 struct ad_claim_info,
1086 ad_claims_count);
1087 if (ad_claims == NULL) {
1088 talloc_free(tmp_ctx);
1089 return ldb_oom(ldb);
1092 ret = dsdb_search_one(ldb,
1093 tmp_ctx,
1094 &principal_msg,
1095 principal->dn,
1096 LDB_SCOPE_BASE,
1097 ad_claim_attrs,
1099 NULL);
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);
1105 return ret;
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) {
1123 continue;
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,
1147 struct CLAIM_ENTRY,
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,
1158 ldb,
1159 schema,
1160 principal_attribute,
1161 ad_claims[i].name,
1162 ad_claims[i].syntax,
1163 ad_claims[i].claim_type,
1164 claim_entry);
1165 if (ret != LDB_SUCCESS) {
1166 talloc_free(tmp_ctx);
1167 return ret;
1170 if (claim_get_value_count(claim_entry) > 0) {
1172 * If the claim contains values, add it to the
1173 * array(s).
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);
1186 return LDB_SUCCESS;
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)) {
1201 return LDB_SUCCESS;
1204 principal_class_el = ldb_msg_find_element(principal,
1205 "objectClass");
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,
1221 mem_ctx,
1222 principal,
1223 principal_class->governsID_id,
1224 claims_set_out);