ctdbd_conn: Add deregister_from_ctdbd()
[Samba.git] / source4 / kdc / ad_claims.c
blob109bb8a529b21f27c823aab7afa12a63ae70170b
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 "libcli/security/security.h"
28 #include "libcli/util/werror.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/samdb/ldb_modules/util.h"
31 #include "librpc/gen_ndr/claims.h"
32 #include "librpc/gen_ndr/ndr_claims.h"
33 #include "librpc/gen_ndr/krb5pac.h"
34 #include "librpc/gen_ndr/ndr_krb5pac.h"
35 #include "lzxpress_huffman.h"
36 #include "lib/util/binsearch.h"
38 #undef strcasecmp
40 bool ad_claims_are_issued(struct ldb_context *samdb)
43 * Claims aren’t issued by Samba unless the DC is at
44 * FL2012. This is to match Windows, which will offer
45 * this feature as soon as the DC is upgraded.
47 const int functional_level = dsdb_dc_functional_level(samdb);
48 return functional_level >= DS_DOMAIN_FUNCTION_2012;
51 static int acl_attr_cmp_fn(const char *a, const char * const *b)
53 return ldb_attr_cmp(a, *b);
57 * Add a single attribute to a list of attributes if it is not already
58 * present. The list is maintained in case-insensitive sorted order.
60 static int add_attr_unique(TALLOC_CTX *mem_ctx,
61 const char **attrs,
62 unsigned *ad_claim_attrs_count,
63 const char *attr)
65 const unsigned count = *ad_claim_attrs_count;
66 const char * const *exact = NULL;
67 const char * const *next = NULL;
69 BINARY_ARRAY_SEARCH_GTE(attrs,
70 count,
71 attr,
72 acl_attr_cmp_fn,
73 exact,
74 next);
75 if (exact != NULL) {
76 /* The attribute is already present; there's nothing to do. */
77 return LDB_SUCCESS;
80 /* Make sure we don't overflow the array. */
81 SMB_ASSERT(count < talloc_array_length(attrs));
82 *ad_claim_attrs_count = count + 1;
84 if (next == NULL) {
85 /* Just add the new element on the end. */
86 attrs[count] = attr;
87 } else {
88 /* Shift all following elements over to make room. */
89 size_t next_idx = next - attrs;
90 size_t bytes_to_move = (count - next_idx) * sizeof (attrs[0]);
91 memmove(&attrs[next_idx + 1],
92 &attrs[next_idx],
93 bytes_to_move);
95 attrs[next_idx] = attr;
98 return LDB_SUCCESS;
102 * Return true if a data_blob, interpreted as a string, is equal to another
103 * string. This is more efficient than strcmp(), particularly when comparing
104 * against a string constant. This assumes the data_blob's length does not
105 * include the zero-terminator.
107 static inline bool data_blob_equals_str(const DATA_BLOB val, const char *str)
109 size_t len = strlen(str);
110 if (val.length != len) {
111 return false;
114 return memcmp(val.data, str, len) == 0;
117 static int fill_claim_int64(TALLOC_CTX *mem_ctx,
118 struct ldb_context *ldb,
119 const struct ldb_message_element *principal_attribute,
120 const struct ldb_val name,
121 struct CLAIM_INT64 *claim)
123 uint32_t i;
125 claim->value_count = 0;
126 claim->values = talloc_array(mem_ctx,
127 int64_t,
128 principal_attribute->num_values);
129 if (claim->values == NULL) {
130 return ldb_oom(ldb);
133 for (i = 0; i < principal_attribute->num_values; ++i) {
134 const struct ldb_val *value = &principal_attribute->values[i];
135 int ret = ldb_val_as_int64(value, &claim->values[i]);
136 if (ret) {
137 char buf[1024];
138 const char *reason = NULL;
139 int err = strerror_r(ret, buf, sizeof(buf));
140 if (err == 0) {
141 reason = buf;
142 } else {
143 reason = "Unknown error";
145 DBG_WARNING("Failed to interpret value %s as INT64 "
146 "while creating claim %s for attribute %s (%s); "
147 "skipping value\n",
148 (value->data != NULL) ? (const char *)value->data : "<unknown>",
149 name.data, principal_attribute->name,
150 reason);
151 continue;
154 ++claim->value_count;
157 /* Shrink the array to fit. */
158 claim->values = talloc_realloc(mem_ctx,
159 claim->values,
160 int64_t,
161 claim->value_count);
162 if (claim->value_count && claim->values == NULL) {
163 return ldb_oom(ldb);
166 return LDB_SUCCESS;
169 static int fill_claim_uint64(TALLOC_CTX *mem_ctx,
170 struct ldb_context *ldb,
171 const struct ldb_message_element *principal_attribute,
172 const struct ldb_val name,
173 struct CLAIM_UINT64 *claim)
175 uint32_t i;
177 claim->value_count = 0;
178 claim->values = talloc_array(mem_ctx,
179 uint64_t,
180 principal_attribute->num_values);
181 if (claim->values == NULL) {
182 return ldb_oom(ldb);
185 for (i = 0; i < principal_attribute->num_values; ++i) {
186 const struct ldb_val *value = &principal_attribute->values[i];
187 int ret = ldb_val_as_uint64(value, &claim->values[i]);
188 if (ret) {
189 char buf[1024];
190 const char *reason = NULL;
191 int err = strerror_r(ret, buf, sizeof(buf));
192 if (err == 0) {
193 reason = buf;
194 } else {
195 reason = "Unknown error";
197 DBG_WARNING("Failed to interpret value %s as UINT64 "
198 "while creating claim %s for attribute %s (%s); "
199 "skipping value\n",
200 (value->data != NULL) ? (const char *)value->data : "<unknown>",
201 name.data, principal_attribute->name,
202 reason);
203 continue;
206 ++claim->value_count;
209 /* Shrink the array to fit. */
210 claim->values = talloc_realloc(mem_ctx,
211 claim->values,
212 uint64_t,
213 claim->value_count);
214 if (claim->value_count && claim->values == NULL) {
215 return ldb_oom(ldb);
218 return LDB_SUCCESS;
221 static int fill_claim_uint64_oid_syntax(TALLOC_CTX *mem_ctx,
222 struct ldb_context *ldb,
223 const struct dsdb_schema *schema,
224 const struct ldb_message_element *principal_attribute,
225 const struct ldb_val name,
226 struct CLAIM_UINT64 *claim)
228 uint32_t i;
230 claim->value_count = 0;
231 claim->values = talloc_array(mem_ctx,
232 uint64_t,
233 principal_attribute->num_values);
234 if (claim->values == NULL) {
235 return ldb_oom(ldb);
238 for (i = 0; i < principal_attribute->num_values; ++i) {
239 const struct dsdb_class *class_val = NULL;
242 * OID values for objectClass
243 * are presented in reverse
244 * order.
246 const struct ldb_val *display_name = &principal_attribute->values[
247 principal_attribute->num_values - 1 - i];
249 class_val = dsdb_class_by_lDAPDisplayName_ldb_val(schema, display_name);
250 if (class_val == NULL) {
251 DBG_WARNING("Failed to look up OID for value %s "
252 "while creating claim %s for attribute %s; "
253 "skipping value\n",
254 (display_name->data != NULL) ? (const char *)display_name->data : "<unknown>",
255 name.data, principal_attribute->name);
256 continue;
259 claim->values[i] = class_val->governsID_id;
260 ++claim->value_count;
263 /* Shrink the array to fit. */
264 claim->values = talloc_realloc(mem_ctx,
265 claim->values,
266 uint64_t,
267 claim->value_count);
268 if (claim->value_count && claim->values == NULL) {
269 return ldb_oom(ldb);
272 return LDB_SUCCESS;
275 static int fill_claim_boolean(TALLOC_CTX *mem_ctx,
276 struct ldb_context *ldb,
277 const struct ldb_message_element *principal_attribute,
278 const struct ldb_val name,
279 struct CLAIM_UINT64 *claim)
281 uint32_t i;
283 claim->value_count = 0;
284 claim->values = talloc_array(mem_ctx,
285 uint64_t,
286 principal_attribute->num_values);
287 if (claim->values == NULL) {
288 return ldb_oom(ldb);
291 for (i = 0; i < principal_attribute->num_values; ++i) {
292 const struct ldb_val *value = &principal_attribute->values[i];
293 bool val = false;
294 int ret = ldb_val_as_bool(value, &val);
295 if (ret) {
296 char buf[1024];
297 const char *reason = NULL;
298 int err = strerror_r(ret, buf, sizeof(buf));
299 if (err == 0) {
300 reason = buf;
301 } else {
302 reason = "Unknown error";
304 DBG_WARNING("Failed to interpret value %s as BOOL "
305 "while creating claim %s for attribute %s (%s); "
306 "skipping value\n",
307 (value->data != NULL) ? (const char *)value->data : "<unknown>",
308 name.data, principal_attribute->name,
309 reason);
310 continue;
313 claim->values[i] = val;
314 ++claim->value_count;
317 /* Shrink the array to fit. */
318 claim->values = talloc_realloc(mem_ctx,
319 claim->values,
320 uint64_t,
321 claim->value_count);
322 if (claim->value_count && claim->values == NULL) {
323 return ldb_oom(ldb);
326 return LDB_SUCCESS;
329 static int fill_claim_string(TALLOC_CTX *mem_ctx,
330 struct ldb_context *ldb,
331 const struct ldb_message_element *principal_attribute,
332 struct CLAIM_STRING *claim)
334 uint32_t i;
336 claim->value_count = 0;
337 claim->values = talloc_array(mem_ctx,
338 const char *,
339 principal_attribute->num_values);
340 if (claim->values == NULL) {
341 return ldb_oom(ldb);
344 for (i = 0; i < principal_attribute->num_values; ++i) {
345 const char *val = NULL;
346 const struct ldb_val *v = &principal_attribute->values[i];
348 if (v == NULL || v->data == NULL) {
349 continue;
352 val = talloc_strndup(claim->values,
353 (const char *)v->data,
354 v->length);
355 if (val == NULL) {
356 return ldb_oom(ldb);
359 claim->values[i] = val;
360 ++claim->value_count;
363 /* Shrink the array to fit. */
364 claim->values = talloc_realloc(mem_ctx,
365 claim->values,
366 const char *,
367 claim->value_count);
368 if (claim->value_count && claim->values == NULL) {
369 return ldb_oom(ldb);
372 return LDB_SUCCESS;
375 static int fill_claim_string_sec_desc_syntax(TALLOC_CTX *mem_ctx,
376 struct ldb_context *ldb,
377 const struct ldb_message_element *principal_attribute,
378 struct CLAIM_STRING *claim)
380 TALLOC_CTX *tmp_ctx = NULL;
381 const struct dom_sid *domain_sid = NULL;
382 uint32_t i;
384 claim->value_count = 0;
385 claim->values = talloc_array(mem_ctx,
386 const char *,
387 principal_attribute->num_values);
388 if (claim->values == NULL) {
389 return ldb_oom(ldb);
392 domain_sid = samdb_domain_sid(ldb);
393 if (domain_sid == NULL) {
394 return ldb_oom(ldb);
397 tmp_ctx = talloc_new(mem_ctx);
398 if (tmp_ctx == NULL) {
399 return ldb_oom(ldb);
402 for (i = 0; i < principal_attribute->num_values; ++i) {
403 const struct ldb_val *v = &principal_attribute->values[i];
405 enum ndr_err_code ndr_err;
406 struct security_descriptor desc = {};
407 const char *sddl = NULL;
409 if (v == NULL || v->data == NULL) {
410 continue;
413 ndr_err = ndr_pull_struct_blob(v,
414 tmp_ctx,
415 &desc,
416 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
417 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
418 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
419 DBG_ERR("security_descriptor pull failed: %s\n",
420 nt_errstr(nt_status));
421 talloc_free(tmp_ctx);
422 return ldb_operr(ldb);
425 sddl = sddl_encode(mem_ctx,
426 &desc,
427 domain_sid);
428 if (sddl == NULL) {
429 talloc_free(tmp_ctx);
430 return ldb_oom(ldb);
433 claim->values[i] = sddl;
434 ++claim->value_count;
437 talloc_free(tmp_ctx);
439 /* Shrink the array to fit. */
440 claim->values = talloc_realloc(mem_ctx,
441 claim->values,
442 const char *,
443 claim->value_count);
444 if (claim->value_count && claim->values == NULL) {
445 return ldb_oom(ldb);
448 return LDB_SUCCESS;
451 static int fill_claim_entry(TALLOC_CTX *mem_ctx,
452 struct ldb_context *ldb,
453 const struct dsdb_schema *schema,
454 const struct ldb_message_element *principal_attribute,
455 const struct ldb_val name,
456 const DATA_BLOB syntax,
457 enum CLAIM_TYPE claim_type,
458 struct CLAIM_ENTRY *claim_entry)
461 claim_entry->id = (const char *)name.data;
462 claim_entry->type = claim_type;
464 switch (claim_type) {
465 case CLAIM_TYPE_INT64:
466 return fill_claim_int64(mem_ctx,
467 ldb,
468 principal_attribute,
469 name,
470 &claim_entry->values.claim_int64);
471 case CLAIM_TYPE_UINT64:
472 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.2")) {
473 return fill_claim_uint64_oid_syntax(mem_ctx,
474 ldb,
475 schema,
476 principal_attribute,
477 name,
478 &claim_entry->values.claim_uint64);
479 } else {
480 return fill_claim_uint64(mem_ctx,
481 ldb,
482 principal_attribute,
483 name,
484 &claim_entry->values.claim_uint64);
486 case CLAIM_TYPE_BOOLEAN:
487 return fill_claim_boolean(mem_ctx,
488 ldb,
489 principal_attribute,
490 name,
491 &claim_entry->values.claim_boolean);
492 case CLAIM_TYPE_STRING:
493 default:
494 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.15")) {
495 return fill_claim_string_sec_desc_syntax(mem_ctx,
496 ldb,
497 principal_attribute,
498 &claim_entry->values.claim_string);
499 } else {
500 return fill_claim_string(mem_ctx,
501 ldb,
502 principal_attribute,
503 &claim_entry->values.claim_string);
509 * Determine wheter a claim applies to the most specific objectClass of the
510 * principal.
512 static int claim_applies_to_class(TALLOC_CTX *mem_ctx,
513 struct ldb_context *ldb,
514 const struct dsdb_schema *schema,
515 const struct ldb_message *claim_msg,
516 const uint32_t principal_class_id,
517 bool *applies)
519 struct ldb_message_element *applies_to_class = NULL;
520 unsigned i;
522 applies_to_class = ldb_msg_find_element(claim_msg,
523 "msDS-ClaimTypeAppliesToClass");
524 if (applies_to_class == NULL) {
525 *applies = false;
526 return LDB_SUCCESS;
529 for (i = 0; i < applies_to_class->num_values; ++i) {
530 struct ldb_dn *class_dn = NULL;
531 const struct dsdb_class *class_val = NULL;
532 const struct ldb_val *class_rdn = NULL;
534 class_dn = ldb_dn_from_ldb_val(mem_ctx,
535 ldb,
536 &applies_to_class->values[i]);
537 if (class_dn == NULL) {
538 return ldb_oom(ldb);
541 class_rdn = ldb_dn_get_rdn_val(class_dn);
542 if (class_rdn == NULL) {
543 TALLOC_FREE(class_dn);
544 continue;
547 class_val = dsdb_class_by_cn_ldb_val(schema, class_rdn);
548 TALLOC_FREE(class_dn);
549 if (class_val == NULL) {
550 continue;
553 if (class_val->governsID_id == principal_class_id) {
554 *applies = true;
555 return LDB_SUCCESS;
559 *applies = false;
560 return LDB_SUCCESS;
563 struct assigned_silo {
564 const char *name;
565 bool is_initialised;
566 bool is_assigned;
569 static struct assigned_silo new_assigned_silo(void)
571 return (struct assigned_silo) {
572 .name = NULL,
573 .is_initialised = false,
574 .is_assigned = false,
578 static bool silo_is_maybe_assigned(struct assigned_silo silo)
580 return !silo.is_initialised || silo.is_assigned;
583 static int get_assigned_silo(struct ldb_context *ldb,
584 TALLOC_CTX *mem_ctx,
585 const struct ldb_message *principal,
586 struct assigned_silo *assigned_silo)
588 TALLOC_CTX *tmp_ctx = NULL;
589 int ret;
591 const struct ldb_message *silo_msg = NULL;
592 static const char * const silo_attrs[] = {
593 "msDS-AuthNPolicySiloEnforced",
594 "msDS-AuthNPolicySiloMembers",
595 "name",
596 NULL
599 bool is_silo_enforced = false;
600 const char *silo_name = NULL;
602 if (assigned_silo->is_initialised) {
603 return LDB_SUCCESS;
606 tmp_ctx = talloc_new(mem_ctx);
607 if (tmp_ctx == NULL) {
608 return ldb_oom(ldb);
611 if (!authn_policy_silos_and_policies_in_effect(ldb)) {
612 /* No assigned silo. */
613 assigned_silo->is_assigned = false;
614 assigned_silo->is_initialised = true;
616 talloc_free(tmp_ctx);
617 return LDB_SUCCESS;
620 /* Check whether the user is assigned to an enforced silo. */
621 ret = authn_policy_get_assigned_silo(ldb,
622 tmp_ctx,
623 principal,
624 silo_attrs,
625 &silo_msg,
626 &is_silo_enforced);
627 if (ret) {
628 talloc_free(tmp_ctx);
629 return ret;
632 if (silo_msg == NULL || !is_silo_enforced) {
633 /* No assigned silo. */
634 assigned_silo->is_assigned = false;
635 assigned_silo->is_initialised = true;
637 talloc_free(tmp_ctx);
638 return LDB_SUCCESS;
641 /* The user does belong to a silo, so return the name of the silo. */
642 silo_name = ldb_msg_find_attr_as_string(silo_msg,
643 "name",
644 NULL);
645 assigned_silo->name = talloc_steal(mem_ctx, silo_name);
646 assigned_silo->is_assigned = true;
647 assigned_silo->is_initialised = true;
649 talloc_free(tmp_ctx);
650 return LDB_SUCCESS;
653 static inline struct ldb_val talloc_steal_ldb_val(TALLOC_CTX *mem_ctx, struct ldb_val val)
655 val.data = talloc_steal(mem_ctx, val.data);
656 return val;
659 static uint32_t claim_get_value_count(const struct CLAIM_ENTRY *claim)
661 switch (claim->type) {
662 case CLAIM_TYPE_INT64:
663 return claim->values.claim_int64.value_count;
664 case CLAIM_TYPE_UINT64:
665 return claim->values.claim_uint64.value_count;
666 case CLAIM_TYPE_STRING:
667 return claim->values.claim_string.value_count;
668 case CLAIM_TYPE_BOOLEAN:
669 return claim->values.claim_boolean.value_count;
672 smb_panic(__location__ ": unknown claim type");
673 return 0;
676 static int encode_claims_set(struct ldb_context *ldb,
677 TALLOC_CTX *mem_ctx,
678 struct CLAIMS_SET *claims_set,
679 DATA_BLOB *claims_blob)
681 TALLOC_CTX *tmp_ctx = NULL;
682 enum ndr_err_code ndr_err;
683 struct CLAIMS_SET_NDR *claims_set_info = NULL;
684 struct CLAIMS_SET_METADATA *metadata = NULL;
685 struct CLAIMS_SET_METADATA_NDR *metadata_ndr = NULL;
687 tmp_ctx = talloc_new(mem_ctx);
688 if (tmp_ctx == NULL) {
689 return ldb_oom(ldb);
692 metadata_ndr = talloc_zero(tmp_ctx, struct CLAIMS_SET_METADATA_NDR);
693 if (metadata_ndr == NULL) {
694 talloc_free(tmp_ctx);
695 return ldb_oom(ldb);
698 metadata = talloc_zero(metadata_ndr, struct CLAIMS_SET_METADATA);
699 if (metadata == NULL) {
700 talloc_free(tmp_ctx);
701 return ldb_oom(ldb);
704 claims_set_info = talloc_zero(metadata, struct CLAIMS_SET_NDR);
705 if (claims_set_info == NULL) {
706 talloc_free(tmp_ctx);
707 return ldb_oom(ldb);
710 metadata_ndr->claims.metadata = metadata;
712 metadata->claims_set = claims_set_info;
713 metadata->compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF;
715 claims_set_info->claims.claims = claims_set;
717 ndr_err = ndr_push_struct_blob(claims_blob, mem_ctx, metadata_ndr,
718 (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_METADATA_NDR);
719 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
720 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
721 DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
722 nt_errstr(nt_status));
724 talloc_free(tmp_ctx);
725 return ldb_operr(ldb);
728 talloc_free(tmp_ctx);
729 return LDB_SUCCESS;
732 static bool is_schema_dn(struct ldb_dn *dn,
733 struct ldb_dn *schema_dn)
735 if (ldb_dn_get_comp_num(dn) != (ldb_dn_get_comp_num(schema_dn) + 1)) {
736 return false;
739 return ldb_dn_compare_base(schema_dn, dn) == 0;
742 static bool is_valid_claim_attribute_syntax(const DATA_BLOB source_syntax,
743 uint64_t claim_value_type)
745 switch (claim_value_type) {
746 case CLAIM_TYPE_STRING:
747 if (data_blob_equals_str(source_syntax, "2.5.5.1")) {
748 return true;
750 if (data_blob_equals_str(source_syntax, "2.5.5.12")) {
751 return true;
753 if (data_blob_equals_str(source_syntax, "2.5.5.15")) {
754 return true;
756 break;
757 case CLAIM_TYPE_UINT64:
758 if (data_blob_equals_str(source_syntax, "2.5.5.2")) {
759 return true;
761 break;
762 case CLAIM_TYPE_INT64:
763 if (data_blob_equals_str(source_syntax, "2.5.5.9")) {
764 return true;
766 if (data_blob_equals_str(source_syntax, "2.5.5.16")) {
767 return true;
769 break;
770 case CLAIM_TYPE_BOOLEAN:
771 /* Note: MS-ADTS has a typo (2.2.5.8 instead of 2.5.5.8) */
772 if (data_blob_equals_str(source_syntax, "2.5.5.8")) {
773 return true;
775 break;
776 default:
777 break;
780 return false;
783 static int get_all_claims(struct ldb_context *ldb,
784 TALLOC_CTX *mem_ctx,
785 const struct ldb_message *principal,
786 uint32_t principal_class_id,
787 DATA_BLOB *claims_blob)
789 TALLOC_CTX *tmp_ctx = NULL;
791 const struct dsdb_schema *schema = NULL;
793 struct ldb_dn *claim_config_container = NULL;
794 struct ldb_dn *claim_types_child = NULL;
795 struct ldb_dn *config_dn = ldb_get_config_basedn(ldb);
796 struct ldb_dn *schema_dn = ldb_get_schema_basedn(ldb);
797 bool ok;
798 int ret;
799 struct ldb_result *res = NULL;
800 static const char * const attrs[] = {
801 "Enabled",
802 "msDS-ClaimAttributeSource",
803 "msDS-ClaimSource",
804 "msDS-ClaimSourceType",
805 "msDS-ClaimTypeAppliesToClass",
806 "msDS-ClaimValueType",
807 "name",
808 NULL
811 const char **ad_claim_attrs = NULL;
812 unsigned int ad_claim_attrs_count;
813 struct ad_claim_info {
814 struct ldb_val name;
815 DATA_BLOB syntax;
816 const char *attribute;
817 enum CLAIM_TYPE claim_type;
818 } *ad_claims = NULL;
819 unsigned ad_claims_count;
821 unsigned i;
823 /* The structure which we'll use to build up the claims. */
824 struct CLAIMS_SET claims_set = {};
826 struct CLAIMS_ARRAY *ad_sourced_constructed = NULL;
828 struct assigned_silo assigned_silo = new_assigned_silo();
830 *claims_blob = data_blob_null;
832 tmp_ctx = talloc_new(mem_ctx);
833 if (tmp_ctx == NULL) {
834 return ldb_oom(ldb);
837 schema = dsdb_get_schema(ldb, tmp_ctx);
838 if (schema == NULL) {
839 talloc_free(tmp_ctx);
840 return ldb_operr(ldb);
843 /* Get the DN of the claims container. */
844 claim_config_container = ldb_dn_copy(tmp_ctx, config_dn);
845 if (claim_config_container == NULL) {
846 talloc_free(tmp_ctx);
847 return ldb_oom(ldb);
850 claim_types_child = ldb_dn_new(tmp_ctx, ldb,
851 "CN=Claim Types,CN=Claims Configuration,CN=Services");
852 if (claim_types_child == NULL) {
853 talloc_free(tmp_ctx);
854 return ldb_oom(ldb);
857 ok = ldb_dn_add_child(claim_config_container, claim_types_child);
858 TALLOC_FREE(claim_types_child);
859 if (!ok) {
860 talloc_free(tmp_ctx);
861 return ldb_operr(ldb);
864 /* Search for the claims container's children. */
865 ret = ldb_search(ldb, tmp_ctx, &res,
866 claim_config_container,
867 LDB_SCOPE_ONELEVEL,
868 attrs, NULL);
869 if (ret) {
870 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
871 ret = LDB_SUCCESS;
874 talloc_free(tmp_ctx);
875 return ret;
879 * Allocate enough space for all AD claim attributes, followed by space
880 * for a NULL marker (so it can be passed as the attributes filter to an
881 * LDB search).
883 ad_claim_attrs = talloc_array(tmp_ctx,
884 const char *,
885 res->count + 1);
886 if (ad_claim_attrs == NULL) {
887 talloc_free(tmp_ctx);
888 return ldb_oom(ldb);
890 ad_claims = talloc_array(tmp_ctx,
891 struct ad_claim_info,
892 res->count);
893 if (ad_claims == NULL) {
894 talloc_free(tmp_ctx);
895 return ldb_oom(ldb);
897 ad_claims_count = ad_claim_attrs_count = 0;
899 /* Loop through each child of the claims container. */
900 for (i = 0; i < res->count; ++i) {
901 bool claim_applies = false;
903 int enabled;
904 uint64_t claim_value_type;
906 const char *claim_source_type = NULL;
907 const struct ldb_val *claim_attribute_source = NULL;
908 const char *claim_source = NULL;
911 * Does this claim apply to the most specific objectClass of the
912 * principal?
914 ret = claim_applies_to_class(tmp_ctx,
915 ldb,
916 schema,
917 res->msgs[i],
918 principal_class_id,
919 &claim_applies);
920 if (ret) {
921 talloc_free(tmp_ctx);
922 return ret;
924 if (!claim_applies) {
925 /* If the claim doesn't apply, skip it. */
926 continue;
929 enabled = ldb_msg_find_attr_as_bool(res->msgs[i], "Enabled", 0);
930 if (!enabled) {
931 /* If the claim isn't enabled, skip it. */
932 continue;
935 claim_value_type = ldb_msg_find_attr_as_uint64(res->msgs[i],
936 "msDS-ClaimValueType",
938 if (!claim_value_type) {
939 continue;
942 claim_source_type = ldb_msg_find_attr_as_string(res->msgs[i],
943 "msDS-ClaimSourceType",
944 "");
946 /* Get the attribute used by the claim. */
947 claim_attribute_source = ldb_msg_find_ldb_val(res->msgs[i],
948 "msDS-ClaimAttributeSource");
950 claim_source = ldb_msg_find_attr_as_string(res->msgs[i],
951 "msDS-ClaimSource",
952 NULL);
954 if (strcasecmp(claim_source_type, "AD") == 0) {
955 struct ldb_dn *claim_attribute_source_dn = NULL;
956 const struct ldb_val *claim_attribute_source_rdn = NULL;
957 const struct dsdb_attribute *claim_attribute_source_class = NULL;
959 DATA_BLOB source_syntax;
960 const char *attribute = NULL;
961 const struct ldb_val *name = NULL;
963 if (claim_attribute_source == NULL) {
964 continue;
967 claim_attribute_source_dn = ldb_val_as_dn(ldb,
968 tmp_ctx,
969 claim_attribute_source);
970 if (claim_attribute_source_dn == NULL) {
971 talloc_free(tmp_ctx);
972 return ldb_operr(ldb);
975 if (!is_schema_dn(claim_attribute_source_dn, schema_dn)) {
976 /* This DN doesn't belong to the schema. */
977 continue;
980 claim_attribute_source_rdn = ldb_dn_get_rdn_val(claim_attribute_source_dn);
981 if (claim_attribute_source_rdn == NULL) {
982 /* No RDN, skip it. */
983 continue;
986 claim_attribute_source_class = dsdb_attribute_by_cn_ldb_val(schema,
987 claim_attribute_source_rdn);
988 claim_attribute_source_rdn = NULL;
989 TALLOC_FREE(claim_attribute_source_dn);
990 if (claim_attribute_source_class == NULL) {
991 continue;
994 source_syntax = data_blob_string_const(claim_attribute_source_class->attributeSyntax_oid);
995 if (source_syntax.data == NULL) {
996 continue;
999 if (!is_valid_claim_attribute_syntax(source_syntax, claim_value_type)) {
1000 continue;
1003 attribute = claim_attribute_source_class->lDAPDisplayName;
1004 if (attribute == NULL) {
1005 continue;
1008 ret = add_attr_unique(tmp_ctx,
1009 ad_claim_attrs,
1010 &ad_claim_attrs_count,
1011 attribute);
1012 if (ret) {
1013 talloc_free(tmp_ctx);
1014 return ret;
1017 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
1018 if (name == NULL) {
1019 name = &data_blob_null;
1022 ad_claims[ad_claims_count++] = (struct ad_claim_info) {
1023 .name = *name,
1024 .syntax = source_syntax,
1025 .attribute = attribute,
1026 .claim_type = claim_value_type,
1028 } else if (silo_is_maybe_assigned(assigned_silo)
1029 && strcasecmp(claim_source_type, "Constructed") == 0)
1031 const struct ldb_val *name = NULL;
1032 struct CLAIM_STRING *claim = NULL;
1033 struct CLAIM_ENTRY *claim_entry = NULL;
1034 const char *claim_value = NULL;
1036 if (claim_attribute_source != NULL) {
1037 continue;
1040 if (claim_source != NULL) {
1041 continue;
1044 name = ldb_msg_find_ldb_val(res->msgs[i], "name");
1045 if (name == NULL || name->data == NULL) {
1046 continue;
1048 /* Does the claim ID match exactly in case? */
1049 if (strcmp((const char *)name->data, "ad://ext/AuthenticationSilo") != 0) {
1050 continue;
1053 ret = get_assigned_silo(ldb, tmp_ctx, principal, &assigned_silo);
1054 if (ret) {
1055 talloc_free(tmp_ctx);
1056 return ret;
1058 if (!assigned_silo.is_assigned) {
1059 continue;
1062 if (ad_sourced_constructed == NULL) {
1063 claims_set.claims_arrays = talloc_realloc(tmp_ctx,
1064 claims_set.claims_arrays,
1065 struct CLAIMS_ARRAY,
1066 claims_set.claims_array_count + 1);
1067 if (claims_set.claims_arrays == NULL) {
1068 talloc_free(tmp_ctx);
1069 return ldb_oom(ldb);
1072 ad_sourced_constructed = &claims_set.claims_arrays[claims_set.claims_array_count++];
1073 *ad_sourced_constructed = (struct CLAIMS_ARRAY) {
1074 .claims_source_type = CLAIMS_SOURCE_TYPE_AD,
1078 /* Add the claim to the array. */
1079 ad_sourced_constructed->claim_entries = talloc_realloc(
1080 tmp_ctx,
1081 ad_sourced_constructed->claim_entries,
1082 struct CLAIM_ENTRY,
1083 ad_sourced_constructed->claims_count + 1);
1084 if (ad_sourced_constructed->claim_entries == NULL) {
1085 talloc_free(tmp_ctx);
1086 return ldb_oom(ldb);
1089 claim_entry = &ad_sourced_constructed->claim_entries[ad_sourced_constructed->claims_count++];
1091 /* Fill in the claim details and return the claim. */
1092 claim_entry->id = "ad://ext/AuthenticationSilo";
1093 claim_entry->type = CLAIM_TYPE_STRING;
1095 claim = &claim_entry->values.claim_string;
1097 claim->value_count = 1;
1098 claim->values = talloc_array(ad_sourced_constructed->claim_entries,
1099 const char *,
1100 claim->value_count);
1101 if (claim->values == NULL) {
1102 talloc_free(tmp_ctx);
1103 return ldb_oom(ldb);
1106 claim_value = talloc_strdup(claim->values, assigned_silo.name);
1107 if (claim_value == NULL) {
1108 talloc_free(tmp_ctx);
1109 return ldb_oom(ldb);
1112 claim->values[0] = claim_value;
1116 if (ad_claims_count) {
1117 struct ldb_message *principal_msg = NULL;
1119 /* Shrink the arrays to remove any unused space. */
1120 ad_claim_attrs = talloc_realloc(tmp_ctx,
1121 ad_claim_attrs,
1122 const char *,
1123 ad_claim_attrs_count + 1);
1124 if (ad_claim_attrs == NULL) {
1125 talloc_free(tmp_ctx);
1126 return ldb_oom(ldb);
1128 ad_claim_attrs[ad_claim_attrs_count] = NULL;
1130 ad_claims = talloc_realloc(tmp_ctx,
1131 ad_claims,
1132 struct ad_claim_info,
1133 ad_claims_count);
1134 if (ad_claims == NULL) {
1135 talloc_free(tmp_ctx);
1136 return ldb_oom(ldb);
1139 ret = dsdb_search_one(ldb,
1140 tmp_ctx,
1141 &principal_msg,
1142 principal->dn,
1143 LDB_SCOPE_BASE,
1144 ad_claim_attrs,
1146 NULL);
1147 if (ret != LDB_SUCCESS) {
1148 const char *dn = ldb_dn_get_linearized(principal->dn);
1149 DBG_ERR("Failed to find principal %s to construct claims\n",
1150 dn != NULL ? dn : "<NULL>");
1151 talloc_free(tmp_ctx);
1152 return ret;
1156 * Ensure that only the attrs we asked for end up in the results
1157 * (it's fine if some are missing)
1159 SMB_ASSERT(principal_msg->num_elements <= ad_claim_attrs_count);
1161 for (i = 0; i < ad_claims_count; ++i) {
1162 const struct ldb_message_element *principal_attribute = NULL;
1163 struct CLAIM_ENTRY *claim_entry = NULL;
1164 uint32_t new_claims_array_count = claims_set.claims_array_count;
1166 /* Get the value of the claim attribute for the principal. */
1167 principal_attribute = ldb_msg_find_element(principal_msg,
1168 ad_claims[i].attribute);
1169 if (principal_attribute == NULL) {
1170 continue;
1173 /* Add the claim to the array. */
1175 if (ad_sourced_constructed == NULL) {
1176 claims_set.claims_arrays = talloc_realloc(tmp_ctx,
1177 claims_set.claims_arrays,
1178 struct CLAIMS_ARRAY,
1179 new_claims_array_count + 1);
1180 if (claims_set.claims_arrays == NULL) {
1181 talloc_free(tmp_ctx);
1182 return ldb_oom(ldb);
1185 ad_sourced_constructed = &claims_set.claims_arrays[new_claims_array_count++];
1186 *ad_sourced_constructed = (struct CLAIMS_ARRAY) {
1187 .claims_source_type = CLAIMS_SOURCE_TYPE_AD,
1191 ad_sourced_constructed->claim_entries = talloc_realloc(
1192 tmp_ctx,
1193 ad_sourced_constructed->claim_entries,
1194 struct CLAIM_ENTRY,
1195 ad_sourced_constructed->claims_count + 1);
1196 if (ad_sourced_constructed->claim_entries == NULL) {
1197 talloc_free(tmp_ctx);
1198 return ldb_oom(ldb);
1201 claim_entry = &ad_sourced_constructed->claim_entries[
1202 ad_sourced_constructed->claims_count];
1204 ret = fill_claim_entry(ad_sourced_constructed->claim_entries,
1205 ldb,
1206 schema,
1207 principal_attribute,
1208 ad_claims[i].name,
1209 ad_claims[i].syntax,
1210 ad_claims[i].claim_type,
1211 claim_entry);
1212 if (ret != LDB_SUCCESS) {
1213 talloc_free(tmp_ctx);
1214 return ret;
1217 if (claim_get_value_count(claim_entry) > 0) {
1219 * If the claim contains values, add it to the
1220 * array(s).
1222 ++ad_sourced_constructed->claims_count;
1223 claims_set.claims_array_count = new_claims_array_count;
1228 if (claims_set.claims_array_count == 0) {
1229 /* If we have no claims, we're done. */
1230 talloc_free(tmp_ctx);
1231 return LDB_SUCCESS;
1234 /* Encode the claims ready to go into a PAC buffer. */
1235 ret = encode_claims_set(ldb, mem_ctx, &claims_set, claims_blob);
1237 talloc_free(tmp_ctx);
1238 return ret;
1241 int get_claims_for_principal(struct ldb_context *ldb,
1242 TALLOC_CTX *mem_ctx,
1243 const struct ldb_message *principal,
1244 DATA_BLOB *claims_blob)
1246 struct ldb_message_element *principal_class_el = NULL;
1247 struct dsdb_schema *schema = NULL;
1248 const struct dsdb_class *principal_class = NULL;
1250 *claims_blob = data_blob_null;
1252 if (!ad_claims_are_issued(ldb)) {
1253 return LDB_SUCCESS;
1256 principal_class_el = ldb_msg_find_element(principal,
1257 "objectClass");
1258 if (principal_class_el == NULL) {
1259 return ldb_operr(ldb);
1262 schema = dsdb_get_schema(ldb, mem_ctx);
1263 if (schema == NULL) {
1264 return ldb_operr(ldb);
1267 principal_class = dsdb_get_last_structural_class(schema, principal_class_el);
1268 if (principal_class == NULL) {
1269 return ldb_operr(ldb);
1272 return get_all_claims(ldb,
1273 mem_ctx,
1274 principal,
1275 principal_class->governsID_id,
1276 claims_blob);