summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/dsdb/samdb/ldb_modules/subtree_rename.c124
1 files changed, 122 insertions, 2 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/subtree_rename.c b/source4/dsdb/samdb/ldb_modules/subtree_rename.c
index 49cf9a7e8b..590f6f7680 100644
--- a/source4/dsdb/samdb/ldb_modules/subtree_rename.c
+++ b/source4/dsdb/samdb/ldb_modules/subtree_rename.c
@@ -31,6 +31,8 @@
#include "includes.h"
#include <ldb.h>
#include <ldb_module.h>
+#include "libds/common/flags.h"
+#include "dsdb/samdb/samdb.h"
struct subren_msg_store {
struct subren_msg_store *next;
@@ -139,6 +141,110 @@ static int subtree_rename_next_request(struct subtree_rename_context *ac)
return ldb_next_request(ac->module, req);
}
+static int check_system_flags(struct ldb_message *msg,
+ struct subtree_rename_context *ac,
+ struct ldb_dn *olddn, struct ldb_dn *newdn)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+ struct ldb_dn *dn1, *dn2;
+ int32_t systemFlags;
+ bool move_op = false;
+ bool rename_op = false;
+
+ if (ldb_dn_compare(olddn, newdn) == 0) {
+ return LDB_SUCCESS;
+ }
+
+ dn1 = ldb_dn_get_parent(ac, olddn);
+ dn2 = ldb_dn_get_parent(ac, newdn);
+
+ if (ldb_dn_compare(dn1, dn2) == 0) {
+ rename_op = true;
+ } else {
+ move_op = true;
+ }
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+
+ systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
+
+ /* the config system flags don't apply for the schema partition */
+ if ((ldb_dn_compare_base(ldb_get_config_basedn(ldb), olddn) == 0) &&
+ (ldb_dn_compare_base(ldb_get_schema_basedn(ldb), olddn) != 0)) {
+ if (move_op &&
+ (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
+ /* Here we have to do more: control the
+ * "ALLOW_LIMITED_MOVE" flag. This means that the
+ * grand-grand-parents of two objects have to be equal
+ * in order to perform the move (this is used for
+ * moving "server" objects in the "sites" container). */
+ bool limited_move =
+ systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
+
+ if (limited_move) {
+ dn1 = ldb_dn_copy(ac, olddn);
+ dn2 = ldb_dn_copy(ac, newdn);
+
+ limited_move &= ldb_dn_remove_child_components(dn1, 3);
+ limited_move &= ldb_dn_remove_child_components(dn2, 3);
+ limited_move &= ldb_dn_compare(dn1, dn2) == 0;
+
+ talloc_free(dn1);
+ talloc_free(dn2);
+ }
+
+ if (!limited_move) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot move %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+ if (rename_op &&
+ (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot rename %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+ if (ldb_dn_compare_base(ldb_get_schema_basedn(ldb), olddn) == 0) {
+ if (move_op) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot move %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ if (rename_op &&
+ (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot rename %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+ if (ldb_dn_compare_base(ldb_get_default_basedn(ldb),
+ ac->current->olddn) == 0) {
+ if (move_op &&
+ (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot move %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ if (rename_op &&
+ (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
+ ldb_asprintf_errstring(ldb,
+ "subtree_rename: Cannot rename %s, it isn't permitted!",
+ ldb_dn_get_linearized(olddn));
+ return LDB_ERR_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ return LDB_SUCCESS;
+}
+
static int subtree_rename_search_callback(struct ldb_request *req,
struct ldb_reply *ares)
{
@@ -159,10 +265,18 @@ static int subtree_rename_search_callback(struct ldb_request *req,
switch (ares->type) {
case LDB_REPLY_ENTRY:
-
if (ldb_dn_compare(ares->message->dn, ac->list->olddn) == 0) {
/* this was already stored by the
* subtree_rename_search() */
+
+ ret = check_system_flags(ares->message, ac,
+ ac->list->olddn,
+ ac->list->newdn);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL,
+ ret);
+ }
+
talloc_free(ares);
return LDB_SUCCESS;
}
@@ -190,6 +304,12 @@ static int subtree_rename_search_callback(struct ldb_request *req,
LDB_ERR_OPERATIONS_ERROR);
}
+ ret = check_system_flags(ares->message, ac,
+ store->olddn, store->newdn);
+ if (ret != LDB_SUCCESS) {
+ return ldb_module_done(ac->req, NULL, NULL, ret);
+ }
+
break;
case LDB_REPLY_REFERRAL:
@@ -218,7 +338,7 @@ static int subtree_rename_search_callback(struct ldb_request *req,
static int subtree_rename(struct ldb_module *module, struct ldb_request *req)
{
struct ldb_context *ldb;
- static const char *attrs[2] = { "distinguishedName", NULL };
+ static const char * const attrs[] = { "systemFlags", NULL };
struct ldb_request *search_req;
struct subtree_rename_context *ac;
int ret;