4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * Component: ldb partitions module
26 * Description: Implement LDAP partitions
28 * Author: Andrew Bartlett
29 * Author: Stefan Metzmacher
32 #include "dsdb/samdb/ldb_modules/partition.h"
34 static int partition_sort_compare(const void *v1, const void *v2)
36 const struct dsdb_partition *p1;
37 const struct dsdb_partition *p2;
39 p1 = *((struct dsdb_partition * const*)v1);
40 p2 = *((struct dsdb_partition * const*)v2);
42 return ldb_dn_compare(p1->ctrl->dn, p2->ctrl->dn);
45 /* Load the list of DNs that we must replicate to all partitions */
46 static int partition_load_replicate_dns(struct ldb_context *ldb, struct partition_private_data *data, struct ldb_message *msg)
48 struct ldb_message_element *replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
50 talloc_free(data->replicate);
51 if (!replicate_attributes) {
52 data->replicate = NULL;
55 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
56 if (!data->replicate) {
57 return LDB_ERR_OPERATIONS_ERROR;
60 for (i=0; i < replicate_attributes->num_values; i++) {
61 data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb, &replicate_attributes->values[i]);
62 if (!ldb_dn_validate(data->replicate[i])) {
63 ldb_asprintf_errstring(ldb,
65 "invalid DN in partition replicate record: %s",
66 replicate_attributes->values[i].data);
67 return LDB_ERR_CONSTRAINT_VIOLATION;
70 data->replicate[i] = NULL;
75 /* Load the list of modules for the partitions */
76 static int partition_load_modules(struct ldb_context *ldb,
77 struct partition_private_data *data, struct ldb_message *msg)
80 struct ldb_message_element *modules_attributes = ldb_msg_find_element(msg, "modules");
81 talloc_free(data->modules);
82 if (!modules_attributes) {
86 data->modules = talloc_array(data, struct partition_module *, modules_attributes->num_values + 1);
89 return LDB_ERR_OPERATIONS_ERROR;
92 for (i=0; i < modules_attributes->num_values; i++) {
96 data->modules[i] = talloc(data->modules, struct partition_module);
97 if (!data->modules[i]) {
99 return LDB_ERR_OPERATIONS_ERROR;
102 base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
103 p = strchr(base, ':');
105 ldb_asprintf_errstring(ldb,
106 "partition_load_modules: "
107 "invalid form for partition module record (missing ':'): %s", base);
108 return LDB_ERR_CONSTRAINT_VIOLATION;
112 data->modules[i]->modules = ldb_modules_list_from_string(ldb, data->modules[i],
115 if (strcmp(base, "*") == 0) {
116 data->modules[i]->dn = NULL;
118 data->modules[i]->dn = ldb_dn_new(data->modules[i], ldb, base);
119 if (!data->modules[i]->dn || !ldb_dn_validate(data->modules[i]->dn)) {
120 return LDB_ERR_OPERATIONS_ERROR;
127 static int partition_reload_metadata(struct ldb_module *module, struct partition_private_data *data, TALLOC_CTX *mem_ctx, struct ldb_message **_msg)
130 struct ldb_message *msg;
131 struct ldb_result *res;
132 struct ldb_context *ldb = ldb_module_get_ctx(module);
133 const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
134 /* perform search for @PARTITION, looking for module, replicateEntries and ldapBackend */
135 ret = dsdb_module_search_dn(module, mem_ctx, &res,
136 ldb_dn_new(mem_ctx, ldb, DSDB_PARTITION_DN),
138 if (ret != LDB_SUCCESS) {
144 ret = partition_load_replicate_dns(ldb, data, msg);
145 if (ret != LDB_SUCCESS) {
149 ret = partition_load_modules(ldb, data, msg);
150 if (ret != LDB_SUCCESS) {
154 data->ldapBackend = talloc_steal(data, ldb_msg_find_attr_as_string(msg, "ldapBackend", NULL));
163 static const char **find_modules_for_dn(struct partition_private_data *data, struct ldb_dn *dn)
166 struct partition_module *default_mod = NULL;
167 for (i=0; data->modules && data->modules[i]; i++) {
168 if (!data->modules[i]->dn) {
169 default_mod = data->modules[i];
170 } else if (ldb_dn_compare(dn, data->modules[i]->dn) == 0) {
171 return data->modules[i]->modules;
175 return default_mod->modules;
181 static int new_partition_from_dn(struct ldb_context *ldb, struct partition_private_data *data,
184 struct dsdb_partition **partition) {
185 const char *backend_name;
186 const char *full_backend;
187 struct dsdb_control_current_partition *ctrl;
188 struct ldb_module *module;
189 const char **modules;
192 (*partition) = talloc(mem_ctx, struct dsdb_partition);
194 return LDB_ERR_OPERATIONS_ERROR;
197 (*partition)->ctrl = ctrl = talloc((*partition), struct dsdb_control_current_partition);
199 talloc_free(*partition);
201 return LDB_ERR_OPERATIONS_ERROR;
204 /* See if an LDAP backend has been specified */
205 if (data->ldapBackend) {
206 backend_name = data->ldapBackend;
208 /* If we don't have a : in the record, then the partition name is the name of the LDB */
209 backend_name = talloc_asprintf(data, "%s.ldb", ldb_dn_get_casefold(dn));
212 ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
213 ctrl->dn = talloc_steal(ctrl, dn);
215 full_backend = samdb_relative_path(ldb,
219 ldb_asprintf_errstring(ldb_module_get_ctx(module),
220 "partition_init: unable to determine an relative path for partition: %s", backend_name);
221 talloc_free(*partition);
222 return LDB_ERR_OPERATIONS_ERROR;
225 ret = ldb_connect_backend(ldb, full_backend, NULL, &module);
226 if (ret != LDB_SUCCESS) {
230 modules = find_modules_for_dn(data, dn);
232 ret = ldb_load_modules_list(ldb, modules, module, &(*partition)->module);
233 if (ret != LDB_SUCCESS) {
234 ldb_asprintf_errstring(ldb,
236 "loading backend for %s failed: %s",
237 ldb_dn_get_linearized(dn), ldb_errstring(ldb));
238 talloc_free(*partition);
241 ret = ldb_init_module_chain(ldb, (*partition)->module);
242 if (ret != LDB_SUCCESS) {
243 ldb_asprintf_errstring(ldb,
245 "initialising backend for %s failed: %s",
246 ldb_dn_get_linearized(dn), ldb_errstring(ldb));
247 talloc_free(*partition);
251 talloc_steal((*partition), (*partition)->module);
256 static int partition_register(struct ldb_context *ldb, struct dsdb_control_current_partition *ctrl, TALLOC_CTX *mem_ctx)
258 struct ldb_request *req;
261 req = talloc_zero(mem_ctx, struct ldb_request);
264 return LDB_ERR_OPERATIONS_ERROR;
267 req->operation = LDB_REQ_REGISTER_PARTITION;
268 req->op.reg_partition.dn = ctrl->dn;
269 req->callback = ldb_op_default_callback;
271 ldb_set_timeout(ldb, req, 0);
273 req->handle = ldb_handle_new(req, ldb);
274 if (req->handle == NULL) {
275 return LDB_ERR_OPERATIONS_ERROR;
278 ret = ldb_request(ldb, req);
279 if (ret == LDB_SUCCESS) {
280 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
282 if (ret != LDB_SUCCESS) {
283 ldb_debug(ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
284 talloc_free(mem_ctx);
285 return LDB_ERR_OTHER;
292 int partition_create(struct ldb_module *module, struct ldb_request *req)
295 struct ldb_context *ldb = ldb_module_get_ctx(module);
296 struct ldb_request *mod_req;
297 struct ldb_message *mod_msg;
298 struct partition_private_data *data;
299 struct dsdb_partition *partition;
301 /* Check if this is already a partition */
303 struct dsdb_create_partition_exop *ex_op = talloc_get_type(req->op.extended.data, struct dsdb_create_partition_exop);
304 struct ldb_dn *dn = ex_op->new_dn;
306 data = talloc_get_type(module->private_data, struct partition_private_data);
308 return LDB_ERR_OPERATIONS_ERROR;
312 /* We are not going to create a partition before we are even set up */
313 return LDB_ERR_UNWILLING_TO_PERFORM;
316 for (i=0; data->partitions && data->partitions[i]; i++) {
317 if (ldb_dn_compare(data->partitions[i]->ctrl->dn, dn) == 0) {
318 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
322 mod_msg = ldb_msg_new(req);
325 return LDB_ERR_OPERATIONS_ERROR;
328 mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN);
329 ret = ldb_msg_add_empty(mod_msg, DSDB_PARTITION_ATTR, LDB_FLAG_MOD_ADD, NULL);
330 if (ret != LDB_SUCCESS) {
333 ret = ldb_msg_add_string(mod_msg, DSDB_PARTITION_ATTR, ldb_dn_get_casefold(dn));
334 if (ret != LDB_SUCCESS) {
338 /* Perform modify on @PARTITION record */
339 ret = ldb_build_mod_req(&mod_req, ldb, req, mod_msg, NULL, NULL,
340 ldb_op_default_callback, req);
342 if (ret != LDB_SUCCESS) {
346 ret = ldb_next_request(module, mod_req);
347 if (ret == LDB_SUCCESS) {
348 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
351 if (ret != LDB_SUCCESS) {
355 ret = partition_reload_metadata(module, data, req, NULL);
356 if (ret != LDB_SUCCESS) {
360 /* Make a partition structure for this new partition, so we can copy in the template structure */
361 ret = new_partition_from_dn(ldb, data, req, ldb_dn_copy(req, dn), &partition);
362 if (ret != LDB_SUCCESS) {
366 /* Start a transaction on the DB (as it won't be in one being brand new) */
368 struct ldb_module *next = partition->module;
369 PARTITION_FIND_OP(next, start_transaction);
371 ret = next->ops->start_transaction(next);
372 if (ret != LDB_SUCCESS) {
377 /* otherwise, for each replicate, copy from main partition. If we get an error, we report it up the chain */
379 for (i=0; data->replicate && data->replicate[i]; i++) {
380 struct ldb_result *replicate_res;
381 struct ldb_request *add_req;
382 ret = dsdb_module_search_dn(module, req, &replicate_res,
385 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
388 if (ret != LDB_SUCCESS) {
389 ldb_asprintf_errstring(ldb,
390 "Failed to search for %s from " DSDB_PARTITION_DN
391 " replicateEntries for new partition at %s: %s",
392 ldb_dn_get_linearized(data->replicate[i]),
393 ldb_dn_get_linearized(partition->ctrl->dn),
398 /* Build add request */
399 ret = ldb_build_add_req(&add_req, ldb, replicate_res, replicate_res->msgs[0], NULL, NULL,
400 ldb_op_default_callback, mod_req);
401 if (ret != LDB_SUCCESS) {
405 ret = ldb_next_request(partition->module, add_req);
408 if (ret == LDB_SUCCESS) {
409 ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
411 talloc_free(replicate_res);
412 if (ret != LDB_SUCCESS) {
413 ldb_asprintf_errstring(ldb,
414 "Failed to add %s from " DSDB_PARTITION_DN
415 " replicateEntries to new partition at %s: %s",
416 ldb_dn_get_linearized(data->replicate[i]),
417 ldb_dn_get_linearized(partition->ctrl->dn),
421 /* And around again, for the next thing we must merge */
424 /* Count the partitions */
425 for (i=0; data->partitions && data->partitions[i]; i++) { /* noop */};
427 /* Add partition to list of partitions */
428 data->partitions = talloc_realloc(data, data->partitions, struct dsdb_partition *, i + 2);
429 if (!data->partitions) {
431 return LDB_ERR_OPERATIONS_ERROR;
433 data->partitions[i] = talloc_steal(data->partitions, partition);
434 data->partitions[i+1] = NULL;
436 /* Sort again (should use binary insert) */
437 qsort(data->partitions, i+1,
438 sizeof(*data->partitions), partition_sort_compare);
440 ret = partition_register(ldb, partition->ctrl, req);
441 if (ret != LDB_SUCCESS) {
445 /* send request done */
446 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
450 int partition_init(struct ldb_module *module)
453 TALLOC_CTX *mem_ctx = talloc_new(module);
454 struct ldb_context *ldb = ldb_module_get_ctx(module);
455 struct ldb_message *msg;
456 struct ldb_message_element *partition_attributes;
458 struct partition_private_data *data;
461 return LDB_ERR_OPERATIONS_ERROR;
464 data = talloc_zero(mem_ctx, struct partition_private_data);
466 return LDB_ERR_OPERATIONS_ERROR;
469 ret = partition_reload_metadata(module, data, mem_ctx, &msg);
470 if (ret != LDB_SUCCESS) {
474 partition_attributes = ldb_msg_find_element(msg, "partition");
475 if (!partition_attributes) {
476 data->partitions = NULL;
478 data->partitions = talloc_array(data, struct dsdb_partition *, partition_attributes->num_values + 1);
479 if (!data->partitions) {
480 ldb_oom(ldb_module_get_ctx(module));
481 talloc_free(mem_ctx);
482 return LDB_ERR_OPERATIONS_ERROR;
485 for (i=0; partition_attributes && i < partition_attributes->num_values; i++) {
486 struct ldb_dn *dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &partition_attributes->values[i]);
488 ldb_asprintf_errstring(ldb_module_get_ctx(module),
489 "partition_init: invalid DN in partition record: %s", (const char *)partition_attributes->values[i].data);
490 talloc_free(mem_ctx);
491 return LDB_ERR_CONSTRAINT_VIOLATION;
494 ret = new_partition_from_dn(ldb, data, data->partitions, dn, &data->partitions[i]);
495 if (ret != LDB_SUCCESS) {
496 talloc_free(mem_ctx);
501 if (data->partitions) {
502 data->partitions[i] = NULL;
504 /* sort these into order, most to least specific */
505 qsort(data->partitions, partition_attributes->num_values,
506 sizeof(*data->partitions), partition_sort_compare);
509 for (i=0; data->partitions && data->partitions[i]; i++) {
510 ret = partition_register(ldb, data->partitions[i]->ctrl, mem_ctx);
511 if (ret != LDB_SUCCESS) {
516 ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
517 if (ret != LDB_SUCCESS) {
518 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
519 "partition: Unable to register control with rootdse!\n");
520 return LDB_ERR_OPERATIONS_ERROR;
523 ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
524 if (ret != LDB_SUCCESS) {
525 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
526 "partition: Unable to register control with rootdse!\n");
527 return LDB_ERR_OPERATIONS_ERROR;
530 module->private_data = talloc_steal(module, data);
532 talloc_free(mem_ctx);
533 return ldb_next_init(module);