s4:dsdb Rework modules create new partitions at runtime
authorAndrew Bartlett <abartlet@samba.org>
Fri, 2 Oct 2009 00:28:29 +0000 (10:28 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 21 Oct 2009 11:43:50 +0000 (22:43 +1100)
This is done by passing an extended operation to the partitions module
to extend the @PARTITION record and to extend the in-memory list of
partitions.

This also splits things up into module parts that belong above and below
repl_meta_data

Also slit the partitions module into two files due to the complexity
of the code

Andrew Barltett

source4/dsdb/samdb/ldb_modules/config.mk
source4/dsdb/samdb/ldb_modules/instancetype.c
source4/dsdb/samdb/ldb_modules/new_partition.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/partition.c
source4/dsdb/samdb/ldb_modules/partition.h [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/partition_init.c [new file with mode: 0644]
source4/dsdb/samdb/samdb.h
source4/scripting/python/samba/provision.py
source4/setup/provision_partitions.ldif
source4/setup/schema_samba4.ldif

index ea4e7228226e431f82b349a3b080c67a8a79ed6a..40e37a47fc86d5ed3482fd572bf7ebdf756dc22b 100644 (file)
@@ -235,7 +235,20 @@ INIT_FUNCTION = LDB_MODULE(partition)
 # End MODULE ldb_partition
 ################################################
 
-ldb_partition_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/partition.o
+ldb_partition_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/partition.o \
+                         $(dsdbsrcdir)/samdb/ldb_modules/partition_init.o
+$(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/partition_proto.h,$(ldb_partition_OBJ_FILES:.o=.c)))
+
+################################################
+# Start MODULE ldb_partition
+[MODULE::ldb_new_partition]
+SUBSYSTEM = LIBLDB
+PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS SAMDB DSDB_MODULE_HELPERS
+INIT_FUNCTION = LDB_MODULE(new_partition)
+# End MODULE ldb_partition
+################################################
+
+ldb_new_partition_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/new_partition.o 
 
 ################################################
 # Start MODULE ldb_update_kt
index 201ed044125c8a6400e858612b79d52a3d0ffe20..b17f40e82a97b0c0c020634b0b69c293b227f899 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include "includes.h"
+#include "ldb.h"
 #include "ldb_module.h"
 #include "librpc/gen_ndr/ndr_misc.h"
 #include "dsdb/samdb/samdb.h"
 struct it_context {
        struct ldb_module *module;
        struct ldb_request *req;
+       struct ldb_request *add_req;
 };
 
-static int it_callback(struct ldb_request *req, struct ldb_reply *ares)
+static int it_add_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct ldb_context *ldb;
        struct it_context *ac;
@@ -53,6 +55,7 @@ static int it_callback(struct ldb_request *req, struct ldb_reply *ares)
                return ldb_module_done(ac->req, NULL, NULL,
                                        LDB_ERR_OPERATIONS_ERROR);
        }
+
        if (ares->error != LDB_SUCCESS) {
                return ldb_module_done(ac->req, ares->controls,
                                        ares->response, ares->error);
@@ -64,8 +67,10 @@ static int it_callback(struct ldb_request *req, struct ldb_reply *ares)
                                        LDB_ERR_OPERATIONS_ERROR);
        }
 
+       /* Add the boilerplate entries */
+
        return ldb_module_done(ac->req, ares->controls,
-                                       ares->response, ares->error);
+                              ares->response, ares->error);
 }
 
 /* add_record: add instancetype attribute */
@@ -89,14 +94,32 @@ static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
 
        if (ldb_msg_find_element(req->op.add.message, "instanceType")) {
                unsigned int instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
+               if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
+                       return ldb_next_request(module, req);           
+               }
 
-               if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
-                       /* Do something in future */
+               /* Forward the 'add' to the modules below, but if it
+                * succeeds, then we might need to add the boilerplate
+                * entries (lost+found, deleted objects) */
+               ac = talloc(req, struct it_context);
+               if (ac == NULL) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               ac->module = module;
+               ac->req = req;
+               
+               ret = ldb_build_add_req(&ac->add_req, ldb_module_get_ctx(ac->module), ac,
+                                       ac->req->op.add.message,
+                                       ac->req->controls,
+                                       ac, it_add_callback,
+                                       ac->req);
+               
+               if (ret != LDB_SUCCESS) {
+                       return ret;
                }
                
-               /* TODO: we need to validate and possibly create a new
-                  partition */
-               return ldb_next_request(module, req);           
+               /* Do the original add */
+               return ldb_next_request(ac->module, ac->add_req);
        }
 
        /* we have to copy the message as the caller might have it as a const */
