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"
31 add a set of controls to a ldb_request structure based on a set of
32 flags. See util.h for a list of available flags
34 int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req, uint32_t dsdb_flags)
37 if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
38 struct ldb_search_options_control *options;
39 /* Using the phantom root control allows us to search all partitions */
40 options = talloc(req, struct ldb_search_options_control);
41 if (options == NULL) {
42 ldb_module_oom(module);
43 return LDB_ERR_OPERATIONS_ERROR;
45 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
47 ret = ldb_request_add_control(req,
48 LDB_CONTROL_SEARCH_OPTIONS_OID,
50 if (ret != LDB_SUCCESS) {
55 if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
56 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
57 if (ret != LDB_SUCCESS) {
62 if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
63 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
64 if (ret != LDB_SUCCESS) {
69 if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
70 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
72 ldb_module_oom(module);
73 return LDB_ERR_OPERATIONS_ERROR;
75 extended_ctrl->type = 1;
77 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
78 if (ret != LDB_SUCCESS) {
83 if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
84 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
85 if (ret != LDB_SUCCESS) {
90 if (dsdb_flags & DSDB_MODIFY_RELAX) {
91 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
92 if (ret != LDB_SUCCESS) {
101 search for attrs on one DN, in the modules below
103 int dsdb_module_search_dn(struct ldb_module *module,
105 struct ldb_result **_res,
106 struct ldb_dn *basedn,
107 const char * const *attrs,
111 struct ldb_request *req;
113 struct ldb_result *res;
115 tmp_ctx = talloc_new(mem_ctx);
117 res = talloc_zero(tmp_ctx, struct ldb_result);
119 return LDB_ERR_OPERATIONS_ERROR;
122 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
129 ldb_search_default_callback,
131 if (ret != LDB_SUCCESS) {
132 talloc_free(tmp_ctx);
136 ret = dsdb_request_add_controls(module, req, dsdb_flags);
137 if (ret != LDB_SUCCESS) {
138 talloc_free(tmp_ctx);
142 ret = ldb_next_request(module, req);
143 if (ret == LDB_SUCCESS) {
144 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
147 if (ret != LDB_SUCCESS) {
148 talloc_free(tmp_ctx);
152 if (res->count != 1) {
153 /* we may be reading a DB that does not have the 'check base on search' option... */
154 ret = LDB_ERR_NO_SUCH_OBJECT;
155 ldb_asprintf_errstring(ldb_module_get_ctx(module),
156 "dsdb_module_search_dn: did not find base dn %s (%d results)",
157 ldb_dn_get_linearized(basedn), res->count);
159 *_res = talloc_steal(mem_ctx, res);
161 talloc_free(tmp_ctx);
166 search for attrs in the modules below
168 int dsdb_module_search(struct ldb_module *module,
170 struct ldb_result **_res,
171 struct ldb_dn *basedn, enum ldb_scope scope,
172 const char * const *attrs,
174 const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
177 struct ldb_request *req;
179 struct ldb_result *res;
183 tmp_ctx = talloc_new(mem_ctx);
185 va_start(ap, format);
186 expression = talloc_vasprintf(tmp_ctx, format, ap);
189 res = talloc_zero(tmp_ctx, struct ldb_result);
191 return LDB_ERR_OPERATIONS_ERROR;
194 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
201 ldb_search_default_callback,
203 if (ret != LDB_SUCCESS) {
204 talloc_free(tmp_ctx);
208 ret = dsdb_request_add_controls(module, req, dsdb_flags);
209 if (ret != LDB_SUCCESS) {
210 talloc_free(tmp_ctx);
214 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
215 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
216 ret = ops->search(module, req);
217 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
218 ret = ldb_request(ldb_module_get_ctx(module), req);
220 ret = ldb_next_request(module, req);
222 if (ret == LDB_SUCCESS) {
223 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
227 if (ret == LDB_SUCCESS) {
228 *_res = talloc_steal(mem_ctx, res);
230 talloc_free(tmp_ctx);
235 find a DN given a GUID. This searches across all partitions
237 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
238 const struct GUID *guid, struct ldb_dn **dn)
240 struct ldb_result *res;
241 const char *attrs[] = { NULL };
242 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
245 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
247 DSDB_SEARCH_SHOW_DELETED |
248 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
249 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
250 "objectGUID=%s", GUID_string(tmp_ctx, guid));
251 if (ret != LDB_SUCCESS) {
252 talloc_free(tmp_ctx);
255 if (res->count == 0) {
256 talloc_free(tmp_ctx);
257 return LDB_ERR_NO_SUCH_OBJECT;
259 if (res->count != 1) {
260 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
261 GUID_string(tmp_ctx, guid));
262 talloc_free(tmp_ctx);
263 return LDB_ERR_OPERATIONS_ERROR;
266 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
268 talloc_free(tmp_ctx);
273 find a GUID given a DN.
275 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
277 const char *attrs[] = { NULL };
278 struct ldb_result *res;
279 TALLOC_CTX *tmp_ctx = talloc_new(module);
283 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
284 DSDB_SEARCH_SHOW_DELETED|
285 DSDB_SEARCH_SHOW_EXTENDED_DN);
286 if (ret != LDB_SUCCESS) {
287 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
288 ldb_dn_get_linearized(dn));
289 talloc_free(tmp_ctx);
293 status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
294 if (!NT_STATUS_IS_OK(status)) {
295 talloc_free(tmp_ctx);
296 return LDB_ERR_OPERATIONS_ERROR;
299 talloc_free(tmp_ctx);
304 a ldb_modify request operating on modules below the
307 int dsdb_module_modify(struct ldb_module *module,
308 const struct ldb_message *message,
311 struct ldb_request *mod_req;
313 struct ldb_context *ldb = ldb_module_get_ctx(module);
314 TALLOC_CTX *tmp_ctx = talloc_new(module);
316 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
320 ldb_op_default_callback,
322 if (ret != LDB_SUCCESS) {
323 talloc_free(tmp_ctx);
327 ret = dsdb_request_add_controls(module, mod_req, dsdb_flags);
328 if (ret != LDB_SUCCESS) {
329 talloc_free(tmp_ctx);
333 /* Run the new request */
334 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
335 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
336 ret = ops->modify(module, mod_req);
337 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
338 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
340 ret = ldb_next_request(module, mod_req);
342 if (ret == LDB_SUCCESS) {
343 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
346 talloc_free(tmp_ctx);
353 a ldb_rename request operating on modules below the
356 int dsdb_module_rename(struct ldb_module *module,
357 struct ldb_dn *olddn, struct ldb_dn *newdn,
360 struct ldb_request *req;
362 struct ldb_context *ldb = ldb_module_get_ctx(module);
363 TALLOC_CTX *tmp_ctx = talloc_new(module);
365 ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
370 ldb_op_default_callback,
372 if (ret != LDB_SUCCESS) {
373 talloc_free(tmp_ctx);
377 ret = dsdb_request_add_controls(module, req, dsdb_flags);
378 if (ret != LDB_SUCCESS) {
379 talloc_free(tmp_ctx);
383 /* Run the new request */
384 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
385 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
386 ret = ops->rename(module, req);
387 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
388 ret = ldb_request(ldb_module_get_ctx(module), req);
390 ret = ldb_next_request(module, req);
392 if (ret == LDB_SUCCESS) {
393 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
396 talloc_free(tmp_ctx);
401 a ldb_add request operating on modules below the
404 int dsdb_module_add(struct ldb_module *module,
405 const struct ldb_message *message,
408 struct ldb_request *req;
410 struct ldb_context *ldb = ldb_module_get_ctx(module);
411 TALLOC_CTX *tmp_ctx = talloc_new(module);
413 ret = ldb_build_add_req(&req, ldb, tmp_ctx,
417 ldb_op_default_callback,
419 if (ret != LDB_SUCCESS) {
420 talloc_free(tmp_ctx);
424 ret = dsdb_request_add_controls(module, req, dsdb_flags);
425 if (ret != LDB_SUCCESS) {
426 talloc_free(tmp_ctx);
430 /* Run the new request */
431 if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
432 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
433 ret = ops->add(module, req);
434 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
435 ret = ldb_request(ldb_module_get_ctx(module), req);
437 ret = ldb_next_request(module, req);
439 if (ret == LDB_SUCCESS) {
440 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
443 talloc_free(tmp_ctx);
448 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
450 const struct dsdb_class *last_class = NULL;
453 for (i = 0; i < element->num_values; i++){
454 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
456 if(tmp_class == NULL) {
460 if(tmp_class->objectClassCategory == 3) {
465 last_class = tmp_class;
467 if (tmp_class->subClass_order > last_class->subClass_order)
468 last_class = tmp_class;
476 check if a single valued link has multiple non-deleted values
478 This is needed when we will be using the RELAX control to stop
479 ldb_tdb from checking single valued links
481 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
482 const struct ldb_message_element *el)
484 bool found_active = false;
487 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
488 el->num_values < 2) {
492 for (i=0; i<el->num_values; i++) {
493 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
495 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
506 find a 'reference' DN that points at another object
507 (eg. serverReference, rIDManagerReference etc)
509 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
510 const char *attribute, struct ldb_dn **dn)
512 const char *attrs[2];
513 struct ldb_result *res;
516 attrs[0] = attribute;
519 ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs, 0);
520 if (ret != LDB_SUCCESS) {
524 *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
525 mem_ctx, res->msgs[0], attribute);
528 return LDB_ERR_NO_SUCH_ATTRIBUTE;
536 find the RID Manager$ DN via the rIDManagerReference attribute in the
539 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
541 return dsdb_module_reference_dn(module, mem_ctx,
542 samdb_base_dn(ldb_module_get_ctx(module)),
543 "rIDManagerReference", dn);
548 update an integer attribute safely via a constrained delete/add
550 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
551 const char *attr, uint64_t old_val, uint64_t new_val)
553 struct ldb_message *msg;
554 struct ldb_message_element *el;
555 struct ldb_val v1, v2;
559 msg = ldb_msg_new(module);
562 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
563 if (ret != LDB_SUCCESS) {
569 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
571 ldb_module_oom(module);
573 return LDB_ERR_OPERATIONS_ERROR;
575 v1 = data_blob_string_const(vstring);
577 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
578 if (ret != LDB_SUCCESS) {
584 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
586 ldb_module_oom(module);
588 return LDB_ERR_OPERATIONS_ERROR;
590 v2 = data_blob_string_const(vstring);
592 ret = dsdb_module_modify(module, msg, 0);
598 used to chain to the callers callback
600 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
602 struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
604 talloc_steal(up_req, req);
605 return up_req->callback(up_req, ares);
610 set an integer attribute
612 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
613 const char *attr, uint64_t new_val)
615 struct ldb_message *msg;
618 msg = ldb_msg_new(module);
621 ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
622 if (ret != LDB_SUCCESS) {
626 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
628 ret = dsdb_module_modify(module, msg, 0);