s4:dsdb: add dsdb_module_constrainted_update_uint32/64() wrapper functions
[Samba/ita.git] / source4 / dsdb / samdb / ldb_modules / util.c
blobf7218d4d883eb4e3839ad7bcaaecd2a4fd4ecc91
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"
32 search for attrs on one DN, in the modules below
34 int dsdb_module_search_dn(struct ldb_module *module,
35 TALLOC_CTX *mem_ctx,
36 struct ldb_result **_res,
37 struct ldb_dn *basedn,
38 const char * const *attrs,
39 uint32_t dsdb_flags)
41 int ret;
42 struct ldb_request *req;
43 TALLOC_CTX *tmp_ctx;
44 struct ldb_result *res;
46 tmp_ctx = talloc_new(mem_ctx);
48 res = talloc_zero(tmp_ctx, struct ldb_result);
49 if (!res) {
50 talloc_free(tmp_ctx);
51 return ldb_oom(ldb_module_get_ctx(module));
54 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
55 basedn,
56 LDB_SCOPE_BASE,
57 NULL,
58 attrs,
59 NULL,
60 res,
61 ldb_search_default_callback,
62 NULL);
63 if (ret != LDB_SUCCESS) {
64 talloc_free(tmp_ctx);
65 return ret;
68 ret = dsdb_request_add_controls(req, dsdb_flags);
69 if (ret != LDB_SUCCESS) {
70 talloc_free(tmp_ctx);
71 return ret;
74 /* Run the new request */
75 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
76 ret = ldb_next_request(module, req);
77 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
78 ret = ldb_request(ldb_module_get_ctx(module), req);
79 } else {
80 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
81 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
82 ret = ops->modify(module, req);
84 if (ret == LDB_SUCCESS) {
85 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
88 if (ret != LDB_SUCCESS) {
89 talloc_free(tmp_ctx);
90 return ret;
93 if (res->count != 1) {
94 /* we may be reading a DB that does not have the 'check base on search' option... */
95 ret = LDB_ERR_NO_SUCH_OBJECT;
96 ldb_asprintf_errstring(ldb_module_get_ctx(module),
97 "dsdb_module_search_dn: did not find base dn %s (%d results)",
98 ldb_dn_get_linearized(basedn), res->count);
99 } else {
100 *_res = talloc_steal(mem_ctx, res);
102 talloc_free(tmp_ctx);
103 return ret;
107 search for attrs in the modules below
109 int dsdb_module_search(struct ldb_module *module,
110 TALLOC_CTX *mem_ctx,
111 struct ldb_result **_res,
112 struct ldb_dn *basedn, enum ldb_scope scope,
113 const char * const *attrs,
114 int dsdb_flags,
115 const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
117 int ret;
118 struct ldb_request *req;
119 TALLOC_CTX *tmp_ctx;
120 struct ldb_result *res;
121 va_list ap;
122 char *expression;
124 tmp_ctx = talloc_new(mem_ctx);
126 if (format) {
127 va_start(ap, format);
128 expression = talloc_vasprintf(tmp_ctx, format, ap);
129 va_end(ap);
131 if (!expression) {
132 talloc_free(tmp_ctx);
133 return ldb_oom(ldb_module_get_ctx(module));
135 } else {
136 expression = NULL;
139 res = talloc_zero(tmp_ctx, struct ldb_result);
140 if (!res) {
141 talloc_free(tmp_ctx);
142 return ldb_oom(ldb_module_get_ctx(module));
145 ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
146 basedn,
147 scope,
148 expression,
149 attrs,
150 NULL,
151 res,
152 ldb_search_default_callback,
153 NULL);
154 if (ret != LDB_SUCCESS) {
155 talloc_free(tmp_ctx);
156 return ret;
159 ret = dsdb_request_add_controls(req, dsdb_flags);
160 if (ret != LDB_SUCCESS) {
161 talloc_free(tmp_ctx);
162 return ret;
165 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
166 ret = ldb_next_request(module, req);
167 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
168 ret = ldb_request(ldb_module_get_ctx(module), req);
169 } else {
170 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
171 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
172 ret = ops->search(module, req);
174 if (ret == LDB_SUCCESS) {
175 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
178 talloc_free(req);
179 if (ret == LDB_SUCCESS) {
180 *_res = talloc_steal(mem_ctx, res);
182 talloc_free(tmp_ctx);
183 return ret;
187 find a DN given a GUID. This searches across all partitions
189 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
190 const struct GUID *guid, struct ldb_dn **dn)
192 struct ldb_result *res;
193 const char *attrs[] = { NULL };
194 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
195 int ret;
197 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
198 attrs,
199 DSDB_FLAG_NEXT_MODULE |
200 DSDB_SEARCH_SHOW_DELETED |
201 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
202 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
203 "objectGUID=%s", GUID_string(tmp_ctx, guid));
204 if (ret != LDB_SUCCESS) {
205 talloc_free(tmp_ctx);
206 return ret;
208 if (res->count == 0) {
209 talloc_free(tmp_ctx);
210 return LDB_ERR_NO_SUCH_OBJECT;
212 if (res->count != 1) {
213 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
214 GUID_string(tmp_ctx, guid));
215 talloc_free(tmp_ctx);
216 return LDB_ERR_OPERATIONS_ERROR;
219 *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
221 talloc_free(tmp_ctx);
222 return LDB_SUCCESS;
226 find a GUID given a DN.
228 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
230 const char *attrs[] = { NULL };
231 struct ldb_result *res;
232 TALLOC_CTX *tmp_ctx = talloc_new(module);
233 int ret;
234 NTSTATUS status;
236 ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
237 DSDB_FLAG_NEXT_MODULE |
238 DSDB_SEARCH_SHOW_DELETED |
239 DSDB_SEARCH_SHOW_EXTENDED_DN);
240 if (ret != LDB_SUCCESS) {
241 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
242 ldb_dn_get_linearized(dn));
243 talloc_free(tmp_ctx);
244 return ret;
247 status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
248 if (!NT_STATUS_IS_OK(status)) {
249 talloc_free(tmp_ctx);
250 return ldb_operr(ldb_module_get_ctx(module));
253 talloc_free(tmp_ctx);
254 return LDB_SUCCESS;
258 a ldb_modify request operating on modules below the
259 current module
261 int dsdb_module_modify(struct ldb_module *module,
262 const struct ldb_message *message,
263 uint32_t dsdb_flags)
265 struct ldb_request *mod_req;
266 int ret;
267 struct ldb_context *ldb = ldb_module_get_ctx(module);
268 TALLOC_CTX *tmp_ctx = talloc_new(module);
269 struct ldb_result *res;
271 res = talloc_zero(tmp_ctx, struct ldb_result);
272 if (!res) {
273 talloc_free(tmp_ctx);
274 return ldb_oom(ldb_module_get_ctx(module));
277 ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
278 message,
279 NULL,
280 res,
281 ldb_modify_default_callback,
282 NULL);
283 if (ret != LDB_SUCCESS) {
284 talloc_free(tmp_ctx);
285 return ret;
288 ret = dsdb_request_add_controls(mod_req, dsdb_flags);
289 if (ret != LDB_SUCCESS) {
290 talloc_free(tmp_ctx);
291 return ret;
294 /* Run the new request */
295 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
296 ret = ldb_next_request(module, mod_req);
297 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
298 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
299 } else {
300 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
301 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
302 ret = ops->modify(module, mod_req);
304 if (ret == LDB_SUCCESS) {
305 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
308 talloc_free(tmp_ctx);
309 return ret;
315 a ldb_rename request operating on modules below the
316 current module
318 int dsdb_module_rename(struct ldb_module *module,
319 struct ldb_dn *olddn, struct ldb_dn *newdn,
320 uint32_t dsdb_flags)
322 struct ldb_request *req;
323 int ret;
324 struct ldb_context *ldb = ldb_module_get_ctx(module);
325 TALLOC_CTX *tmp_ctx = talloc_new(module);
326 struct ldb_result *res;
328 res = talloc_zero(tmp_ctx, struct ldb_result);
329 if (!res) {
330 talloc_free(tmp_ctx);
331 return ldb_oom(ldb_module_get_ctx(module));
334 ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
335 olddn,
336 newdn,
337 NULL,
338 res,
339 ldb_modify_default_callback,
340 NULL);
341 if (ret != LDB_SUCCESS) {
342 talloc_free(tmp_ctx);
343 return ret;
346 ret = dsdb_request_add_controls(req, dsdb_flags);
347 if (ret != LDB_SUCCESS) {
348 talloc_free(tmp_ctx);
349 return ret;
352 /* Run the new request */
353 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
354 ret = ldb_next_request(module, req);
355 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
356 ret = ldb_request(ldb_module_get_ctx(module), req);
357 } else {
358 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
359 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
360 ret = ops->rename(module, req);
362 if (ret == LDB_SUCCESS) {
363 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
366 talloc_free(tmp_ctx);
367 return ret;
371 a ldb_add request operating on modules below the
372 current module
374 int dsdb_module_add(struct ldb_module *module,
375 const struct ldb_message *message,
376 uint32_t dsdb_flags)
378 struct ldb_request *req;
379 int ret;
380 struct ldb_context *ldb = ldb_module_get_ctx(module);
381 TALLOC_CTX *tmp_ctx = talloc_new(module);
382 struct ldb_result *res;
384 res = talloc_zero(tmp_ctx, struct ldb_result);
385 if (!res) {
386 talloc_free(tmp_ctx);
387 return ldb_oom(ldb_module_get_ctx(module));
390 ret = ldb_build_add_req(&req, ldb, tmp_ctx,
391 message,
392 NULL,
393 res,
394 ldb_modify_default_callback,
395 NULL);
396 if (ret != LDB_SUCCESS) {
397 talloc_free(tmp_ctx);
398 return ret;
401 ret = dsdb_request_add_controls(req, dsdb_flags);
402 if (ret != LDB_SUCCESS) {
403 talloc_free(tmp_ctx);
404 return ret;
407 /* Run the new request */
408 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
409 ret = ldb_next_request(module, req);
410 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
411 ret = ldb_request(ldb_module_get_ctx(module), req);
412 } else {
413 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
414 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
415 ret = ops->add(module, req);
417 if (ret == LDB_SUCCESS) {
418 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
421 talloc_free(tmp_ctx);
422 return ret;
426 a ldb_delete request operating on modules below the
427 current module
429 int dsdb_module_del(struct ldb_module *module,
430 struct ldb_dn *dn,
431 uint32_t dsdb_flags)
433 struct ldb_request *req;
434 int ret;
435 struct ldb_context *ldb = ldb_module_get_ctx(module);
436 TALLOC_CTX *tmp_ctx = talloc_new(module);
437 struct ldb_result *res;
439 res = talloc_zero(tmp_ctx, struct ldb_result);
440 if (!res) {
441 talloc_free(tmp_ctx);
442 return ldb_oom(ldb);
445 ret = ldb_build_del_req(&req, ldb, tmp_ctx,
447 NULL,
448 res,
449 ldb_modify_default_callback,
450 NULL);
451 if (ret != LDB_SUCCESS) {
452 talloc_free(tmp_ctx);
453 return ret;
456 ret = dsdb_request_add_controls(req, dsdb_flags);
457 if (ret != LDB_SUCCESS) {
458 talloc_free(tmp_ctx);
459 return ret;
462 /* Run the new request */
463 if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
464 ret = ldb_next_request(module, req);
465 } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
466 ret = ldb_request(ldb_module_get_ctx(module), req);
467 } else {
468 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
469 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
470 ret = ops->del(module, req);
472 if (ret == LDB_SUCCESS) {
473 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
476 talloc_free(tmp_ctx);
477 return ret;
480 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
482 const struct dsdb_class *last_class = NULL;
483 unsigned int i;
485 for (i = 0; i < element->num_values; i++){
486 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
488 if(tmp_class == NULL) {
489 continue;
492 if(tmp_class->objectClassCategory > 1) {
493 continue;
496 if (!last_class) {
497 last_class = tmp_class;
498 } else {
499 if (tmp_class->subClass_order > last_class->subClass_order)
500 last_class = tmp_class;
504 return last_class;
508 check if a single valued link has multiple non-deleted values
510 This is needed when we will be using the RELAX control to stop
511 ldb_tdb from checking single valued links
513 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
514 const struct ldb_message_element *el)
516 bool found_active = false;
517 unsigned int i;
519 if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
520 el->num_values < 2) {
521 return LDB_SUCCESS;
524 for (i=0; i<el->num_values; i++) {
525 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
526 if (found_active) {
527 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
529 found_active = true;
533 return LDB_SUCCESS;
536 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
537 struct GUID op_feature_guid, bool *feature_enabled)
539 TALLOC_CTX *tmp_ctx;
540 struct ldb_context *ldb = ldb_module_get_ctx(module);
541 struct ldb_result *res;
542 struct ldb_dn *search_dn;
543 struct GUID search_guid;
544 const char *attrs[] = {"msDS-EnabledFeature", NULL};
545 int ret;
546 unsigned int i;
547 struct ldb_message_element *el;
549 *feature_enabled = false;
551 tmp_ctx = talloc_new(ldb);
553 ret = ldb_search(ldb, tmp_ctx, &res,
554 scope, LDB_SCOPE_BASE, attrs,
555 NULL);
556 if (ret != LDB_SUCCESS) {
557 ldb_asprintf_errstring(ldb,
558 "Could no find the scope object - dn: %s\n",
559 ldb_dn_get_linearized(scope));
560 talloc_free(tmp_ctx);
561 return LDB_ERR_OPERATIONS_ERROR;
563 if (res->msgs[0]->num_elements > 0) {
565 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
567 attrs[0] = "msDS-OptionalFeatureGUID";
569 for (i=0; i<el->num_values; i++) {
570 search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
572 ret = ldb_search(ldb, tmp_ctx, &res,
573 search_dn, LDB_SCOPE_BASE, attrs,
574 NULL);
575 if (ret != LDB_SUCCESS) {
576 ldb_asprintf_errstring(ldb,
577 "Could no find object dn: %s\n",
578 ldb_dn_get_linearized(search_dn));
579 talloc_free(tmp_ctx);
580 return LDB_ERR_OPERATIONS_ERROR;
583 search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
585 if (GUID_compare(&search_guid, &op_feature_guid) == 0){
586 *feature_enabled = true;
587 break;
591 talloc_free(tmp_ctx);
592 return LDB_SUCCESS;
596 find a 'reference' DN that points at another object
597 (eg. serverReference, rIDManagerReference etc)
599 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
600 const char *attribute, struct ldb_dn **dn)
602 const char *attrs[2];
603 struct ldb_result *res;
604 int ret;
606 attrs[0] = attribute;
607 attrs[1] = NULL;
609 ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
610 DSDB_FLAG_NEXT_MODULE);
611 if (ret != LDB_SUCCESS) {
612 return ret;
615 *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
616 mem_ctx, res->msgs[0], attribute);
617 if (!*dn) {
618 talloc_free(res);
619 return LDB_ERR_NO_SUCH_ATTRIBUTE;
622 talloc_free(res);
623 return LDB_SUCCESS;
627 find the RID Manager$ DN via the rIDManagerReference attribute in the
628 base DN
630 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
632 return dsdb_module_reference_dn(module, mem_ctx,
633 ldb_get_default_basedn(ldb_module_get_ctx(module)),
634 "rIDManagerReference", dn);
639 update an integer attribute safely via a constrained delete/add
641 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
642 const char *attr, uint64_t old_val, uint64_t new_val)
644 struct ldb_message *msg;
645 struct ldb_message_element *el;
646 struct ldb_val v1, v2;
647 int ret;
648 char *vstring;
650 msg = ldb_msg_new(module);
651 msg->dn = dn;
653 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
654 if (ret != LDB_SUCCESS) {
655 talloc_free(msg);
656 return ret;
658 el->num_values = 1;
659 el->values = &v1;
660 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
661 if (!vstring) {
662 talloc_free(msg);
663 return ldb_module_oom(module);
665 v1 = data_blob_string_const(vstring);
667 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
668 if (ret != LDB_SUCCESS) {
669 talloc_free(msg);
670 return ret;
672 el->num_values = 1;
673 el->values = &v2;
674 vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
675 if (!vstring) {
676 talloc_free(msg);
677 return ldb_module_oom(module);
679 v2 = data_blob_string_const(vstring);
681 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
682 talloc_free(msg);
683 return ret;
687 used to chain to the callers callback
689 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
691 struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
693 talloc_steal(up_req, req);
694 return up_req->callback(up_req, ares);
699 set an integer attribute
701 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
702 const char *attr, uint64_t new_val)
704 struct ldb_message *msg;
705 int ret;
707 msg = ldb_msg_new(module);
708 msg->dn = dn;
710 ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
711 if (ret != LDB_SUCCESS) {
712 talloc_free(msg);
713 return ret;
715 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
717 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
718 talloc_free(msg);
719 return ret;
723 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
724 object for a partition
726 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
727 uint64_t *uSN, uint64_t *urgent_uSN)
729 struct ldb_context *ldb = ldb_module_get_ctx(module);
730 struct ldb_request *req;
731 int ret;
732 TALLOC_CTX *tmp_ctx = talloc_new(module);
733 struct dsdb_control_current_partition *p_ctrl;
734 struct ldb_result *res;
736 res = talloc_zero(tmp_ctx, struct ldb_result);
737 if (!res) {
738 talloc_free(tmp_ctx);
739 return ldb_module_oom(module);
742 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
743 ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
744 LDB_SCOPE_BASE,
745 NULL, NULL,
746 NULL,
747 res, ldb_search_default_callback,
748 NULL);
749 if (ret != LDB_SUCCESS) {
750 talloc_free(tmp_ctx);
751 return ret;
754 p_ctrl = talloc(req, struct dsdb_control_current_partition);
755 if (p_ctrl == NULL) {
756 talloc_free(tmp_ctx);
757 return ldb_module_oom(module);
759 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
760 p_ctrl->dn = dn;
763 ret = ldb_request_add_control(req,
764 DSDB_CONTROL_CURRENT_PARTITION_OID,
765 false, p_ctrl);
766 if (ret != LDB_SUCCESS) {
767 talloc_free(tmp_ctx);
768 return ret;
771 /* Run the new request */
772 ret = ldb_next_request(module, req);
774 if (ret == LDB_SUCCESS) {
775 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
778 if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
779 /* it hasn't been created yet, which means
780 an implicit value of zero */
781 *uSN = 0;
782 talloc_free(tmp_ctx);
783 return LDB_SUCCESS;
786 if (ret != LDB_SUCCESS) {
787 talloc_free(tmp_ctx);
788 return ret;
791 if (res->count != 1) {
792 *uSN = 0;
793 if (urgent_uSN) {
794 *urgent_uSN = 0;
796 } else {
797 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
798 if (urgent_uSN) {
799 *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
803 talloc_free(tmp_ctx);
805 return LDB_SUCCESS;
809 save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
810 partition
812 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
813 uint64_t uSN, uint64_t urgent_uSN)
815 struct ldb_context *ldb = ldb_module_get_ctx(module);
816 struct ldb_request *req;
817 struct ldb_message *msg;
818 struct dsdb_control_current_partition *p_ctrl;
819 int ret;
820 struct ldb_result *res;
822 msg = ldb_msg_new(module);
823 if (msg == NULL) {
824 return ldb_module_oom(module);
827 msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
828 if (msg->dn == NULL) {
829 talloc_free(msg);
830 return ldb_operr(ldb_module_get_ctx(module));
833 res = talloc_zero(msg, struct ldb_result);
834 if (!res) {
835 talloc_free(msg);
836 return ldb_module_oom(module);
839 ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
840 if (ret != LDB_SUCCESS) {
841 talloc_free(msg);
842 return ret;
844 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
846 /* urgent_uSN is optional so may not be stored */
847 if (urgent_uSN) {
848 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
849 if (ret != LDB_SUCCESS) {
850 talloc_free(msg);
851 return ret;
853 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
857 p_ctrl = talloc(msg, struct dsdb_control_current_partition);
858 if (p_ctrl == NULL) {
859 talloc_free(msg);
860 return ldb_oom(ldb);
862 p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
863 p_ctrl->dn = dn;
864 ret = ldb_build_mod_req(&req, ldb, msg,
865 msg,
866 NULL,
867 res,
868 ldb_modify_default_callback,
869 NULL);
870 again:
871 if (ret != LDB_SUCCESS) {
872 talloc_free(msg);
873 return ret;
876 ret = ldb_request_add_control(req,
877 DSDB_CONTROL_CURRENT_PARTITION_OID,
878 false, p_ctrl);
879 if (ret != LDB_SUCCESS) {
880 talloc_free(msg);
881 return ret;
884 /* Run the new request */
885 ret = ldb_next_request(module, req);
887 if (ret == LDB_SUCCESS) {
888 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
890 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
891 ret = ldb_build_add_req(&req, ldb, msg,
892 msg,
893 NULL,
894 res,
895 ldb_modify_default_callback,
896 NULL);
897 goto again;
900 talloc_free(msg);
902 return ret;
905 bool dsdb_module_am_system(struct ldb_module *module)
907 struct ldb_context *ldb = ldb_module_get_ctx(module);
908 struct auth_session_info *session_info
909 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
910 return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
914 check if the recyclebin is enabled
916 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
918 struct ldb_context *ldb = ldb_module_get_ctx(module);
919 struct ldb_dn *partitions_dn;
920 struct GUID recyclebin_guid;
921 int ret;
923 partitions_dn = samdb_partitions_dn(ldb, module);
925 GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
927 ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
928 if (ret != LDB_SUCCESS) {
929 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
930 talloc_free(partitions_dn);
931 return LDB_ERR_UNWILLING_TO_PERFORM;
934 talloc_free(partitions_dn);
935 return LDB_SUCCESS;
938 bool is_attr_in_list(const char * const * attrs, const char *attr)
940 unsigned int i;
942 for (i = 0; attrs[i]; i++) {
943 if (ldb_attr_cmp(attrs[i], attr) == 0)
944 return true;
947 return false;
950 int dsdb_msg_constrainted_update_int32(struct ldb_module *module,
951 struct ldb_message *msg,
952 const char *attr,
953 const int32_t *old_val,
954 const int32_t *new_val)
956 struct ldb_message_element *el;
957 struct ldb_val *v1, *v2;
958 int ret;
959 char *vstring;
961 if (old_val) {
962 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
963 if (ret != LDB_SUCCESS) {
964 return ret;
966 el->num_values = 1;
967 el->values = talloc_array(msg, struct ldb_val, el->num_values);
968 if (!el->values) {
969 return ldb_module_oom(module);
971 vstring = talloc_asprintf(el->values, "%ld", (long)*old_val);
972 if (!vstring) {
973 return ldb_module_oom(module);
975 *el->values = data_blob_string_const(vstring);
978 if (new_val) {
979 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
980 if (ret != LDB_SUCCESS) {
981 return ret;
983 el->num_values = 1;
984 el->values = talloc_array(msg, struct ldb_val, el->num_values);
985 if (!el->values) {
986 return ldb_module_oom(module);
988 vstring = talloc_asprintf(el->values, "%ld", (long)*new_val);
989 if (!vstring) {
990 return ldb_module_oom(module);
992 *el->values = data_blob_string_const(vstring);
995 return LDB_SUCCESS;
998 int dsdb_msg_constrainted_update_uint32(struct ldb_module *module,
999 struct ldb_message *msg,
1000 const char *attr,
1001 const uint32_t *old_val,
1002 const uint32_t *new_val)
1004 return dsdb_msg_constrainted_update_int32(module, msg, attr,
1005 (const int32_t *)old_val,
1006 (const int32_t *)new_val);
1009 int dsdb_msg_constrainted_update_int64(struct ldb_module *module,
1010 struct ldb_message *msg,
1011 const char *attr,
1012 const int64_t *old_val,
1013 const int64_t *new_val)
1015 struct ldb_message_element *el;
1016 struct ldb_val *v1, *v2;
1017 int ret;
1018 char *vstring;
1020 if (old_val) {
1021 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1022 if (ret != LDB_SUCCESS) {
1023 return ret;
1025 el->num_values = 1;
1026 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1027 if (!el->values) {
1028 return ldb_module_oom(module);
1030 vstring = talloc_asprintf(el->values, "%lld", (long long)*old_val);
1031 if (!vstring) {
1032 return ldb_module_oom(module);
1034 *el->values = data_blob_string_const(vstring);
1037 if (new_val) {
1038 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1039 if (ret != LDB_SUCCESS) {
1040 return ret;
1042 el->num_values = 1;
1043 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1044 if (!el->values) {
1045 return ldb_module_oom(module);
1047 vstring = talloc_asprintf(el->values, "%lld", (long long)*new_val);
1048 if (!vstring) {
1049 return ldb_module_oom(module);
1051 *el->values = data_blob_string_const(vstring);
1054 return LDB_SUCCESS;
1057 int dsdb_msg_constrainted_update_uint64(struct ldb_module *module,
1058 struct ldb_message *msg,
1059 const char *attr,
1060 const uint64_t *old_val,
1061 const uint64_t *new_val)
1063 return dsdb_msg_constrainted_update_int64(module, msg, attr,
1064 (const int64_t *)old_val,
1065 (const int64_t *)new_val);
1069 update an int32 attribute safely via a constrained delete/add
1071 int dsdb_module_constrainted_update_int32(struct ldb_module *module,
1072 struct ldb_dn *dn,
1073 const char *attr,
1074 const int32_t *old_val,
1075 const int32_t *new_val)
1077 struct ldb_message *msg;
1078 int ret;
1080 msg = ldb_msg_new(module);
1081 msg->dn = dn;
1083 ret = dsdb_msg_constrainted_update_int32(module,
1084 msg, attr,
1085 old_val,
1086 new_val);
1087 if (ret != LDB_SUCCESS) {
1088 talloc_free(msg);
1089 return ret;
1092 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1093 talloc_free(msg);
1094 return ret;
1097 int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
1098 struct ldb_dn *dn,
1099 const char *attr,
1100 const uint32_t *old_val,
1101 const uint32_t *new_val)
1103 return dsdb_module_constrainted_update_int32(module, dn, attr,
1104 (const int32_t *)old_val,
1105 (const int32_t *)new_val);
1109 update an int64 attribute safely via a constrained delete/add
1111 int dsdb_module_constrainted_update_int64(struct ldb_module *module,
1112 struct ldb_dn *dn,
1113 const char *attr,
1114 const int64_t *old_val,
1115 const int64_t *new_val)
1117 struct ldb_message *msg;
1118 int ret;
1120 msg = ldb_msg_new(module);
1121 msg->dn = dn;
1123 ret = dsdb_msg_constrainted_update_int64(module,
1124 msg, attr,
1125 old_val,
1126 new_val);
1127 if (ret != LDB_SUCCESS) {
1128 talloc_free(msg);
1129 return ret;
1132 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1133 talloc_free(msg);
1134 return ret;
1137 int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
1138 struct ldb_dn *dn,
1139 const char *attr,
1140 const uint64_t *old_val,
1141 const uint64_t *new_val)
1143 return dsdb_module_constrainted_update_int64(module, dn, attr,
1144 (const int64_t *)old_val,
1145 (const int64_t *)new_val);