diff --git a/source4/dsdb/samdb/ldb_modules/new_partition.c b/source4/dsdb/samdb/ldb_modules/new_partition.c
new file mode 100644 (file)
index 0000000..c497d97
--- /dev/null
@@ -0,0 +1,189 @@
+/* 
+   ldb database library
+
+   Copyright (C) Simo Sorce  2004-2008
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+   Copyright (C) Andrew Tridgell 2005
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb instancetype module
+ *
+ *  Description: add an instanceType onto every new record
+ *
+ *  Author: Andrew Bartlett
+ */
+
+#include "includes.h"
+#include "ldb.h"
+#include "ldb_module.h"
+#include "librpc/gen_ndr/ndr_misc.h"
+#include "dsdb/samdb/samdb.h"
+#include "../libds/common/flags.h"
+
+struct np_context {
+       struct ldb_module *module;
+       struct ldb_request *req;
+       struct ldb_request *search_req;
+       struct ldb_request *part_add;
+};
+
+static int np_part_mod_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct ldb_context *ldb;
+       struct np_context *ac;
+
+       ac = talloc_get_type(req->context, struct np_context);
+       ldb = ldb_module_get_ctx(ac->module);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       /* We just want to update the @PARTITIONS record if the value does not exist */
+       if (ares->error != LDB_SUCCESS && ares->error != LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ldb, "Invalid reply type!");
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       ldb_reset_err_string(ldb);
+
+       /* Do the original add */
+       return ldb_next_request(ac->module, ac->req);
+}
+
+static int np_part_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct ldb_context *ldb;
+       struct np_context *ac;
+       struct dsdb_create_partition_exop *ex_op;
+       int ret;
+
+       ac = talloc_get_type(req->context, struct np_context);
+       ldb = ldb_module_get_ctx(ac->module);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       /* If this already exists, we really don't want to create a
+        * partition - it would allow a duplicate entry to be
+        * created */
+       if (ares->error != LDB_ERR_NO_SUCH_OBJECT) {
+               if (ares->error == LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, ares->controls,
+                                              ares->response, LDB_ERR_ENTRY_ALREADY_EXISTS);
+               } else {
+                       return ldb_module_done(ac->req, ares->controls,
+                                              ares->response, ares->error);
+               }
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(ldb, "Invalid reply type - we must not get a result here!");
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       ldb_reset_err_string(ldb);
+
+       /* Now that we know it does not exist, we can try and create the partition */
+       ex_op = talloc(ac, struct dsdb_create_partition_exop);
+       if (ex_op == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       ex_op->new_dn = ac->req->op.add.message->dn;
+       
+       ret = ldb_build_extended_req(&ac->part_add, 
+                                    ldb, ac, DSDB_EXTENDED_CREATE_PARTITION_OID, ex_op, 
+                                    NULL, ac, np_part_mod_callback, req);
+       
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       
+       return ldb_next_request(ac->module, ac->part_add);
+}
+
+/* add_record: add instancetype attribute */
+static int new_partition_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_context *ldb;
+       struct ldb_request *down_req;
+       struct np_context *ac;
+       int ret;
+
+       ldb = ldb_module_get_ctx(module);
+
+       ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add_record\n");
+
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       if (!ldb_msg_find_element(req->op.add.message, "instanceType")) {
+               return ldb_next_request(module, req);           
+       } else {
+               const char *no_attrs[] = { NULL };
+               unsigned int instanceType = ldb_msg_find_attr_as_uint(req->op.add.message, "instanceType", 0);
+               if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
+                       return ldb_next_request(module, req);           
+               }
+
+               /* Create an @PARTITIONS record for this partition -
+                * by asking the partitions module to do so via an
+                * extended operation, after first checking if the
+                * record already exists */
+               ac = talloc(req, struct np_context);
+               if (ac == NULL) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               ac->module = module;
+               ac->req = req;
+               
+               ret = ldb_build_search_req(&ac->search_req, ldb, ac, req->op.add.message->dn, 
+                                          LDB_SCOPE_BASE, NULL, no_attrs, req->controls, ac, 
+                                          np_part_search_callback,
+                                          req);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+               
+               return ldb_next_request(module, ac->search_req);
+       }
+
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
+
+_PUBLIC_ const struct ldb_module_ops ldb_new_partition_module_ops = {
+       .name          = "new_partition",
+       .add           = new_partition_add,
+};
index c5bbdf8dce35b9c3fff78735026797b6ed5bd887..f6031fb944e58962a1318256d9f84f182aa3e61a 100644 (file)
  *  Author: Stefan Metzmacher
  */
 
-#include "includes.h"
-#include "lib/ldb/include/ldb.h"
-#include "lib/ldb/include/ldb_errors.h"
-#include "lib/ldb/include/ldb_module.h"
-#include "lib/ldb/include/ldb_private.h"
-#include "dsdb/samdb/samdb.h"
-
-struct dsdb_partition {
-       struct ldb_module *module;
-       struct dsdb_control_current_partition *ctrl;
-};
-
-struct partition_private_data {
-       struct dsdb_partition **partitions;
-       struct ldb_dn **replicate;
-};
+#include "dsdb/samdb/ldb_modules/partition.h"
 
 struct part_request {
        struct ldb_module *module;
@@ -77,19 +62,6 @@ static struct partition_context *partition_init_ctx(struct ldb_module *module, s
        return ac;
 }
 
-#define PARTITION_FIND_OP_NOERROR(module, op) do { \
-        while (module && module->ops->op == NULL) module = module->next; \
-} while (0)
-
-#define PARTITION_FIND_OP(module, op) do { \
-       PARTITION_FIND_OP_NOERROR(module, op); \
-        if (module == NULL) { \
-                ldb_asprintf_errstring(ldb_module_get_ctx(module), \
-                       "Unable to find backend operation for " #op ); \
-                return LDB_ERR_OPERATIONS_ERROR; \
-        } \
-} while (0)
-
 /*
  *    helper functions to call the next module in chain
  *    */
@@ -1108,7 +1080,7 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
        struct partition_context *ac;
 
        data = talloc_get_type(module->private_data, struct partition_private_data);
