s4-dsdb: added tagging of requests in dsdb modules
[Samba.git] / source4 / dsdb / samdb / ldb_modules / util.c
blob03c301898e615b3f2b2031c4d255f8c396cd61b8
1 /*
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/>.
22 #include "includes.h"
23 #include "ldb.h"
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"
28 #include "util.h"
29 #include "libcli/security/security.h"
30 #include "lib/ldb/include/ldb_private.h"
33 search for attrs on one DN, in the modules below
35 int dsdb_module_search_dn(struct ldb_module *module,
36 TALLOC_CTX *mem_ctx,
37 struct ldb_result **_res,
38 struct ldb_dn *basedn,
39 const char * const *attrs,
40 uint32_t dsdb_flags)
42 int ret;
43 struct ldb_request *req;
44 TALLOC_CTX *tmp_ctx;
45 struct ldb_result *res;
47 tmp_ctx = talloc_new(mem_ctx);
49 res = talloc_zero(tmp_ctx, struct ldb_result);
50 if (!res) {
51 talloc_free(tmp_ctx);
52 return ldb_oom(ldb_module_get_ctx(module));
55 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
56 basedn,
57 LDB_SCOPE_BASE,
58 NULL,
59 attrs,
60 NULL,
61 res,
62 ldb_search_default_callback,
63 NULL);
64 if (ret != LDB_SUCCESS) {
65 talloc_free(tmp_ctx);
66 return ret;
69 ret = dsdb_request_add_controls(req, dsdb_flags);
70 if (ret != LDB_SUCCESS) {
71 talloc_free(tmp_ctx);
72 return ret;
75 /* Run the new request */
76 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
77 ret = ldb_next_request(module, req);
78 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
79 ret = ldb_request(ldb_module_get_ctx(module), req);
80 } else {
81 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
82 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
83 ret = ops->search(module, req);
85 if (ret == LDB_SUCCESS) {
86 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
89 if (ret != LDB_SUCCESS) {
90 talloc_free(tmp_ctx);
91 return ret;
94 if (res->count != 1) {
95 /* we may be reading a DB that does not have the 'check base on search' option... */
96 ret = LDB_ERR_NO_SUCH_OBJECT;
97 ldb_asprintf_errstring(ldb_module_get_ctx(module),
98 "dsdb_module_search_dn: did not find base dn %s (%d results)",
99 ldb_dn_get_linearized(basedn), res->count);
100 } else {
101 *_res = talloc_steal(mem_ctx, res);
103 talloc_free(tmp_ctx);
104 return ret;
108 search for attrs in the modules below
110 int dsdb_module_search(struct ldb_module *module,
111 TALLOC_CTX *mem_ctx,
112 struct ldb_result **_res,
113 struct ldb_dn *basedn, enum ldb_scope scope,
114 const char * const *attrs,
115 int dsdb_flags,
116 const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
118 int ret;
119 struct ldb_request *req;
120 TALLOC_CTX *tmp_ctx;
121 struct ldb_result *res;
122 va_list ap;
123 char *expression;
125 tmp_ctx = talloc_new(mem_ctx);
127 if (format) {
128 va_start(ap, format);
129 expression = talloc_vasprintf(tmp_ctx, format, ap);
130 va_end(ap);
132 if (!expression) {
133 talloc_free(tmp_ctx);
134 return ldb_oom(ldb_module_get_ctx(module));
136 } else {
137 expression = NULL;
140 res = talloc_zero(tmp_ctx, struct ldb_result);
141 if (!res) {
142 talloc_free(tmp_ctx);
143 return ldb_oom(ldb_module_get_ctx(module));
146 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
147 basedn,
148 scope,
149 expression,
150 attrs,
151 NULL,
152 res,
153 ldb_search_default_callback,
154 NULL);
155 if (ret != LDB_SUCCESS) {
156 talloc_free(tmp_ctx);
157 return ret;
160 ret = dsdb_request_add_controls(req, dsdb_flags);
161 if (ret != LDB_SUCCESS) {
162 talloc_free(tmp_ctx);
163 return ret;
166 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
167 ret = ldb_next_request(module, req);
168 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
169 ret = ldb_request(ldb_module_get_ctx(module), req);
170 } else {
171 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
172 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
173 ret = ops->search(module, req);
175 if (ret == LDB_SUCCESS) {
176 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
179 talloc_free(req);
180 if (ret == LDB_SUCCESS) {
181 *_res = talloc_steal(mem_ctx, res);
183 talloc_free(tmp_ctx);
184 return ret;
188 find a DN given a GUID. This searches across all partitions
190 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
191 const struct GUID *guid, struct ldb_dn **dn)
193 struct ldb_result *res;
194 const char *attrs[] = { NULL };
195 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
196 int ret;
198 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
199 attrs,
200 DSDB_FLAG_NEXT_MODULE |
201 DSDB_SEARCH_SHOW_DELETED |
202 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
203 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
204 "objectGUID=%s", GUID_string(tmp_ctx, guid));
205 if (ret != LDB_SUCCESS) {
206 talloc_free(tmp_ctx);
207 return ret;
209 if (res->count == 0) {
210 talloc_free(tmp_ctx);
211 return LDB_ERR_NO_SUCH_OBJECT;
213 if (res->count != 1) {
214 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
215 GUID_string(tmp_ctx, guid));
216 talloc_free(tmp_ctx);
217 return LDB_ERR_OPERATIONS_ERROR;
220 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
222 talloc_free(tmp_ctx);
223 return LDB_SUCCESS;
227 find a GUID given a DN.
229 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
231 const char *attrs[] = { NULL };
232 struct ldb_result *res;
233 TALLOC_CTX *tmp_ctx = talloc_new(module);
234 int ret;
235 NTSTATUS status;
237 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
238 DSDB_FLAG_NEXT_MODULE |
239 DSDB_SEARCH_SHOW_DELETED |
240 DSDB_SEARCH_SHOW_EXTENDED_DN);
241 if (ret != LDB_SUCCESS) {
242 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
243 ldb_dn_get_linearized(dn));
244 talloc_free(tmp_ctx);
245 return ret;
248 status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
249 if (!NT_STATUS_IS_OK(status)) {
250 talloc_free(tmp_ctx);
251 return ldb_operr(ldb_module_get_ctx(module));
254 talloc_free(tmp_ctx);
255 return LDB_SUCCESS;
259 a ldb_modify request operating on modules below the
260 current module
262 int dsdb_module_modify(struct ldb_module *module,
263 const struct ldb_message *message,
264 uint32_t dsdb_flags)
266 struct ldb_request *mod_req;
267 int ret;
268 struct ldb_context *ldb = ldb_module_get_ctx(module);
269 TALLOC_CTX *tmp_ctx = talloc_new(module);
270 struct ldb_result *res;
272 res = talloc_zero(tmp_ctx, struct ldb_result);
273 if (!res) {
274 talloc_free(tmp_ctx);
275 return ldb_oom(ldb_module_get_ctx(module));
278 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
279 message,
280 NULL,
281 res,
282 ldb_modify_default_callback,
283 NULL);
284 if (ret != LDB_SUCCESS) {
285 talloc_free(tmp_ctx);
286 return ret;
289 ret = dsdb_request_add_controls(mod_req, dsdb_flags);
290 if (ret != LDB_SUCCESS) {
291 talloc_free(tmp_ctx);
292 return ret;
295 /* Run the new request */
296 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
297 ret = ldb_next_request(module, mod_req);
298 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
299 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
300 } else {
301 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
302 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
303 ret = ops->modify(module, mod_req);
305 if (ret == LDB_SUCCESS) {
306 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
309 talloc_free(tmp_ctx);
310 return ret;
316 a ldb_rename request operating on modules below the
317 current module
319 int dsdb_module_rename(struct ldb_module *module,
320 struct ldb_dn *olddn, struct ldb_dn *newdn,
321 uint32_t dsdb_flags)
323 struct ldb_request *req;
324 int ret;
325 struct ldb_context *ldb = ldb_module_get_ctx(module);
326 TALLOC_CTX *tmp_ctx = talloc_new(module);
327 struct ldb_result *res;
329 res = talloc_zero(tmp_ctx, struct ldb_result);
330 if (!res) {
331 talloc_free(tmp_ctx);
332 return ldb_oom(ldb_module_get_ctx(module));
335 ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
336 olddn,
337 newdn,
338 NULL,
339 res,
340 ldb_modify_default_callback,
341 NULL);
342 if (ret != LDB_SUCCESS) {
343 talloc_free(tmp_ctx);
344 return ret;
347 ret = dsdb_request_add_controls(req, dsdb_flags);
348 if (ret != LDB_SUCCESS) {
349 talloc_free(tmp_ctx);
350 return ret;
353 /* Run the new request */
354 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
355 ret = ldb_next_request(module, req);
356 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
357 ret = ldb_request(ldb_module_get_ctx(module), req);
358 } else {
359 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
360 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
361 ret = ops->rename(module, req);
363 if (ret == LDB_SUCCESS) {
364 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
367 talloc_free(tmp_ctx);
368 return ret;
372 a ldb_add request operating on modules below the
373 current module
375 int dsdb_module_add(struct ldb_module *module,
376 const struct ldb_message *message,
377 uint32_t dsdb_flags)
379 struct ldb_request *req;
380 int ret;
381 struct ldb_context *ldb = ldb_module_get_ctx(module);
382 TALLOC_CTX *tmp_ctx = talloc_new(module);
383 struct ldb_result *res;
385 res = talloc_zero(tmp_ctx, struct ldb_result);
386 if (!res) {
387 talloc_free(tmp_ctx);
388 return ldb_oom(ldb_module_get_ctx(module));
391 ret = ldb_build_add_req(&req, ldb, tmp_ctx,
392 message,
393 NULL,
394 res,
395 ldb_modify_default_callback,
396 NULL);
397 if (ret != LDB_SUCCESS) {
398 talloc_free(tmp_ctx);
399 return ret;
402 ret = dsdb_request_add_controls(req, dsdb_flags);
403 if (ret != LDB_SUCCESS) {
404 talloc_free(tmp_ctx);
405 return ret;
408 /* Run the new request */
409 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
410 ret = ldb_next_request(module, req);
411 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
412 ret = ldb_request(ldb_module_get_ctx(module), req);
413 } else {
414 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
415 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
416 ret = ops->add(module, req);
418 if (ret == LDB_SUCCESS) {
419 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
422 talloc_free(tmp_ctx);
423 return ret;
427 a ldb_delete request operating on modules below the
428 current module
430 int dsdb_module_del(struct ldb_module *module,
431 struct ldb_dn *dn,
432 uint32_t dsdb_flags)
434 struct ldb_request *req;
435 int ret;
436 struct ldb_context *ldb = ldb_module_get_ctx(module);
437 TALLOC_CTX *tmp_ctx = talloc_new(module);
438 struct ldb_result *res;
440 res = talloc_zero(tmp_ctx, struct ldb_result);
441 if (!res) {
442 talloc_free(tmp_ctx);
443 return ldb_oom(ldb);
446 ret = ldb_build_del_req(&req, ldb, tmp_ctx,
448 NULL,
449 res,
450 ldb_modify_default_callback,
451 NULL);
452 if (ret != LDB_SUCCESS) {
453 talloc_free(tmp_ctx);
454 return ret;
457 ret = dsdb_request_add_controls(req, dsdb_flags);
458 if (ret != LDB_SUCCESS) {
459 talloc_free(tmp_ctx);
460 return ret;
463 /* Run the new request */
464 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
465 ret = ldb_next_request(module, req);
466 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
467 ret = ldb_request(ldb_module_get_ctx(module), req);
468 } else {
469 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
470 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
471 ret = ops->del(module, req);
473 if (ret == LDB_SUCCESS) {
474 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
477 talloc_free(tmp_ctx);
478 return ret;
481 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
483 const struct dsdb_class *last_class = NULL;
484 unsigned int i;
486 for (i = 0; i < element->num_values; i++){
487 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
489 if(tmp_class == NULL) {
490 continue;
493 if(tmp_class->objectClassCategory > 1) {
494 continue;
497 if (!last_class) {
498 last_class = tmp_class;
499 } else {
500 if (tmp_class->subClass_order > last_class->subClass_order)
501 last_class = tmp_class;
505 return last_class;
509 check if a single valued link has multiple non-deleted values
511 This is needed when we will be using the RELAX control to stop
512 ldb_tdb from checking single valued links
514 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
515 const struct ldb_message_element *el)
517 bool found_active = false;
518 unsigned int i;
520 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
521 el->num_values < 2) {
522 return LDB_SUCCESS;
525 for (i=0; i<el->num_values; i++) {
526 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
527 if (found_active) {
528 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
530 found_active = true;
534 return LDB_SUCCESS;
537 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
538 struct GUID op_feature_guid, bool *feature_enabled)
540 TALLOC_CTX *tmp_ctx;
541 struct ldb_context *ldb = ldb_module_get_ctx(module);
542 struct ldb_result *res;
543 struct ldb_dn *search_dn;
544 struct GUID search_guid;
545 const char *attrs[] = {"msDS-EnabledFeature", NULL};
546 int ret;
547 unsigned int i;
548 struct ldb_message_element *el;
550 *feature_enabled = false;
552 tmp_ctx = talloc_new(ldb);
554 ret = ldb_search(ldb, tmp_ctx, &res,
555 scope, LDB_SCOPE_BASE, attrs,
556 NULL);
557 if (ret != LDB_SUCCESS) {
558 ldb_asprintf_errstring(ldb,
559 "Could no find the scope object - dn: %s\n",
560 ldb_dn_get_linearized(scope));
561 talloc_free(tmp_ctx);
562 return LDB_ERR_OPERATIONS_ERROR;
564 if (res->msgs[0]->num_elements > 0) {
566 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
568 attrs[0] = "msDS-OptionalFeatureGUID";
570 for (i=0; i<el->num_values; i++) {
571 search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
573 ret = ldb_search(ldb, tmp_ctx, &res,
574 search_dn, LDB_SCOPE_BASE, attrs,
575 NULL);
576 if (ret != LDB_SUCCESS) {
577 ldb_asprintf_errstring(ldb,
578 "Could no find object dn: %s\n",
579 ldb_dn_get_linearized(search_dn));
580 talloc_free(tmp_ctx);
581 return LDB_ERR_OPERATIONS_ERROR;
584 search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
586 if (GUID_compare(&search_guid, &op_feature_guid) == 0){
587 *feature_enabled = true;
588 break;
592 talloc_free(tmp_ctx);
593 return LDB_SUCCESS;
597 find a 'reference' DN that points at another object
598 (eg. serverReference, rIDManagerReference etc)
600 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
601 const char *attribute, struct ldb_dn **dn)
603 const char *attrs[2];
604 struct ldb_result *res;
605 int ret;
607 attrs[0] = attribute;
608 attrs[1] = NULL;
610 ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
611 DSDB_FLAG_NEXT_MODULE);
612 if (ret != LDB_SUCCESS) {
613 return ret;
616 *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
617 mem_ctx, res->msgs[0], attribute);
618 if (!*dn) {
619 talloc_free(res);
620 return LDB_ERR_NO_SUCH_ATTRIBUTE;
623 talloc_free(res);
624 return LDB_SUCCESS;
628 find the RID Manager$ DN via the rIDManagerReference attribute in the
629 base DN
631 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
633 return dsdb_module_reference_dn(module, mem_ctx,
634 ldb_get_default_basedn(ldb_module_get_ctx(module)),
635 "rIDManagerReference", dn);
640 update an integer attribute safely via a constrained delete/add
642 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
643 const char *attr, uint64_t old_val, uint64_t new_val)
645 struct ldb_message *msg;
646 struct ldb_message_element *el;
647 struct ldb_val v1, v2;
648 int ret;
649 char *vstring;
651 msg = ldb_msg_new(module);
652 msg->dn = dn;
654 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
655 if (ret != LDB_SUCCESS) {
656 talloc_free(msg);
657 return ret;
659 el->num_values = 1;
660 el->values = &v1;
661 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
662 if (!vstring) {
663 talloc_free(msg);
664 return ldb_module_oom(module);
666 v1 = data_blob_string_const(vstring);
668 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
669 if (ret != LDB_SUCCESS) {
670 talloc_free(msg);
671 return ret;
673 el->num_values = 1;
674 el->values = &v2;
675 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
676 if (!vstring) {
677 talloc_free(msg);
678 return ldb_module_oom(module);
680 v2 = data_blob_string_const(vstring);
682 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
683 talloc_free(msg);
684 return ret;
688 used to chain to the callers callback
690 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
692 struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
694 talloc_steal(up_req, req);
695 return up_req->callback(up_req, ares);
700 set an integer attribute
702 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
703 const char *attr, uint64_t new_val)
705 struct ldb_message *msg;
706 int ret;
708 msg = ldb_msg_new(module);
709 msg->dn = dn;
711 ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
712 if (ret != LDB_SUCCESS) {
713 talloc_free(msg);
714 return ret;
716 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
718 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
719 talloc_free(msg);
720 return ret;
724 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
725 object for a partition
727 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
728 uint64_t *uSN, uint64_t *urgent_uSN)
730 struct ldb_context *ldb = ldb_module_get_ctx(module);
731 struct ldb_request *req;
732 int ret;
733 TALLOC_CTX *tmp_ctx = talloc_new(module);
734 struct dsdb_control_current_partition *p_ctrl;
735 struct ldb_result *res;
737 res = talloc_zero(tmp_ctx, struct ldb_result);
738 if (!res) {
739 talloc_free(tmp_ctx);
740 return ldb_module_oom(module);
743 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
744 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
745 LDB_SCOPE_BASE,
746 NULL, NULL,
747 NULL,
748 res, ldb_search_default_callback,
749 NULL);
750 if (ret != LDB_SUCCESS) {
751 talloc_free(tmp_ctx);
752 return ret;
755 p_ctrl = talloc(req, struct dsdb_control_current_partition);
756 if (p_ctrl == NULL) {
757 talloc_free(tmp_ctx);
758 return ldb_module_oom(module);
760 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
761 p_ctrl->dn = dn;
764 ret = ldb_request_add_control(req,
765 DSDB_CONTROL_CURRENT_PARTITION_OID,
766 false, p_ctrl);
767 if (ret != LDB_SUCCESS) {
768 talloc_free(tmp_ctx);
769 return ret;
772 /* Run the new request */
773 ret = ldb_next_request(module, req);
775 if (ret == LDB_SUCCESS) {
776 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
779 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
780 /* it hasn't been created yet, which means
781 an implicit value of zero */
782 *uSN = 0;
783 talloc_free(tmp_ctx);
784 return LDB_SUCCESS;
787 if (ret != LDB_SUCCESS) {
788 talloc_free(tmp_ctx);
789 return ret;
792 if (res->count != 1) {
793 *uSN = 0;
794 if (urgent_uSN) {
795 *urgent_uSN = 0;
797 } else {
798 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
799 if (urgent_uSN) {
800 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
804 talloc_free(tmp_ctx);
806 return LDB_SUCCESS;
810 save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
811 partition
813 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
814 uint64_t uSN, uint64_t urgent_uSN)
816 struct ldb_context *ldb = ldb_module_get_ctx(module);
817 struct ldb_request *req;
818 struct ldb_message *msg;
819 struct dsdb_control_current_partition *p_ctrl;
820 int ret;
821 struct ldb_result *res;
823 msg = ldb_msg_new(module);
824 if (msg == NULL) {
825 return ldb_module_oom(module);
828 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
829 if (msg->dn == NULL) {
830 talloc_free(msg);
831 return ldb_operr(ldb_module_get_ctx(module));
834 res = talloc_zero(msg, struct ldb_result);
835 if (!res) {
836 talloc_free(msg);
837 return ldb_module_oom(module);
840 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
841 if (ret != LDB_SUCCESS) {
842 talloc_free(msg);
843 return ret;
845 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
847 /* urgent_uSN is optional so may not be stored */
848 if (urgent_uSN) {
849 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
850 if (ret != LDB_SUCCESS) {
851 talloc_free(msg);
852 return ret;
854 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
858 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
859 if (p_ctrl == NULL) {
860 talloc_free(msg);
861 return ldb_oom(ldb);
863 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
864 p_ctrl->dn = dn;
865 ret = ldb_build_mod_req(&req, ldb, msg,
866 msg,
867 NULL,
868 res,
869 ldb_modify_default_callback,
870 NULL);
871 again:
872 if (ret != LDB_SUCCESS) {
873 talloc_free(msg);
874 return ret;
877 ret = ldb_request_add_control(req,
878 DSDB_CONTROL_CURRENT_PARTITION_OID,
879 false, p_ctrl);
880 if (ret != LDB_SUCCESS) {
881 talloc_free(msg);
882 return ret;
885 /* Run the new request */
886 ret = ldb_next_request(module, req);
888 if (ret == LDB_SUCCESS) {
889 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
891 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
892 ret = ldb_build_add_req(&req, ldb, msg,
893 msg,
894 NULL,
895 res,
896 ldb_modify_default_callback,
897 NULL);
898 goto again;
901 talloc_free(msg);
903 return ret;
906 bool dsdb_module_am_system(struct ldb_module *module)
908 struct ldb_context *ldb = ldb_module_get_ctx(module);
909 struct auth_session_info *session_info
910 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
911 return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
914 bool dsdb_module_am_administrator(struct ldb_module *module)
916 struct ldb_context *ldb = ldb_module_get_ctx(module);
917 struct auth_session_info *session_info
918 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
919 return security_session_user_level(session_info, NULL) == SECURITY_ADMINISTRATOR;
923 check if the recyclebin is enabled
925 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
927 struct ldb_context *ldb = ldb_module_get_ctx(module);
928 struct ldb_dn *partitions_dn;
929 struct GUID recyclebin_guid;
930 int ret;
932 partitions_dn = samdb_partitions_dn(ldb, module);
934 GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
936 ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
937 if (ret != LDB_SUCCESS) {
938 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
939 talloc_free(partitions_dn);
940 return LDB_ERR_UNWILLING_TO_PERFORM;
943 talloc_free(partitions_dn);
944 return LDB_SUCCESS;
947 bool is_attr_in_list(const char * const * attrs, const char *attr)
949 unsigned int i;
951 for (i = 0; attrs[i]; i++) {
952 if (ldb_attr_cmp(attrs[i], attr) == 0)
953 return true;
956 return false;
959 int dsdb_msg_constrainted_update_int32(struct ldb_module *module,
960 struct ldb_message *msg,
961 const char *attr,
962 const int32_t *old_val,
963 const int32_t *new_val)
965 struct ldb_message_element *el;
966 int ret;
967 char *vstring;
969 if (old_val) {
970 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
971 if (ret != LDB_SUCCESS) {
972 return ret;
974 el->num_values = 1;
975 el->values = talloc_array(msg, struct ldb_val, el->num_values);
976 if (!el->values) {
977 return ldb_module_oom(module);
979 vstring = talloc_asprintf(el->values, "%ld", (long)*old_val);
980 if (!vstring) {
981 return ldb_module_oom(module);
983 *el->values = data_blob_string_const(vstring);
986 if (new_val) {
987 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
988 if (ret != LDB_SUCCESS) {
989 return ret;
991 el->num_values = 1;
992 el->values = talloc_array(msg, struct ldb_val, el->num_values);
993 if (!el->values) {
994 return ldb_module_oom(module);
996 vstring = talloc_asprintf(el->values, "%ld", (long)*new_val);
997 if (!vstring) {
998 return ldb_module_oom(module);
1000 *el->values = data_blob_string_const(vstring);
1003 return LDB_SUCCESS;
1006 int dsdb_msg_constrainted_update_uint32(struct ldb_module *module,
1007 struct ldb_message *msg,
1008 const char *attr,
1009 const uint32_t *old_val,
1010 const uint32_t *new_val)
1012 return dsdb_msg_constrainted_update_int32(module, msg, attr,
1013 (const int32_t *)old_val,
1014 (const int32_t *)new_val);
1017 int dsdb_msg_constrainted_update_int64(struct ldb_module *module,
1018 struct ldb_message *msg,
1019 const char *attr,
1020 const int64_t *old_val,
1021 const int64_t *new_val)
1023 struct ldb_message_element *el;
1024 int ret;
1025 char *vstring;
1027 if (old_val) {
1028 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1029 if (ret != LDB_SUCCESS) {
1030 return ret;
1032 el->num_values = 1;
1033 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1034 if (!el->values) {
1035 return ldb_module_oom(module);
1037 vstring = talloc_asprintf(el->values, "%lld", (long long)*old_val);
1038 if (!vstring) {
1039 return ldb_module_oom(module);
1041 *el->values = data_blob_string_const(vstring);
1044 if (new_val) {
1045 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1046 if (ret != LDB_SUCCESS) {
1047 return ret;
1049 el->num_values = 1;
1050 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1051 if (!el->values) {
1052 return ldb_module_oom(module);
1054 vstring = talloc_asprintf(el->values, "%lld", (long long)*new_val);
1055 if (!vstring) {
1056 return ldb_module_oom(module);
1058 *el->values = data_blob_string_const(vstring);
1061 return LDB_SUCCESS;
1064 int dsdb_msg_constrainted_update_uint64(struct ldb_module *module,
1065 struct ldb_message *msg,
1066 const char *attr,
1067 const uint64_t *old_val,
1068 const uint64_t *new_val)
1070 return dsdb_msg_constrainted_update_int64(module, msg, attr,
1071 (const int64_t *)old_val,
1072 (const int64_t *)new_val);
1076 update an int32 attribute safely via a constrained delete/add
1078 int dsdb_module_constrainted_update_int32(struct ldb_module *module,
1079 struct ldb_dn *dn,
1080 const char *attr,
1081 const int32_t *old_val,
1082 const int32_t *new_val)
1084 struct ldb_message *msg;
1085 int ret;
1087 msg = ldb_msg_new(module);
1088 msg->dn = dn;
1090 ret = dsdb_msg_constrainted_update_int32(module,
1091 msg, attr,
1092 old_val,
1093 new_val);
1094 if (ret != LDB_SUCCESS) {
1095 talloc_free(msg);
1096 return ret;
1099 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1100 talloc_free(msg);
1101 return ret;
1104 int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
1105 struct ldb_dn *dn,
1106 const char *attr,
1107 const uint32_t *old_val,
1108 const uint32_t *new_val)
1110 return dsdb_module_constrainted_update_int32(module, dn, attr,
1111 (const int32_t *)old_val,
1112 (const int32_t *)new_val);
1116 update an int64 attribute safely via a constrained delete/add
1118 int dsdb_module_constrainted_update_int64(struct ldb_module *module,
1119 struct ldb_dn *dn,
1120 const char *attr,
1121 const int64_t *old_val,
1122 const int64_t *new_val)
1124 struct ldb_message *msg;
1125 int ret;
1127 msg = ldb_msg_new(module);
1128 msg->dn = dn;
1130 ret = dsdb_msg_constrainted_update_int64(module,
1131 msg, attr,
1132 old_val,
1133 new_val);
1134 if (ret != LDB_SUCCESS) {
1135 talloc_free(msg);
1136 return ret;
1139 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1140 talloc_free(msg);
1141 return ret;
1144 int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
1145 struct ldb_dn *dn,
1146 const char *attr,
1147 const uint64_t *old_val,
1148 const uint64_t *new_val)
1150 return dsdb_module_constrainted_update_int64(module, dn, attr,
1151 (const int64_t *)old_val,
1152 (const int64_t *)new_val);
1156 const struct ldb_val *dsdb_module_find_dsheuristics(struct ldb_module *module,
1157 TALLOC_CTX *mem_ctx)
1159 int ret;
1160 struct ldb_dn *new_dn;
1161 struct ldb_context *ldb = ldb_module_get_ctx(module);
1162 static const char *attrs[] = { "dsHeuristics", NULL };
1163 struct ldb_result *res;
1165 new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(ldb));
1166 if (!ldb_dn_add_child_fmt(new_dn,
1167 "CN=Directory Service,CN=Windows NT,CN=Services")) {
1168 talloc_free(new_dn);
1169 return NULL;
1171 ret = dsdb_module_search_dn(module, mem_ctx, &res,
1172 new_dn,
1173 attrs,
1174 DSDB_FLAG_NEXT_MODULE);
1175 if (ret == LDB_SUCCESS && res->count == 1) {
1176 talloc_free(new_dn);
1177 return ldb_msg_find_ldb_val(res->msgs[0],
1178 "dsHeuristics");
1180 talloc_free(new_dn);
1181 return NULL;
1184 bool dsdb_block_anonymous_ops(struct ldb_module *module,
1185 TALLOC_CTX *mem_ctx)
1187 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1188 bool result;
1189 const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
1190 tmp_ctx);
1191 if (hr_val == NULL || hr_val->length < DS_HR_BLOCK_ANONYMOUS_OPS) {
1192 result = true;
1193 } else if (hr_val->data[DS_HR_BLOCK_ANONYMOUS_OPS -1] == '2') {
1194 result = false;
1195 } else {
1196 result = true;
1199 talloc_free(tmp_ctx);
1200 return result;
1204 show the chain of requests, useful for debugging async requests
1206 void dsdb_req_chain_debug(struct ldb_request *req, int level)
1208 char *ret;
1209 int i=0;
1211 while (req && req->handle) {
1212 DEBUG(level,("req[%u] %p : %s\n", i++, req, ldb_req_location(req)));
1213 req = req->handle->parent;