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);
50 return LDB_ERR_OPERATIONS_ERROR;
53 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
60 ldb_search_default_callback,
62 if (ret != LDB_SUCCESS) {
67 ret = dsdb_request_add_controls(req, dsdb_flags);
68 if (ret != LDB_SUCCESS) {
73 ret = ldb_next_request(module, req);
74 if (ret == LDB_SUCCESS) {
75 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
78 if (ret != LDB_SUCCESS) {
83 if (res->count != 1) {
84 /* we may be reading a DB that does not have the 'check base on search' option... */
85 ret = LDB_ERR_NO_SUCH_OBJECT;
86 ldb_asprintf_errstring(ldb_module_get_ctx(module),
87 "dsdb_module_search_dn: did not find base dn %s (%d results)",
88 ldb_dn_get_linearized(basedn), res->count);
90 *_res = talloc_steal(mem_ctx, res);
97 search for attrs in the modules below
99 int dsdb_module_search(struct ldb_module *module,
101 struct ldb_result **_res,
102 struct ldb_dn *basedn, enum ldb_scope scope,
103 const char * const *attrs,
105 const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
108 struct ldb_request *req;
110 struct ldb_result *res;
114 tmp_ctx = talloc_new(mem_ctx);
116 va_start(ap, format);
117 expression = talloc_vasprintf(tmp_ctx, format, ap);
120 res = talloc_zero(tmp_ctx, struct ldb_result);
122 return LDB_ERR_OPERATIONS_ERROR;
125 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
132 ldb_search_default_callback,
134 if (ret != LDB_SUCCESS) {
135 talloc_free(tmp_ctx);
139 ret = dsdb_request_add_controls(req, dsdb_flags);
140 if (ret != LDB_SUCCESS) {
141 talloc_free(tmp_ctx);
145 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
146 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
147 ret = ops->search(module, req);
148 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
149 ret = ldb_request(ldb_module_get_ctx(module), req);
151 ret = ldb_next_request(module, req);
153 if (ret == LDB_SUCCESS) {
154 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
158 if (ret == LDB_SUCCESS) {
159 *_res = talloc_steal(mem_ctx, res);
161 talloc_free(tmp_ctx);
166 find a DN given a GUID. This searches across all partitions
168 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
169 const struct GUID *guid, struct ldb_dn **dn)
171 struct ldb_result *res;
172 const char *attrs[] = { NULL };
173 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
176 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
178 DSDB_SEARCH_SHOW_DELETED |
179 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
180 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
181 "objectGUID=%s", GUID_string(tmp_ctx, guid));
182 if (ret != LDB_SUCCESS) {
183 talloc_free(tmp_ctx);
186 if (res->count == 0) {
187 talloc_free(tmp_ctx);
188 return LDB_ERR_NO_SUCH_OBJECT;
190 if (res->count != 1) {
191 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
192 GUID_string(tmp_ctx, guid));
193 talloc_free(tmp_ctx);
194 return LDB_ERR_OPERATIONS_ERROR;
197 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
199 talloc_free(tmp_ctx);
204 find a GUID given a DN.
206 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
208 const char *attrs[] = { NULL };
209 struct ldb_result *res;
210 TALLOC_CTX *tmp_ctx = talloc_new(module);
214 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
215 DSDB_SEARCH_SHOW_DELETED|
216 DSDB_SEARCH_SHOW_EXTENDED_DN);
217 if (ret != LDB_SUCCESS) {
218 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
219 ldb_dn_get_linearized(dn));
220 talloc_free(tmp_ctx);
224 status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
225 if (!NT_STATUS_IS_OK(status)) {
226 talloc_free(tmp_ctx);
227 return LDB_ERR_OPERATIONS_ERROR;
230 talloc_free(tmp_ctx);
235 a ldb_modify request operating on modules below the
238 int dsdb_module_modify(struct ldb_module *module,
239 const struct ldb_message *message,
242 struct ldb_request *mod_req;
244 struct ldb_context *ldb = ldb_module_get_ctx(module);
245 TALLOC_CTX *tmp_ctx = talloc_new(module);
246 struct ldb_result *res;
248 res = talloc_zero(tmp_ctx, struct ldb_result);
250 return LDB_ERR_OPERATIONS_ERROR;
253 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
257 ldb_modify_default_callback,
259 if (ret != LDB_SUCCESS) {
260 talloc_free(tmp_ctx);
264 ret = dsdb_request_add_controls(mod_req, dsdb_flags);
265 if (ret != LDB_SUCCESS) {
266 talloc_free(tmp_ctx);
270 /* Run the new request */
271 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
272 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
273 ret = ops->modify(module, mod_req);
274 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
275 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
277 ret = ldb_next_request(module, mod_req);
279 if (ret == LDB_SUCCESS) {
280 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
283 talloc_free(tmp_ctx);
290 a ldb_rename request operating on modules below the
293 int dsdb_module_rename(struct ldb_module *module,
294 struct ldb_dn *olddn, struct ldb_dn *newdn,
297 struct ldb_request *req;
299 struct ldb_context *ldb = ldb_module_get_ctx(module);
300 TALLOC_CTX *tmp_ctx = talloc_new(module);
301 struct ldb_result *res;
303 res = talloc_zero(tmp_ctx, struct ldb_result);
305 return LDB_ERR_OPERATIONS_ERROR;
308 ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
313 ldb_modify_default_callback,
315 if (ret != LDB_SUCCESS) {
316 talloc_free(tmp_ctx);
320 ret = dsdb_request_add_controls(req, dsdb_flags);
321 if (ret != LDB_SUCCESS) {
322 talloc_free(tmp_ctx);
326 /* Run the new request */
327 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
328 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
329 ret = ops->rename(module, req);
330 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
331 ret = ldb_request(ldb_module_get_ctx(module), req);
333 ret = ldb_next_request(module, req);
335 if (ret == LDB_SUCCESS) {
336 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
339 talloc_free(tmp_ctx);
344 a ldb_add request operating on modules below the
347 int dsdb_module_add(struct ldb_module *module,
348 const struct ldb_message *message,
351 struct ldb_request *req;
353 struct ldb_context *ldb = ldb_module_get_ctx(module);
354 TALLOC_CTX *tmp_ctx = talloc_new(module);
355 struct ldb_result *res;
357 res = talloc_zero(tmp_ctx, struct ldb_result);
359 return LDB_ERR_OPERATIONS_ERROR;
362 ret = ldb_build_add_req(&req, ldb, tmp_ctx,
366 ldb_modify_default_callback,
368 if (ret != LDB_SUCCESS) {
369 talloc_free(tmp_ctx);
373 ret = dsdb_request_add_controls(req, dsdb_flags);
374 if (ret != LDB_SUCCESS) {
375 talloc_free(tmp_ctx);
379 /* Run the new request */
380 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
381 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
382 ret = ops->add(module, req);
383 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
384 ret = ldb_request(ldb_module_get_ctx(module), req);
386 ret = ldb_next_request(module, req);
388 if (ret == LDB_SUCCESS) {
389 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
392 talloc_free(tmp_ctx);
397 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
399 const struct dsdb_class *last_class = NULL;
402 for (i = 0; i < element->num_values; i++){
403 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
405 if(tmp_class == NULL) {
409 if(tmp_class->objectClassCategory == 3) {
414 last_class = tmp_class;
416 if (tmp_class->subClass_order > last_class->subClass_order)
417 last_class = tmp_class;
425 check if a single valued link has multiple non-deleted values
427 This is needed when we will be using the RELAX control to stop
428 ldb_tdb from checking single valued links
430 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
431 const struct ldb_message_element *el)
433 bool found_active = false;
436 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
437 el->num_values < 2) {
441 for (i=0; i<el->num_values; i++) {
442 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
444 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
453 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
454 struct GUID op_feature_guid, bool *feature_enabled)
457 struct ldb_context *ldb = ldb_module_get_ctx(module);
458 struct ldb_result *res;
459 struct ldb_dn *search_dn;
460 struct GUID search_guid;
461 const char *attrs[] = {"msDS-EnabledFeature", NULL};
464 struct ldb_message_element *el;
466 *feature_enabled = false;
468 tmp_ctx = talloc_new(ldb);
470 ret = ldb_search(ldb, tmp_ctx, &res,
471 scope, LDB_SCOPE_BASE, attrs,
473 if (ret != LDB_SUCCESS) {
474 ldb_asprintf_errstring(ldb,
475 "Could no find the scope object - dn: %s\n",
476 ldb_dn_get_linearized(scope));
477 talloc_free(tmp_ctx);
478 return LDB_ERR_OPERATIONS_ERROR;
480 if (res->msgs[0]->num_elements > 0) {
482 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
484 attrs[0] = "msDS-OptionalFeatureGUID";
486 for (i=0; i<el->num_values; i++) {
487 search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
489 ret = ldb_search(ldb, tmp_ctx, &res,
490 search_dn, LDB_SCOPE_BASE, attrs,
492 if (ret != LDB_SUCCESS) {
493 ldb_asprintf_errstring(ldb,
494 "Could no find object dn: %s\n",
495 ldb_dn_get_linearized(search_dn));
496 talloc_free(tmp_ctx);
497 return LDB_ERR_OPERATIONS_ERROR;
500 search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
502 if (GUID_compare(&search_guid, &op_feature_guid) == 0){
503 *feature_enabled = true;
508 talloc_free(tmp_ctx);
513 find a 'reference' DN that points at another object
514 (eg. serverReference, rIDManagerReference etc)
516 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
517 const char *attribute, struct ldb_dn **dn)
519 const char *attrs[2];
520 struct ldb_result *res;
523 attrs[0] = attribute;
526 ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs, 0);
527 if (ret != LDB_SUCCESS) {
531 *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
532 mem_ctx, res->msgs[0], attribute);
535 return LDB_ERR_NO_SUCH_ATTRIBUTE;
543 find the RID Manager$ DN via the rIDManagerReference attribute in the
546 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
548 return dsdb_module_reference_dn(module, mem_ctx,
549 ldb_get_default_basedn(ldb_module_get_ctx(module)),
550 "rIDManagerReference", dn);
555 update an integer attribute safely via a constrained delete/add
557 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
558 const char *attr, uint64_t old_val, uint64_t new_val)
560 struct ldb_message *msg;
561 struct ldb_message_element *el;
562 struct ldb_val v1, v2;
566 msg = ldb_msg_new(module);
569 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
570 if (ret != LDB_SUCCESS) {
576 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
578 ldb_module_oom(module);
580 return LDB_ERR_OPERATIONS_ERROR;
582 v1 = data_blob_string_const(vstring);
584 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
585 if (ret != LDB_SUCCESS) {
591 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
593 ldb_module_oom(module);
595 return LDB_ERR_OPERATIONS_ERROR;
597 v2 = data_blob_string_const(vstring);
599 ret = dsdb_module_modify(module, msg, 0);
605 used to chain to the callers callback
607 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
609 struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
611 talloc_steal(up_req, req);
612 return up_req->callback(up_req, ares);
617 set an integer attribute
619 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
620 const char *attr, uint64_t new_val)
622 struct ldb_message *msg;
625 msg = ldb_msg_new(module);
628 ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
629 if (ret != LDB_SUCCESS) {
633 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
635 ret = dsdb_module_modify(module, msg, 0);
641 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
642 object for a partition
644 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
645 uint64_t *uSN, uint64_t *urgent_uSN)
647 struct ldb_context *ldb = ldb_module_get_ctx(module);
648 struct ldb_request *req;
650 TALLOC_CTX *tmp_ctx = talloc_new(module);
651 struct dsdb_control_current_partition *p_ctrl;
652 struct ldb_result *res;
654 res = talloc_zero(tmp_ctx, struct ldb_result);
656 talloc_free(tmp_ctx);
657 return LDB_ERR_OPERATIONS_ERROR;
660 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
661 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
665 res, ldb_search_default_callback,
667 if (ret != LDB_SUCCESS) {
668 talloc_free(tmp_ctx);
672 p_ctrl = talloc(req, struct dsdb_control_current_partition);
673 if (p_ctrl == NULL) {
675 return LDB_ERR_OPERATIONS_ERROR;
677 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
681 ret = ldb_request_add_control(req,
682 DSDB_CONTROL_CURRENT_PARTITION_OID,
684 if (ret != LDB_SUCCESS) {
685 talloc_free(tmp_ctx);
689 /* Run the new request */
690 ret = ldb_next_request(module, req);
692 if (ret == LDB_SUCCESS) {
693 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
696 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
697 /* it hasn't been created yet, which means
698 an implicit value of zero */
700 talloc_free(tmp_ctx);
704 if (ret != LDB_SUCCESS) {
705 talloc_free(tmp_ctx);
709 if (res->count < 1) {
715 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
717 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
721 talloc_free(tmp_ctx);
727 save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
730 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
731 uint64_t uSN, uint64_t urgent_uSN)
733 struct ldb_context *ldb = ldb_module_get_ctx(module);
734 struct ldb_request *req;
735 struct ldb_message *msg;
736 struct dsdb_control_current_partition *p_ctrl;
738 struct ldb_result *res;
740 msg = ldb_msg_new(module);
742 return LDB_ERR_OPERATIONS_ERROR;
745 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
746 if (msg->dn == NULL) {
748 return LDB_ERR_OPERATIONS_ERROR;
751 res = talloc_zero(msg, struct ldb_result);
753 return LDB_ERR_OPERATIONS_ERROR;
756 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
757 if (ret != LDB_SUCCESS) {
761 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
763 /* urgent_uSN is optional so may not be stored */
765 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
766 if (ret != LDB_SUCCESS) {
770 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
774 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
775 if (p_ctrl == NULL) {
777 return LDB_ERR_OPERATIONS_ERROR;
779 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
781 ret = ldb_build_mod_req(&req, ldb, msg,
785 ldb_modify_default_callback,
788 if (ret != LDB_SUCCESS) {
793 ret = ldb_request_add_control(req,
794 DSDB_CONTROL_CURRENT_PARTITION_OID,
796 if (ret != LDB_SUCCESS) {
801 /* Run the new request */
802 ret = ldb_next_request(module, req);
804 if (ret == LDB_SUCCESS) {
805 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
807 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
808 ret = ldb_build_add_req(&req, ldb, msg,
812 ldb_modify_default_callback,
822 bool dsdb_module_am_system(struct ldb_module *module)
824 struct ldb_context *ldb = ldb_module_get_ctx(module);
825 struct auth_session_info *session_info
826 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
827 return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
831 check if the recyclebin is enabled
833 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
835 struct ldb_context *ldb = ldb_module_get_ctx(module);
836 struct ldb_dn *partitions_dn;
837 struct GUID recyclebin_guid;
840 partitions_dn = samdb_partitions_dn(ldb, module);
842 GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
844 ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
845 if (ret != LDB_SUCCESS) {
846 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
847 talloc_free(partitions_dn);
848 return LDB_ERR_UNWILLING_TO_PERFORM;
851 talloc_free(partitions_dn);
855 bool is_attr_in_list(const char * const * attrs, const char *attr)
859 for (i = 0; attrs[i]; i++) {
860 if (ldb_attr_cmp(attrs[i], attr) == 0)