-       if (!data || !data->partitions) {
+       if (!data) {
                return ldb_next_request(module, req);
        }
 
@@ -1116,6 +1088,10 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
                return partition_sequence_number(module, req);
        }
 
+       if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_PARTITION_OID) == 0) {
+               return partition_create(module, req);
+       }
+
        /* forward schemaUpdateNow operation to schema_fsmo module*/
        if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) == 0) {
                return partition_extended_schema_update_now( module, req );
@@ -1134,279 +1110,6 @@ static int partition_extended(struct ldb_module *module, struct ldb_request *req
        return partition_send_all(module, ac, req);
 }
 
-static int partition_sort_compare(const void *v1, const void *v2)
-{
-       const struct dsdb_partition *p1;
-       const struct dsdb_partition *p2;
-
-       p1 = *((struct dsdb_partition * const*)v1);
-       p2 = *((struct dsdb_partition * const*)v2);
-
-       return ldb_dn_compare(p1->ctrl->dn, p2->ctrl->dn);
-}
-
-static int partition_init(struct ldb_module *module)
-{
-       int ret, i;
-       TALLOC_CTX *mem_ctx = talloc_new(module);
-       const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
-       struct ldb_result *res;
-       struct ldb_message *msg;
-       struct ldb_message_element *partition_attributes;
-       struct ldb_message_element *replicate_attributes;
-       struct ldb_message_element *modules_attributes;
-
-       struct partition_private_data *data;
-
-       if (!mem_ctx) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       data = talloc(mem_ctx, struct partition_private_data);
-       if (data == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ret = ldb_search(ldb_module_get_ctx(module), mem_ctx, &res,
-                        ldb_dn_new(mem_ctx, ldb_module_get_ctx(module), "@PARTITION"),
-                        LDB_SCOPE_BASE, attrs, NULL);
-       if (ret != LDB_SUCCESS) {
-               talloc_free(mem_ctx);
-               return ret;
-       }
-       if (res->count == 0) {
-               talloc_free(mem_ctx);
-               return ldb_next_init(module);
-       }
-
-       if (res->count > 1) {
-               talloc_free(mem_ctx);
-               return LDB_ERR_CONSTRAINT_VIOLATION;
-       }
-
-       msg = res->msgs[0];
-
-       partition_attributes = ldb_msg_find_element(msg, "partition");
-       if (!partition_attributes) {
-               ldb_set_errstring(ldb_module_get_ctx(module), "partition_init: no partitions specified");
-               talloc_free(mem_ctx);
-               return LDB_ERR_CONSTRAINT_VIOLATION;
-       }
-       data->partitions = talloc_array(data, struct dsdb_partition *, partition_attributes->num_values + 1);
-       if (!data->partitions) {
-               talloc_free(mem_ctx);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       for (i=0; i < partition_attributes->num_values; i++) {
-               char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
-               char *p = strchr(base, ':');
-               const char *backend;
-
-               if (!p) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                               "partition_init: "
-                                               "invalid form for partition record (missing ':'): %s", base);
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_CONSTRAINT_VIOLATION;
-               }
-               p[0] = '\0';
-               p++;
-               if (!p[0]) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                               "partition_init: "
-                                               "invalid form for partition record (missing backend database): %s", base);
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_CONSTRAINT_VIOLATION;
-               }
-               data->partitions[i] = talloc(data->partitions, struct dsdb_partition);
-               if (!data->partitions[i]) {
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               data->partitions[i]->ctrl = talloc(data->partitions[i], struct dsdb_control_current_partition);
-               if (!data->partitions[i]->ctrl) {
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               data->partitions[i]->ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
-               data->partitions[i]->ctrl->dn = ldb_dn_new(data->partitions[i], ldb_module_get_ctx(module), base);
-               if (!data->partitions[i]->ctrl->dn) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                               "partition_init: invalid DN in partition record: %s", base);
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_CONSTRAINT_VIOLATION;
-               }
-
-               backend = samdb_relative_path(ldb_module_get_ctx(module), 
-                                                                  data->partitions[i], 
-                                                                  p);
-               if (!backend) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                               "partition_init: unable to determine an relative path for partition: %s", base);
-                       talloc_free(mem_ctx);                   
-               }
-               ret = ldb_connect_backend(ldb_module_get_ctx(module), backend, NULL, &data->partitions[i]->module);
-               if (ret != LDB_SUCCESS) {
-                       talloc_free(mem_ctx);
-                       return ret;
-               }
-       }
-       data->partitions[i] = NULL;
-
-       /* sort these into order, most to least specific */
-       qsort(data->partitions, partition_attributes->num_values,
-             sizeof(*data->partitions), partition_sort_compare);
-
-       for (i=0; data->partitions[i]; i++) {
-               struct ldb_request *req;
-               req = talloc_zero(mem_ctx, struct ldb_request);
-               if (req == NULL) {
-                       ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Out of memory!\n");
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               
-               req->operation = LDB_REQ_REGISTER_PARTITION;
-               req->op.reg_partition.dn = data->partitions[i]->ctrl->dn;
-               req->callback = ldb_op_default_callback;
-
-               ldb_set_timeout(ldb_module_get_ctx(module), req, 0);
-
-               req->handle = ldb_handle_new(req, ldb_module_get_ctx(module));
-               if (req->handle == NULL) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               
-               ret = ldb_request(ldb_module_get_ctx(module), req);
-               if (ret == LDB_SUCCESS) {
-                       ret = ldb_wait(req->handle, LDB_WAIT_ALL);
-               }
-               if (ret != LDB_SUCCESS) {
-                       ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_OTHER;
-               }
-               talloc_free(req);
-       }
-
-       replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
-       if (!replicate_attributes) {
-               data->replicate = NULL;
-       } else {
-               data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
-               if (!data->replicate) {
-                       talloc_free(mem_ctx);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-
-               for (i=0; i < replicate_attributes->num_values; i++) {
-                       data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb_module_get_ctx(module), &replicate_attributes->values[i]);
-                       if (!ldb_dn_validate(data->replicate[i])) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                       "partition_init: "
-                                                       "invalid DN in partition replicate record: %s", 
-                                                       replicate_attributes->values[i].data);
-                               talloc_free(mem_ctx);
-                               return LDB_ERR_CONSTRAINT_VIOLATION;
-                       }
-               }
-               data->replicate[i] = NULL;
-       }
-
-       /* Make the private data available to any searches the modules may trigger in initialisation */
-       module->private_data = data;
-       talloc_steal(module, data);
-       
-       modules_attributes = ldb_msg_find_element(msg, "modules");
-       if (modules_attributes) {
-               for (i=0; i < modules_attributes->num_values; i++) {
-                       struct ldb_dn *base_dn;
-                       int partition_idx;
-                       struct dsdb_partition *partition = NULL;
-                       const char **modules = NULL;
-
-                       char *base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
-                       char *p = strchr(base, ':');
-                       if (!p) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                       "partition_init: "
-                                                       "invalid form for partition module record (missing ':'): %s", base);
-                               talloc_free(mem_ctx);
-                               return LDB_ERR_CONSTRAINT_VIOLATION;
-                       }
-                       p[0] = '\0';
-                       p++;
-                       if (!p[0]) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                       "partition_init: "
-                                                       "invalid form for partition module record (missing backend database): %s", base);
-                               talloc_free(mem_ctx);
-                               return LDB_ERR_CONSTRAINT_VIOLATION;
-                       }
-
-                       modules = ldb_modules_list_from_string(ldb_module_get_ctx(module), mem_ctx,
-                                                              p);
-                       
-                       base_dn = ldb_dn_new(mem_ctx, ldb_module_get_ctx(module), base);
-                       if (!ldb_dn_validate(base_dn)) {
-                               talloc_free(mem_ctx);
-                               return LDB_ERR_OPERATIONS_ERROR;
-                       }
-                       
-                       for (partition_idx = 0; data->partitions[partition_idx]; partition_idx++) {
-                               if (ldb_dn_compare(data->partitions[partition_idx]->ctrl->dn, base_dn) == 0) {
-                                       partition = data->partitions[partition_idx];
-                                       break;
-                               }
-                       }
-                       
-                       if (!partition) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                       "partition_init: "
-                                                       "invalid form for partition module record (no such partition): %s", base);
-                               talloc_free(mem_ctx);
-                               return LDB_ERR_CONSTRAINT_VIOLATION;
-                       }
-                       
-                       ret = ldb_load_modules_list(ldb_module_get_ctx(module), modules, partition->module, &partition->module);
-                       if (ret != LDB_SUCCESS) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                      "partition_init: "
-                                                      "loading backend for %s failed: %s", 
-                                                      base, ldb_errstring(ldb_module_get_ctx(module)));
-                               talloc_free(mem_ctx);
-                               return ret;
-                       }
-                       ret = ldb_init_module_chain(ldb_module_get_ctx(module), partition->module);
-                       if (ret != LDB_SUCCESS) {
-                               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
-                                                      "partition_init: "
-                                                      "initialising backend for %s failed: %s", 
-                                                      base, ldb_errstring(ldb_module_get_ctx(module)));
-                               talloc_free(mem_ctx);
-                               return ret;
-                       }
-               }
-       }
-
-       ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
-       if (ret != LDB_SUCCESS) {
-               ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
-                       "partition: Unable to register control with rootdse!\n");
-               return ret;
-       }
-
-       ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
-       if (ret != LDB_SUCCESS) {
-               ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
-                       "partition: Unable to register control with rootdse!\n");
-               return ret;
-       }
-
-       talloc_free(mem_ctx);
-       return ldb_next_init(module);
-}
-
 _PUBLIC_ const struct ldb_module_ops ldb_partition_module_ops = {
        .name              = "partition",
        .init_context      = partition_init,
diff --git a/source4/dsdb/samdb/ldb_modules/partition.h b/source4/dsdb/samdb/ldb_modules/partition.h
new file mode 100644 (file)
index 0000000..62c2e2e
--- /dev/null
@@ -0,0 +1,59 @@
+/* 
+   Partitions ldb module
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "lib/ldb/include/ldb.h"
+#include "lib/ldb/include/ldb_errors.h"
+#include "lib/ldb/include/ldb_module.h"
+#include "lib/ldb/include/ldb_private.h"
+#include "dsdb/samdb/samdb.h"
+#include "dsdb/samdb/ldb_modules/util.h"
+
+struct dsdb_partition {
+       struct ldb_module *module;
+       struct dsdb_control_current_partition *ctrl;
+};
+
+struct partition_module {
+       const char **modules;
+       struct ldb_dn *dn;
+};
+
+struct partition_private_data {
+       struct dsdb_partition **partitions;
+       struct ldb_dn **replicate;
+       
+       struct partition_module **modules;
+       const char *ldapBackend;
+};
+
+#define PARTITION_FIND_OP_NOERROR(module, op) do { \
+        while (module && module->ops->op == NULL) module = module->next; \
+} while (0)
+
+#define PARTITION_FIND_OP(module, op) do { \
+       PARTITION_FIND_OP_NOERROR(module, op); \
+        if (module == NULL) { \
+                ldb_asprintf_errstring(ldb_module_get_ctx(module), \
+                       "Unable to find backend operation for " #op ); \
+                return LDB_ERR_OPERATIONS_ERROR; \
+        } \
+} while (0)
+
+#include "dsdb/samdb/ldb_modules/partition_proto.h"
diff --git a/source4/dsdb/samdb/ldb_modules/partition_init.c b/source4/dsdb/samdb/ldb_modules/partition_init.c
new file mode 100644 (file)
index 0000000..0502ff5
--- /dev/null
@@ -0,0 +1,534 @@
+/* 
+   Partitions ldb module
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+   Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*
+ *  Name: ldb
+ *
+ *  Component: ldb partitions module
+ *
+ *  Description: Implement LDAP partitions
+ *
+ *  Author: Andrew Bartlett
+ *  Author: Stefan Metzmacher
+ */
+
+#include "dsdb/samdb/ldb_modules/partition.h"
+
+static int partition_sort_compare(const void *v1, const void *v2)
+{
+       const struct dsdb_partition *p1;
+       const struct dsdb_partition *p2;
+
+       p1 = *((struct dsdb_partition * const*)v1);
+       p2 = *((struct dsdb_partition * const*)v2);
+
+       return ldb_dn_compare(p1->ctrl->dn, p2->ctrl->dn);
+}
+
+/* Load the list of DNs that we must replicate to all partitions */
+static int partition_load_replicate_dns(struct ldb_context *ldb, struct partition_private_data *data, struct ldb_message *msg) 
+{
+       struct ldb_message_element *replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
+
+       talloc_free(data->replicate);
+       if (!replicate_attributes) {
+               data->replicate = NULL;
+       } else {
+               int i;
+               data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
+               if (!data->replicate) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               for (i=0; i < replicate_attributes->num_values; i++) {
+                       data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb, &replicate_attributes->values[i]);
+                       if (!ldb_dn_validate(data->replicate[i])) {
+                               ldb_asprintf_errstring(ldb,
+                                                       "partition_init: "
+                                                       "invalid DN in partition replicate record: %s", 
+                                                       replicate_attributes->values[i].data);
+                               return LDB_ERR_CONSTRAINT_VIOLATION;
+                       }
+               }
+               data->replicate[i] = NULL;
+       }
+       return LDB_SUCCESS;
+}
+
+/* Load the list of modules for the partitions */
+static int partition_load_modules(struct ldb_context *ldb, 
+                                 struct partition_private_data *data, struct ldb_message *msg) 
+{
+       int i;
+       struct ldb_message_element *modules_attributes = ldb_msg_find_element(msg, "modules");
+       talloc_free(data->modules);
+       if (!modules_attributes) {
+               return LDB_SUCCESS;
+       }
+       
+       data->modules = talloc_array(data, struct partition_module *, modules_attributes->num_values + 1);
+       if (!data->modules) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       for (i=0; i < modules_attributes->num_values; i++) {
+               char *base;
+               char *p;
+
+               data->modules[i] = talloc(data->modules, struct partition_module);
+               if (!data->modules[i]) {
+                       ldb_oom(ldb);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
+               p = strchr(base, ':');
+               if (!p) {
+                       ldb_asprintf_errstring(ldb, 
+                                              "partition_load_modules: "
+                                              "invalid form for partition module record (missing ':'): %s", base);
+                       return LDB_ERR_CONSTRAINT_VIOLATION;
+               }
+               p[0] = '\0';
+               p++;
+               data->modules[i]->modules = ldb_modules_list_from_string(ldb, data->modules[i],
+                                                                        p);
+               
+               if (strcmp(base, "*") == 0) {
+                       data->modules[i]->dn = NULL;
+               } else {
+                       data->modules[i]->dn = ldb_dn_new(data->modules[i], ldb, base);
+                       if (!data->modules[i]->dn || !ldb_dn_validate(data->modules[i]->dn)) {
+                               return LDB_ERR_OPERATIONS_ERROR;
+                       }
+               }
+       }
+       return LDB_SUCCESS;
+}
+
+static int partition_reload_metadata(struct ldb_module *module, struct partition_private_data *data, TALLOC_CTX *mem_ctx, struct ldb_message **_msg) 
+{
+       int ret;
+       struct ldb_message *msg;
+       struct ldb_result *res;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
+       /* perform search for @PARTITION, looking for module, replicateEntries and ldapBackend */
+       ret = dsdb_module_search_dn(module, mem_ctx, &res, 
+                                   ldb_dn_new(mem_ctx, ldb, DSDB_PARTITION_DN),
+                                   attrs);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       msg = res->msgs[0];
+
+       ret = partition_load_replicate_dns(ldb, data, msg);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = partition_load_modules(ldb, data, msg);                   
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       data->ldapBackend = talloc_steal(data, ldb_msg_find_attr_as_string(msg, "ldapBackend", NULL));
+       if (_msg) {
+               *_msg = msg;
+       } else {
+               talloc_free(msg);
+       }
+       return LDB_SUCCESS;
+}
+
+static const char **find_modules_for_dn(struct partition_private_data *data, struct ldb_dn *dn) 
+{
+       int i;
+       struct partition_module *default_mod = NULL;
+       for (i=0; data->modules && data->modules[i]; i++) {
+               if (!data->modules[i]->dn) {
+                       default_mod = data->modules[i];
+               } else if (ldb_dn_compare(dn, data->modules[i]->dn) == 0) {
+                       return data->modules[i]->modules;
+               }
+       }
+       if (default_mod) {
+               return default_mod->modules;
+       } else {
+               return NULL;
+       }
+}
+
+static int new_partition_from_dn(struct ldb_context *ldb, struct partition_private_data *data, 
+                         TALLOC_CTX *mem_ctx, 
+                         struct ldb_dn *dn,
+                         struct dsdb_partition **partition) {
+       const char *backend_name;
+       const char *full_backend;
+       struct dsdb_control_current_partition *ctrl;
+       struct ldb_module *module;
+       const char **modules;
+       int ret;
+
+       (*partition) = talloc(mem_ctx, struct dsdb_partition);
+       if (!*partition) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       (*partition)->ctrl = ctrl = talloc((*partition), struct dsdb_control_current_partition);
+       if (!ctrl) {
+               talloc_free(*partition);
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* See if an LDAP backend has been specified */
+       if (data->ldapBackend) {
+               backend_name = data->ldapBackend;
+       } else {
+               /* If we don't have a : in the record, then the partition name is the name of the LDB */
+               backend_name = talloc_asprintf(data, "%s.ldb", ldb_dn_get_casefold(dn)); 
+       }
+
+       ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
+       ctrl->dn = talloc_steal(ctrl, dn);
+       
+       full_backend = samdb_relative_path(ldb, 
+                                          *partition, 
+                                          backend_name);
+       if (!full_backend) {
+               ldb_asprintf_errstring(ldb_module_get_ctx(module), 
+                                      "partition_init: unable to determine an relative path for partition: %s", backend_name);
+               talloc_free(*partition);
+               return LDB_ERR_OPERATIONS_ERROR;                
+       }
+
+       ret = ldb_connect_backend(ldb, full_backend, NULL, &module);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       modules = find_modules_for_dn(data, dn);
+
+       ret = ldb_load_modules_list(ldb, modules, module, &(*partition)->module);
+       if (ret != LDB_SUCCESS) {
+               ldb_asprintf_errstring(ldb, 
+                                      "partition_init: "
+                                      "loading backend for %s failed: %s", 
+                                      ldb_dn_get_linearized(dn), ldb_errstring(ldb));
+               talloc_free(*partition);
+               return ret;
+       }
+       ret = ldb_init_module_chain(ldb, (*partition)->module);
+       if (ret != LDB_SUCCESS) {
+               ldb_asprintf_errstring(ldb,
+                                      "partition_init: "
+                                      "initialising backend for %s failed: %s", 
+                                      ldb_dn_get_linearized(dn), ldb_errstring(ldb));
+               talloc_free(*partition);
+               return ret;
+       }
+
+       talloc_steal((*partition), (*partition)->module);
+
+       return ret;
+}
+
+static int partition_register(struct ldb_context *ldb, struct dsdb_control_current_partition *ctrl, TALLOC_CTX *mem_ctx) 
+{
+       struct ldb_request *req;
+       int ret;
+
+       req = talloc_zero(mem_ctx, struct ldb_request);
+       if (req == NULL) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+               
+       req->operation = LDB_REQ_REGISTER_PARTITION;
+       req->op.reg_partition.dn = ctrl->dn;
+       req->callback = ldb_op_default_callback;
+
+       ldb_set_timeout(ldb, req, 0);
+       
+       req->handle = ldb_handle_new(req, ldb);
+       if (req->handle == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       ret = ldb_request(ldb, req);
+       if (ret == LDB_SUCCESS) {
+               ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+       }
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
+               talloc_free(mem_ctx);
+               return LDB_ERR_OTHER;
+       }
+       talloc_free(req);
+
+       return LDB_SUCCESS;
+}
+
+int partition_create(struct ldb_module *module, struct ldb_request *req)
+{
+       int i, ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct ldb_request *mod_req;
+       struct ldb_message *mod_msg;
+       struct partition_private_data *data;
+       struct dsdb_partition *partition;
+
+       /* Check if this is already a partition */
+
+       struct dsdb_create_partition_exop *ex_op = talloc_get_type(req->op.extended.data, struct dsdb_create_partition_exop);
+       struct ldb_dn *dn = ex_op->new_dn;
+
+       data = talloc_get_type(module->private_data, struct partition_private_data);
+       if (!data) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       
+       if (!data) {
+               /* We are not going to create a partition before we are even set up */
+               return LDB_ERR_UNWILLING_TO_PERFORM;
+       }
+
+       for (i=0; data->partitions && data->partitions[i]; i++) {
+               if (ldb_dn_compare(data->partitions[i]->ctrl->dn, dn) == 0) {
+                       return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
+               }
+       }
+
+       mod_msg = ldb_msg_new(req);
+       if (!mod_msg) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN);
+       ret = ldb_msg_add_empty(mod_msg, DSDB_PARTITION_ATTR, LDB_FLAG_MOD_ADD, NULL);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+       ret = ldb_msg_add_string(mod_msg, DSDB_PARTITION_ATTR, ldb_dn_get_casefold(dn));
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* Perform modify on @PARTITION record */
+       ret = ldb_build_mod_req(&mod_req, ldb, req, mod_msg, NULL, NULL, 
+                               ldb_op_default_callback, req);
+
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+               
+       ret = ldb_next_request(module, mod_req);
+       if (ret == LDB_SUCCESS) {
+               ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
+       }
+
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       ret = partition_reload_metadata(module, data, req, NULL);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* Make a partition structure for this new partition, so we can copy in the template structure */ 
+       ret = new_partition_from_dn(ldb, data, req, ldb_dn_copy(req, dn), &partition);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /* Start a transaction on the DB (as it won't be in one being brand new) */
+       {
+               struct ldb_module *next = partition->module;
+               PARTITION_FIND_OP(next, start_transaction);
+
+               ret = next->ops->start_transaction(next);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+       
+       /* otherwise, for each replicate, copy from main partition.  If we get an error, we report it up the chain */
+
+       for (i=0; data->replicate && data->replicate[i]; i++) {
+               struct ldb_result *replicate_res;
+               struct ldb_request *add_req;
+               ret = dsdb_module_search_dn(module, req, &replicate_res, 
+                                           data->replicate[i],
+                                           NULL);
+               if (ret == LDB_ERR_NO_SUCH_OBJECT) {
+                       continue;
+               }
+               if (ret != LDB_SUCCESS) {
+                       ldb_asprintf_errstring(ldb,
+                                              "Failed to search for %s from " DSDB_PARTITION_DN 
+                                              " replicateEntries for new partition at %s: %s", 
+                                              ldb_dn_get_linearized(data->replicate[i]), 
+                                              ldb_dn_get_linearized(partition->ctrl->dn), 
+                                              ldb_errstring(ldb));
+                       return ret;
+               }
+
+               /* Build add request */
+               ret = ldb_build_add_req(&add_req, ldb, replicate_res, replicate_res->msgs[0], NULL, NULL, 
+                                       ldb_op_default_callback, mod_req);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+               /* do request */
+               ret = ldb_next_request(partition->module, add_req);
+               
+               /* wait */
+               if (ret == LDB_SUCCESS) {
+                       ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
+               }
+               talloc_free(replicate_res);
+               if (ret != LDB_SUCCESS) {
+                       ldb_asprintf_errstring(ldb,
+                                              "Failed to add %s from " DSDB_PARTITION_DN 
+                                              " replicateEntries to new partition at %s: %s", 
+                                              ldb_dn_get_linearized(data->replicate[i]), 
+                                              ldb_dn_get_linearized(partition->ctrl->dn), 
+                                              ldb_errstring(ldb));
+                       return ret;
+               }               
+               /* And around again, for the next thing we must merge */
+       }
+
+       /* Count the partitions */
+       for (i=0; data->partitions && data->partitions[i]; i++) { /* noop */};
+       
+       /* Add partition to list of partitions */
+       data->partitions = talloc_realloc(data, data->partitions, struct dsdb_partition *, i + 2);
+       if (!data->partitions) {
+               ldb_oom(ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       data->partitions[i] = talloc_steal(data->partitions, partition);
+       data->partitions[i+1] = NULL;
+               
+       /* Sort again (should use binary insert) */
+       qsort(data->partitions, i+1,
+             sizeof(*data->partitions), partition_sort_compare);
+
+       ret = partition_register(ldb, partition->ctrl, req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }               
+
+       /* send request done */
+       return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
+}
+
+
+int partition_init(struct ldb_module *module)
+{
+       int ret, i;
+       TALLOC_CTX *mem_ctx = talloc_new(module);
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct ldb_message *msg;
+       struct ldb_message_element *partition_attributes;
+
+       struct partition_private_data *data;
+
+       if (!mem_ctx) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       data = talloc_zero(mem_ctx, struct partition_private_data);
+       if (data == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = partition_reload_metadata(module, data, mem_ctx, &msg);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       partition_attributes = ldb_msg_find_element(msg, "partition");
+       if (!partition_attributes) {
+               data->partitions = NULL;
+       } else {
+               data->partitions = talloc_array(data, struct dsdb_partition *, partition_attributes->num_values + 1);
+               if (!data->partitions) {
+                       ldb_oom(ldb_module_get_ctx(module));
+                       talloc_free(mem_ctx);
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
+       for (i=0; partition_attributes && i < partition_attributes->num_values; i++) {
+               struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &partition_attributes->values[i]);
+               if (!dn) {
+                       ldb_asprintf_errstring(ldb_module_get_ctx(module), 
+                                              "partition_init: invalid DN in partition record: %s", (const char *)partition_attributes->values[i].data);
+                       talloc_free(mem_ctx);
+                       return LDB_ERR_CONSTRAINT_VIOLATION;
+               }
+       
+               ret = new_partition_from_dn(ldb, data, data->partitions, dn, &data->partitions[i]);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(mem_ctx);
+                       return ret;
+               }
+       }
+
+       if (data->partitions) {
+               data->partitions[i] = NULL;
+
+               /* sort these into order, most to least specific */
+               qsort(data->partitions, partition_attributes->num_values,
+                     sizeof(*data->partitions), partition_sort_compare);
+       }
+
+       for (i=0; data->partitions && data->partitions[i]; i++) {
+               ret = partition_register(ldb, data->partitions[i]->ctrl, mem_ctx);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
+                       "partition: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
+       if (ret != LDB_SUCCESS) {
+               ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
+                       "partition: Unable to register control with rootdse!\n");
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       module->private_data = talloc_steal(module, data);
+
+       talloc_free(mem_ctx);
+       return ldb_next_init(module);
+}
index d86200399a87634646ce1dbb593fa1dafe566304..6b83c6dc5a8ea62d456aa6aca17ddefc5c1bf968 100644 (file)
@@ -98,6 +98,11 @@ struct dsdb_pdc_fsmo {
        struct ldb_dn *master_dn;
 };
 
+#define DSDB_EXTENDED_CREATE_PARTITION_OID "1.3.6.1.4.1.7165.4.4.4"
+struct dsdb_create_partition_exop {
+       struct ldb_dn *new_dn;
+};
+
 /*
  * the schema_dn is passed as struct ldb_dn in
  * req->op.extended.data
@@ -126,4 +131,7 @@ struct dsdb_openldap_dereference_result_control {
        struct dsdb_openldap_dereference_result **attributes;
 };
 
+#define DSDB_PARTITION_DN "@PARTITION"
+#define DSDB_PARTITION_ATTR "partition"
+
 #endif /* __SAMDB_H__ */
index d7fadf3b7eff82243088ff1eb576831920912e76..dff61415a7417d322f401b51e27145ec95b8c86d 100644 (file)
@@ -652,15 +652,11 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                     "linked_attributes",
                     "extended_dn_out_ldb"]
     modules_list2 = ["show_deleted",
+                     "new_partition",
                     "partition"]
-    domaindn_ldb = "users.ldb"
-    configdn_ldb = "configuration.ldb"
-    schemadn_ldb = "schema.ldb"
+    ldap_backend_line = "# No LDAP backend"
     if ldap_backend is not None:
-        domaindn_ldb = ldap_backend.ldapi_uri
-        configdn_ldb = ldap_backend.ldapi_uri
-        schemadn_ldb = ldap_backend.ldapi_uri
+        ldap_backend_line = "ldapBackend: %s" % ldap_backend.ldapi_uri
         
         if ldap_backend.ldap_backend_type == "fedora-ds":
             backend_modules = ["nsuniqueid", "paged_searches"]
@@ -686,13 +682,10 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
     try:
         message("Setting up sam.ldb partitions and settings")
         setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
-                "SCHEMADN": names.schemadn, 
-                "SCHEMADN_LDB": schemadn_ldb,
+                "SCHEMADN": ldb.Dn(samdb, names.schemadn).get_casefold(), 
                 "SCHEMADN_MOD2": ",objectguid",
-                "CONFIGDN": names.configdn,
-                "CONFIGDN_LDB": configdn_ldb,
-                "DOMAINDN": names.domaindn,
-                "DOMAINDN_LDB": domaindn_ldb,
+                "CONFIGDN": ldb.Dn(samdb, names.configdn).get_casefold(),
+                "DOMAINDN": ldb.Dn(samdb, names.domaindn).get_casefold(),
                 "SCHEMADN_MOD": "schema_fsmo",
                 "CONFIGDN_MOD": "naming_fsmo",
                 "DOMAINDN_MOD": "pdc_fsmo",
@@ -700,6 +693,7 @@ def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
                 "TDB_MODULES_LIST": tdb_modules_list_as_string,
                 "MODULES_LIST2": ",".join(modules_list2),
                 "BACKEND_MOD": ",".join(backend_modules),
+                "LDAP_BACKEND_LINE": ldap_backend_line,
         })
 
         samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
index 93fea6bc2d05cfec74cde3d75e239dc7b2e78071..5a18f98b0dc3f75b46d714509dc53cce79525afb 100644 (file)
@@ -1,13 +1,12 @@
 dn: @PARTITION
-partition: ${SCHEMADN}:${SCHEMADN_LDB}
-partition: ${CONFIGDN}:${CONFIGDN_LDB}
-partition: ${DOMAINDN}:${DOMAINDN_LDB}
 replicateEntries: @ATTRIBUTES
 replicateEntries: @INDEXLIST
 replicateEntries: @OPTIONS
 modules:${SCHEMADN}:${SCHEMADN_MOD},${BACKEND_MOD}
 modules:${CONFIGDN}:${CONFIGDN_MOD},${BACKEND_MOD}
 modules:${DOMAINDN}:${DOMAINDN_MOD},${BACKEND_MOD}
+modules:*:${BACKEND_MOD}
+${LDAP_BACKEND_LINE}
 
 dn: @MODULES
 @LIST: ${MODULES_LIST}${TDB_MODULES_LIST},${MODULES_LIST2}
index 76b31f0cd74466611275d1d4a6f1e6d5b5e39164..fd663fd97bffb0f9bf19f6d8769b0e00bec2d0b6 100644 (file)
 #Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1
 #Allocated: DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID 1.3.6.1.4.1.7165.4.4.2
 #Allocated: LDB_EXTENDED_SEQUENCE_NUMBER 1.3.6.1.4.1.7165.4.4.3
+#Allocated: DSDB_EXTENDED_CREATE_PARTITION_OID 1.3.6.1.4.1.7165.4.4.4
 
 #Allocated: (middleName) attributeID: 1.3.6.1.4.1.7165.4.255.1