2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2009
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "ldb_module.h"
25 #include "librpc/ndr/libndr.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
27 #include "dsdb/samdb/samdb.h"
29 #include "libcli/security/security.h"
32 search for attrs on one DN, in the modules below
34 int dsdb_module_search_dn(struct ldb_module *module,
36 struct ldb_result **_res,
37 struct ldb_dn *basedn,
38 const char * const *attrs,
42 struct ldb_request *req;
44 struct ldb_result *res;
46 tmp_ctx = talloc_new(mem_ctx);
48 res = talloc_zero(tmp_ctx, struct ldb_result);
51 return ldb_oom(ldb_module_get_ctx(module));
54 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
61 ldb_search_default_callback,
63 if (ret != LDB_SUCCESS) {
68 ret = dsdb_request_add_controls(req, dsdb_flags);
69 if (ret != LDB_SUCCESS) {
74 ret = ldb_next_request(module, req);
75 if (ret == LDB_SUCCESS) {
76 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
79 if (ret != LDB_SUCCESS) {
84 if (res->count != 1) {
85 /* we may be reading a DB that does not have the 'check base on search' option... */
86 ret = LDB_ERR_NO_SUCH_OBJECT;
87 ldb_asprintf_errstring(ldb_module_get_ctx(module),
88 "dsdb_module_search_dn: did not find base dn %s (%d results)",
89 ldb_dn_get_linearized(basedn), res->count);
91 *_res = talloc_steal(mem_ctx, res);
98 search for attrs in the modules below
100 int dsdb_module_search(struct ldb_module *module,
102 struct ldb_result **_res,
103 struct ldb_dn *basedn, enum ldb_scope scope,
104 const char * const *attrs,
106 const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
109 struct ldb_request *req;
111 struct ldb_result *res;
115 tmp_ctx = talloc_new(mem_ctx);
118 va_start(ap, format);
119 expression = talloc_vasprintf(tmp_ctx, format, ap);
123 talloc_free(tmp_ctx);
124 return ldb_oom(ldb_module_get_ctx(module));
130 res = talloc_zero(tmp_ctx, struct ldb_result);
132 talloc_free(tmp_ctx);
133 return ldb_oom(ldb_module_get_ctx(module));
136 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
143 ldb_search_default_callback,
145 if (ret != LDB_SUCCESS) {
146 talloc_free(tmp_ctx);
150 ret = dsdb_request_add_controls(req, dsdb_flags);
151 if (ret != LDB_SUCCESS) {
152 talloc_free(tmp_ctx);
156 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
157 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
158 ret = ops->search(module, req);
159 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
160 ret = ldb_request(ldb_module_get_ctx(module), req);
162 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
163 ret = ldb_next_request(module, req);
165 if (ret == LDB_SUCCESS) {
166 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
170 if (ret == LDB_SUCCESS) {
171 *_res = talloc_steal(mem_ctx, res);
173 talloc_free(tmp_ctx);
178 find a DN given a GUID. This searches across all partitions
180 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
181 const struct GUID *guid, struct ldb_dn **dn)
183 struct ldb_result *res;
184 const char *attrs[] = { NULL };
185 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
188 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
190 DSDB_FLAG_NEXT_MODULE |
191 DSDB_SEARCH_SHOW_DELETED |
192 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
193 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
194 "objectGUID=%s", GUID_string(tmp_ctx, guid));
195 if (ret != LDB_SUCCESS) {
196 talloc_free(tmp_ctx);
199 if (res->count == 0) {
200 talloc_free(tmp_ctx);
201 return LDB_ERR_NO_SUCH_OBJECT;
203 if (res->count != 1) {
204 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
205 GUID_string(tmp_ctx, guid));
206 talloc_free(tmp_ctx);
207 return LDB_ERR_OPERATIONS_ERROR;
210 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
212 talloc_free(tmp_ctx);
217 find a GUID given a DN.
219 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
221 const char *attrs[] = { NULL };
222 struct ldb_result *res;
223 TALLOC_CTX *tmp_ctx = talloc_new(module);
227 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
228 DSDB_FLAG_NEXT_MODULE |
229 DSDB_SEARCH_SHOW_DELETED |
230 DSDB_SEARCH_SHOW_EXTENDED_DN);
231 if (ret != LDB_SUCCESS) {
232 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
233 ldb_dn_get_linearized(dn));
234 talloc_free(tmp_ctx);
238 status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
239 if (!NT_STATUS_IS_OK(status)) {
240 talloc_free(tmp_ctx);
241 return ldb_operr(ldb_module_get_ctx(module));
244 talloc_free(tmp_ctx);
249 a ldb_modify request operating on modules below the
252 int dsdb_module_modify(struct ldb_module *module,
253 const struct ldb_message *message,
256 struct ldb_request *mod_req;
258 struct ldb_context *ldb = ldb_module_get_ctx(module);
259 TALLOC_CTX *tmp_ctx = talloc_new(module);
260 struct ldb_result *res;
262 res = talloc_zero(tmp_ctx, struct ldb_result);
264 talloc_free(tmp_ctx);
265 return ldb_oom(ldb_module_get_ctx(module));
268 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
272 ldb_modify_default_callback,
274 if (ret != LDB_SUCCESS) {
275 talloc_free(tmp_ctx);
279 ret = dsdb_request_add_controls(mod_req, dsdb_flags);
280 if (ret != LDB_SUCCESS) {
281 talloc_free(tmp_ctx);
285 /* Run the new request */
286 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
287 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
288 ret = ops->modify(module, mod_req);
289 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
290 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
292 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
293 ret = ldb_next_request(module, mod_req);
295 if (ret == LDB_SUCCESS) {
296 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
299 talloc_free(tmp_ctx);
306 a ldb_rename request operating on modules below the
309 int dsdb_module_rename(struct ldb_module *module,
310 struct ldb_dn *olddn, struct ldb_dn *newdn,
313 struct ldb_request *req;
315 struct ldb_context *ldb = ldb_module_get_ctx(module);
316 TALLOC_CTX *tmp_ctx = talloc_new(module);
317 struct ldb_result *res;
319 res = talloc_zero(tmp_ctx, struct ldb_result);
321 talloc_free(tmp_ctx);
322 return ldb_oom(ldb_module_get_ctx(module));
325 ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
330 ldb_modify_default_callback,
332 if (ret != LDB_SUCCESS) {
333 talloc_free(tmp_ctx);
337 ret = dsdb_request_add_controls(req, dsdb_flags);
338 if (ret != LDB_SUCCESS) {
339 talloc_free(tmp_ctx);
343 /* Run the new request */
344 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
345 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
346 ret = ops->rename(module, req);
347 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
348 ret = ldb_request(ldb_module_get_ctx(module), req);
350 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
351 ret = ldb_next_request(module, req);
353 if (ret == LDB_SUCCESS) {
354 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
357 talloc_free(tmp_ctx);
362 a ldb_add request operating on modules below the
365 int dsdb_module_add(struct ldb_module *module,
366 const struct ldb_message *message,
369 struct ldb_request *req;
371 struct ldb_context *ldb = ldb_module_get_ctx(module);
372 TALLOC_CTX *tmp_ctx = talloc_new(module);
373 struct ldb_result *res;
375 res = talloc_zero(tmp_ctx, struct ldb_result);
377 talloc_free(tmp_ctx);
378 return ldb_oom(ldb_module_get_ctx(module));
381 ret = ldb_build_add_req(&req, ldb, tmp_ctx,
385 ldb_modify_default_callback,
387 if (ret != LDB_SUCCESS) {
388 talloc_free(tmp_ctx);
392 ret = dsdb_request_add_controls(req, dsdb_flags);
393 if (ret != LDB_SUCCESS) {
394 talloc_free(tmp_ctx);
398 /* Run the new request */
399 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
400 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
401 ret = ops->add(module, req);
402 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
403 ret = ldb_request(ldb_module_get_ctx(module), req);
405 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
406 ret = ldb_next_request(module, req);
408 if (ret == LDB_SUCCESS) {
409 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
412 talloc_free(tmp_ctx);
417 a ldb_delete request operating on modules below the
420 int dsdb_module_del(struct ldb_module *module,
424 struct ldb_request *req;
426 struct ldb_context *ldb = ldb_module_get_ctx(module);
427 TALLOC_CTX *tmp_ctx = talloc_new(module);
428 struct ldb_result *res;
430 res = talloc_zero(tmp_ctx, struct ldb_result);
432 talloc_free(tmp_ctx);
436 ret = ldb_build_del_req(&req, ldb, tmp_ctx,
440 ldb_modify_default_callback,
442 if (ret != LDB_SUCCESS) {
443 talloc_free(tmp_ctx);
447 ret = dsdb_request_add_controls(req, dsdb_flags);
448 if (ret != LDB_SUCCESS) {
449 talloc_free(tmp_ctx);
453 /* Run the new request */
454 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
455 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
456 ret = ops->del(module, req);
457 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
458 ret = ldb_request(ldb_module_get_ctx(module), req);
460 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
461 ret = ldb_next_request(module, req);
463 if (ret == LDB_SUCCESS) {
464 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
467 talloc_free(tmp_ctx);
471 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
473 const struct dsdb_class *last_class = NULL;
476 for (i = 0; i < element->num_values; i++){
477 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
479 if(tmp_class == NULL) {
483 if(tmp_class->objectClassCategory > 1) {
488 last_class = tmp_class;
490 if (tmp_class->subClass_order > last_class->subClass_order)
491 last_class = tmp_class;
499 check if a single valued link has multiple non-deleted values
501 This is needed when we will be using the RELAX control to stop
502 ldb_tdb from checking single valued links
504 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
505 const struct ldb_message_element *el)
507 bool found_active = false;
510 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
511 el->num_values < 2) {
515 for (i=0; i<el->num_values; i++) {
516 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
518 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
527 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
528 struct GUID op_feature_guid, bool *feature_enabled)
531 struct ldb_context *ldb = ldb_module_get_ctx(module);
532 struct ldb_result *res;
533 struct ldb_dn *search_dn;
534 struct GUID search_guid;
535 const char *attrs[] = {"msDS-EnabledFeature", NULL};
538 struct ldb_message_element *el;
540 *feature_enabled = false;
542 tmp_ctx = talloc_new(ldb);
544 ret = ldb_search(ldb, tmp_ctx, &res,
545 scope, LDB_SCOPE_BASE, attrs,
547 if (ret != LDB_SUCCESS) {
548 ldb_asprintf_errstring(ldb,
549 "Could no find the scope object - dn: %s\n",
550 ldb_dn_get_linearized(scope));
551 talloc_free(tmp_ctx);
552 return LDB_ERR_OPERATIONS_ERROR;
554 if (res->msgs[0]->num_elements > 0) {
556 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
558 attrs[0] = "msDS-OptionalFeatureGUID";
560 for (i=0; i<el->num_values; i++) {
561 search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
563 ret = ldb_search(ldb, tmp_ctx, &res,
564 search_dn, LDB_SCOPE_BASE, attrs,
566 if (ret != LDB_SUCCESS) {
567 ldb_asprintf_errstring(ldb,
568 "Could no find object dn: %s\n",
569 ldb_dn_get_linearized(search_dn));
570 talloc_free(tmp_ctx);
571 return LDB_ERR_OPERATIONS_ERROR;
574 search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
576 if (GUID_compare(&search_guid, &op_feature_guid) == 0){
577 *feature_enabled = true;
582 talloc_free(tmp_ctx);
587 find a 'reference' DN that points at another object
588 (eg. serverReference, rIDManagerReference etc)
590 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
591 const char *attribute, struct ldb_dn **dn)
593 const char *attrs[2];
594 struct ldb_result *res;
597 attrs[0] = attribute;
600 ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
601 DSDB_FLAG_NEXT_MODULE);
602 if (ret != LDB_SUCCESS) {
606 *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
607 mem_ctx, res->msgs[0], attribute);
610 return LDB_ERR_NO_SUCH_ATTRIBUTE;
618 find the RID Manager$ DN via the rIDManagerReference attribute in the
621 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
623 return dsdb_module_reference_dn(module, mem_ctx,
624 ldb_get_default_basedn(ldb_module_get_ctx(module)),
625 "rIDManagerReference", dn);
630 update an integer attribute safely via a constrained delete/add
632 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
633 const char *attr, uint64_t old_val, uint64_t new_val)
635 struct ldb_message *msg;
636 struct ldb_message_element *el;
637 struct ldb_val v1, v2;
641 msg = ldb_msg_new(module);
644 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
645 if (ret != LDB_SUCCESS) {
651 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
654 return ldb_module_oom(module);
656 v1 = data_blob_string_const(vstring);
658 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
659 if (ret != LDB_SUCCESS) {
665 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
668 return ldb_module_oom(module);
670 v2 = data_blob_string_const(vstring);
672 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
678 used to chain to the callers callback
680 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
682 struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
684 talloc_steal(up_req, req);
685 return up_req->callback(up_req, ares);
690 set an integer attribute
692 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
693 const char *attr, uint64_t new_val)
695 struct ldb_message *msg;
698 msg = ldb_msg_new(module);
701 ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
702 if (ret != LDB_SUCCESS) {
706 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
708 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
714 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
715 object for a partition
717 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
718 uint64_t *uSN, uint64_t *urgent_uSN)
720 struct ldb_context *ldb = ldb_module_get_ctx(module);
721 struct ldb_request *req;
723 TALLOC_CTX *tmp_ctx = talloc_new(module);
724 struct dsdb_control_current_partition *p_ctrl;
725 struct ldb_result *res;
727 res = talloc_zero(tmp_ctx, struct ldb_result);
729 talloc_free(tmp_ctx);
730 return ldb_module_oom(module);
733 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
734 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
738 res, ldb_search_default_callback,
740 if (ret != LDB_SUCCESS) {
741 talloc_free(tmp_ctx);
745 p_ctrl = talloc(req, struct dsdb_control_current_partition);
746 if (p_ctrl == NULL) {
747 talloc_free(tmp_ctx);
748 return ldb_module_oom(module);
750 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
754 ret = ldb_request_add_control(req,
755 DSDB_CONTROL_CURRENT_PARTITION_OID,
757 if (ret != LDB_SUCCESS) {
758 talloc_free(tmp_ctx);
762 /* Run the new request */
763 ret = ldb_next_request(module, req);
765 if (ret == LDB_SUCCESS) {
766 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
769 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
770 /* it hasn't been created yet, which means
771 an implicit value of zero */
773 talloc_free(tmp_ctx);
777 if (ret != LDB_SUCCESS) {
778 talloc_free(tmp_ctx);
782 if (res->count != 1) {
788 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
790 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
794 talloc_free(tmp_ctx);
800 save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
803 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
804 uint64_t uSN, uint64_t urgent_uSN)
806 struct ldb_context *ldb = ldb_module_get_ctx(module);
807 struct ldb_request *req;
808 struct ldb_message *msg;
809 struct dsdb_control_current_partition *p_ctrl;
811 struct ldb_result *res;
813 msg = ldb_msg_new(module);
815 return ldb_module_oom(module);
818 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
819 if (msg->dn == NULL) {
821 return ldb_operr(ldb_module_get_ctx(module));
824 res = talloc_zero(msg, struct ldb_result);
827 return ldb_module_oom(module);
830 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
831 if (ret != LDB_SUCCESS) {
835 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
837 /* urgent_uSN is optional so may not be stored */
839 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
840 if (ret != LDB_SUCCESS) {
844 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
848 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
849 if (p_ctrl == NULL) {
853 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
855 ret = ldb_build_mod_req(&req, ldb, msg,
859 ldb_modify_default_callback,
862 if (ret != LDB_SUCCESS) {
867 ret = ldb_request_add_control(req,
868 DSDB_CONTROL_CURRENT_PARTITION_OID,
870 if (ret != LDB_SUCCESS) {
875 /* Run the new request */
876 ret = ldb_next_request(module, req);
878 if (ret == LDB_SUCCESS) {
879 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
881 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
882 ret = ldb_build_add_req(&req, ldb, msg,
886 ldb_modify_default_callback,
896 bool dsdb_module_am_system(struct ldb_module *module)
898 struct ldb_context *ldb = ldb_module_get_ctx(module);
899 struct auth_session_info *session_info
900 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
901 return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
905 check if the recyclebin is enabled
907 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
909 struct ldb_context *ldb = ldb_module_get_ctx(module);
910 struct ldb_dn *partitions_dn;
911 struct GUID recyclebin_guid;
914 partitions_dn = samdb_partitions_dn(ldb, module);
916 GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
918 ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
919 if (ret != LDB_SUCCESS) {
920 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
921 talloc_free(partitions_dn);
922 return LDB_ERR_UNWILLING_TO_PERFORM;
925 talloc_free(partitions_dn);
929 bool is_attr_in_list(const char * const * attrs, const char *attr)
933 for (i = 0; attrs[i]; i++) {
934 if (ldb_attr_cmp(attrs[i], attr) == 0)