4 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
6 * NOTICE: this module is NOT released under the GNU LGPL license as
7 * other ldb code. This module is release under the GNU GPL v2 or
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 * Component: ldb partitions module
30 * Description: Implement LDAP partitions
32 * Author: Andrew Bartlett
36 #include "ldb/include/includes.h"
39 struct ldb_module *module;
43 struct partition_private_data {
44 struct partition **partitions;
47 struct partition_context {
48 struct ldb_module *module;
49 struct ldb_request *orig_req;
51 struct ldb_request **search_req;
52 BOOL *finished_search;
56 static struct ldb_handle *partition_init_handle(struct ldb_request *req, struct ldb_module *module)
58 struct partition_context *ac;
61 h = talloc_zero(req, struct ldb_handle);
63 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
69 ac = talloc_zero(h, struct partition_context);
71 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
76 h->private_data = (void *)ac;
84 struct ldb_module *make_module_for_next_request(TALLOC_CTX *mem_ctx,
85 struct ldb_context *ldb,
86 struct ldb_module *module)
88 struct ldb_module *current;
89 static const struct ldb_module_ops ops; /* zero */
90 current = talloc_zero(mem_ctx, struct ldb_module);
91 if (current == NULL) {
98 current->next = module;
102 struct ldb_module *find_backend(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
105 struct partition_private_data *data = talloc_get_type(module->private_data,
106 struct partition_private_data);
107 /* Look at base DN */
108 /* Figure out which partition it is under */
109 /* Skip the lot if 'data' isn't here yet (initialistion) */
110 for (i=0; data && data->partitions && data->partitions[i]; i++) {
111 if (ldb_dn_compare_base(module->ldb,
112 data->partitions[i]->dn,
114 return make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
121 static int partition_send_search(struct partition_context *ac, struct ldb_module *partition)
124 struct ldb_module *next = make_module_for_next_request(ac->module, ac->module->ldb, partition);
126 ac->search_req = talloc_realloc(ac, ac->search_req,
127 struct ldb_request *, ac->num_searches + 1);
128 if (!ac->search_req) {
129 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
130 return LDB_ERR_OPERATIONS_ERROR;
132 ac->search_req[ac->num_searches] = talloc(ac, struct ldb_request);
133 if (ac->search_req[ac->num_searches] == NULL) {
134 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
135 return LDB_ERR_OPERATIONS_ERROR;
138 *ac->search_req[ac->num_searches] = *ac->orig_req; /* copy the request */
140 /* Spray off search requests to all backends */
141 ret = ldb_next_request(next, ac->search_req[ac->num_searches]);
142 if (ret != LDB_SUCCESS) {
151 static int partition_search(struct ldb_module *module, struct ldb_request *req)
154 struct partition_private_data *data = talloc_get_type(module->private_data,
155 struct partition_private_data);
158 /* (later) consider if we should be searching multiple
159 * partitions (for 'invisible' partition behaviour */
160 if (ldb_get_opaque(module->ldb, "global_catalog")) {
162 struct ldb_handle *h;
163 struct partition_context *ac;
165 h = partition_init_handle(req, module);
167 return LDB_ERR_OPERATIONS_ERROR;
169 /* return our own handle to deal with this call */
172 ac = talloc_get_type(h->private_data, struct partition_context);
175 ac->num_searches = 0;
177 for (i=0; data && data->partitions && data->partitions[i]; i++) {
178 /* Find all partitions under the search base */
179 if (ldb_dn_compare_base(module->ldb,
181 data->partitions[i]->dn) == 0) {
182 ret = partition_send_search(ac, data->partitions[i]->module);
183 if (ret != LDB_SUCCESS) {
189 /* Perhaps we didn't match any partitions. Try the main partition, then all partitions */
190 if (ac->num_searches == 0) {
191 ret = partition_send_search(ac, module->next);
192 if (ret != LDB_SUCCESS) {
195 for (i=0; data && data->partitions && data->partitions[i]; i++) {
196 ret = partition_send_search(ac, data->partitions[i]->module);
197 if (ret != LDB_SUCCESS) {
203 ac->finished_search = talloc_zero_array(ac, BOOL, ac->num_searches);
204 if (!ac->finished_search) {
205 return LDB_ERR_OPERATIONS_ERROR;
209 struct ldb_module *backend = find_backend(module, req, req->op.search.base);
211 return ldb_next_request(backend, req);
216 static int partition_add(struct ldb_module *module, struct ldb_request *req)
219 struct ldb_module *backend = find_backend(module, req, req->op.add.message->dn);
223 return ldb_next_request(backend, req);
227 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
230 struct ldb_module *backend = find_backend(module, req, req->op.mod.message->dn);
234 return ldb_next_request(backend, req);
238 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
241 struct ldb_module *backend = find_backend(module, req, req->op.del.dn);
245 return ldb_next_request(backend, req);
249 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
252 struct ldb_module *backend = find_backend(module, req, req->op.rename.olddn);
253 struct ldb_module *backend2 = find_backend(module, req, req->op.rename.newdn);
255 if (backend->next != backend2->next) {
256 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
261 /* (later) consider if we should be searching multiple partitions */
262 return ldb_next_request(backend, req);
265 /* start a transaction */
266 static int partition_start_trans(struct ldb_module *module)
269 struct partition_private_data *data = talloc_get_type(module->private_data,
270 struct partition_private_data);
271 /* Look at base DN */
272 /* Figure out which partition it is under */
273 /* Skip the lot if 'data' isn't here yet (initialistion) */
274 ret = ldb_next_start_trans(module);
275 if (ret != LDB_SUCCESS) {
279 for (i=0; data && data->partitions && data->partitions[i]; i++) {
280 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
282 ret = ldb_next_start_trans(next);
284 if (ret != LDB_SUCCESS) {
285 /* Back it out, if it fails on one */
286 for (i--; i >= 0; i--) {
287 next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
288 ldb_next_del_trans(next);
297 /* end a transaction */
298 static int partition_end_trans(struct ldb_module *module)
300 int i, ret, ret2 = LDB_SUCCESS;
301 struct partition_private_data *data = talloc_get_type(module->private_data,
302 struct partition_private_data);
303 ret = ldb_next_end_trans(module);
304 if (ret != LDB_SUCCESS) {
308 /* Look at base DN */
309 /* Figure out which partition it is under */
310 /* Skip the lot if 'data' isn't here yet (initialistion) */
311 for (i=0; data && data->partitions && data->partitions[i]; i++) {
312 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
314 ret = ldb_next_end_trans(next);
316 if (ret != LDB_SUCCESS) {
321 if (ret != LDB_SUCCESS) {
322 /* Back it out, if it fails on one */
323 for (i=0; data && data->partitions && data->partitions[i]; i++) {
324 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
325 ldb_next_del_trans(next);
332 /* delete a transaction */
333 static int partition_del_trans(struct ldb_module *module)
335 int i, ret, ret2 = LDB_SUCCESS;
336 struct partition_private_data *data = talloc_get_type(module->private_data,
337 struct partition_private_data);
338 ret = ldb_next_del_trans(module);
339 if (ret != LDB_SUCCESS) {
343 /* Look at base DN */
344 /* Figure out which partition it is under */
345 /* Skip the lot if 'data' isn't here yet (initialistion) */
346 for (i=0; data && data->partitions && data->partitions[i]; i++) {
347 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
349 ret = ldb_next_del_trans(next);
351 if (ret != LDB_SUCCESS) {
358 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
361 uint64_t seq_number = 0;
362 struct partition_private_data *data = talloc_get_type(module->private_data,
363 struct partition_private_data);
364 ret = ldb_next_request(module, req);
365 if (ret != LDB_SUCCESS) {
368 seq_number = seq_number + req->op.seq_num.seq_num;
370 /* Look at base DN */
371 /* Figure out which partition it is under */
372 /* Skip the lot if 'data' isn't here yet (initialistion) */
373 for (i=0; data && data->partitions && data->partitions[i]; i++) {
374 struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
376 ret = ldb_next_request(next, req);
378 if (ret != LDB_SUCCESS) {
381 seq_number = seq_number + req->op.seq_num.seq_num;
383 req->op.seq_num.seq_num = seq_number;
387 static int sort_compare(void *void1,
388 void *void2, void *opaque)
390 struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
391 struct partition **pp1 = void1;
392 struct partition **pp2 = void2;
393 struct partition *partition1 = talloc_get_type(*pp1, struct partition);
394 struct partition *partition2 = talloc_get_type(*pp2, struct partition);
396 return ldb_dn_compare(ldb, partition1->dn, partition2->dn);
399 static int partition_init(struct ldb_module *module)
402 TALLOC_CTX *mem_ctx = talloc_new(module);
403 static const char *attrs[] = { "partition", NULL };
404 struct ldb_result *res;
405 struct ldb_message *msg;
406 struct ldb_message_element *partition_attributes;
408 struct partition_private_data *data;
411 return LDB_ERR_OPERATIONS_ERROR;
414 data = talloc(mem_ctx, struct partition_private_data);
416 return LDB_ERR_OPERATIONS_ERROR;
419 ret = ldb_search(module->ldb, ldb_dn_explode(mem_ctx, "@PARTITION"),
423 if (ret != LDB_SUCCESS) {
424 talloc_free(mem_ctx);
427 talloc_steal(mem_ctx, res);
428 if (res->count == 0) {
429 talloc_free(mem_ctx);
430 return ldb_next_init(module);
433 if (res->count > 1) {
434 talloc_free(mem_ctx);
435 return LDB_ERR_CONSTRAINT_VIOLATION;
440 partition_attributes = ldb_msg_find_element(msg, "partition");
441 if (!partition_attributes) {
442 ldb_set_errstring(module->ldb,
443 talloc_asprintf(module, "partition_init: "
444 "no partitions specified"));
445 return LDB_ERR_CONSTRAINT_VIOLATION;
447 data->partitions = talloc_array(data, struct partition *, partition_attributes->num_values + 1);
448 if (!data->partitions) {
449 talloc_free(mem_ctx);
450 return LDB_ERR_OPERATIONS_ERROR;
452 for (i=0; i < partition_attributes->num_values; i++) {
453 char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
454 char *p = strchr(base, ':');
456 ldb_set_errstring(module->ldb,
457 talloc_asprintf(module, "partition_init: "
458 "invalid form for partition record (missing ':'): %s", base));
459 return LDB_ERR_CONSTRAINT_VIOLATION;
464 ldb_set_errstring(module->ldb,
465 talloc_asprintf(module, "partition_init: "
466 "invalid form for partition record (missing backend database): %s", base));
467 return LDB_ERR_CONSTRAINT_VIOLATION;
469 data->partitions[i] = talloc(data->partitions, struct partition);
470 if (!data->partitions[i]) {
471 talloc_free(mem_ctx);
472 return LDB_ERR_OPERATIONS_ERROR;
475 data->partitions[i]->dn = ldb_dn_explode(data->partitions[i], base);
476 if (!data->partitions[i]->dn) {
477 ldb_set_errstring(module->ldb,
478 talloc_asprintf(module, "partition_init: "
479 "invalid DN in partition record: %s", base));
480 return LDB_ERR_CONSTRAINT_VIOLATION;
483 data->partitions[i]->backend = private_path(data->partitions[i], p);
484 ret = ldb_connect_backend(module->ldb, data->partitions[i]->backend, NULL, &data->partitions[i]->module);
485 if (ret != LDB_SUCCESS) {
489 data->partitions[i] = NULL;
491 /* sort these into order, most to least specific */
492 ldb_qsort(data->partitions, partition_attributes->num_values, sizeof(*data->partitions),
493 module->ldb, sort_compare);
495 for (i=0; data->partitions[i]; i++) {
496 struct ldb_request *req;
497 req = talloc_zero(mem_ctx, struct ldb_request);
499 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Out of memory!\n");
500 return LDB_ERR_OPERATIONS_ERROR;
503 req->operation = LDB_REQ_REGISTER_PARTITION;
504 req->op.reg_partition.dn = data->partitions[i]->dn;
506 ret = ldb_request(module->ldb, req);
507 if (ret != LDB_SUCCESS) {
508 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
509 return LDB_ERR_OTHER;
514 module->private_data = data;
515 talloc_steal(module, data);
517 talloc_free(mem_ctx);
518 return ldb_next_init(module);
521 static int partition_wait_none(struct ldb_handle *handle) {
522 struct partition_context *ac;
526 if (!handle || !handle->private_data) {
527 return LDB_ERR_OPERATIONS_ERROR;
530 if (handle->state == LDB_ASYNC_DONE) {
531 return handle->status;
534 handle->state = LDB_ASYNC_PENDING;
535 handle->status = LDB_SUCCESS;
537 ac = talloc_get_type(handle->private_data, struct partition_context);
539 for (i=0; i < ac->num_searches; i++) {
540 ret = ldb_wait(ac->search_req[i]->handle, LDB_WAIT_NONE);
542 if (ret != LDB_SUCCESS) {
543 handle->status = ret;
546 if (ac->search_req[i]->handle->status != LDB_SUCCESS) {
547 handle->status = ac->search_req[i]->handle->status;
551 if (ac->search_req[i]->handle->state != LDB_ASYNC_DONE) {
559 handle->state = LDB_ASYNC_DONE;
564 static int partition_wait_all(struct ldb_handle *handle) {
568 while (handle->state != LDB_ASYNC_DONE) {
569 ret = partition_wait_none(handle);
570 if (ret != LDB_SUCCESS) {
575 return handle->status;
578 static int partition_wait(struct ldb_handle *handle, enum ldb_wait_type type)
580 if (type == LDB_WAIT_ALL) {
581 return partition_wait_all(handle);
583 return partition_wait_none(handle);
587 static const struct ldb_module_ops partition_ops = {
589 .init_context = partition_init,
590 .search = partition_search,
591 .add = partition_add,
592 .modify = partition_modify,
593 .del = partition_delete,
594 .rename = partition_rename,
595 .start_transaction = partition_start_trans,
596 .end_transaction = partition_end_trans,
597 .del_transaction = partition_del_trans,
598 .sequence_number = partition_sequence_number,
599 .wait = partition_wait
602 int ldb_partition_init(void)
604 return ldb_register_module(&partition_ops);