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;
45 struct ldb_dn **replicate;
48 struct partition_context {
49 struct ldb_module *module;
50 struct ldb_request *orig_req;
52 struct ldb_request **down_req;
54 int finished_requests;
57 static struct ldb_handle *partition_init_handle(struct ldb_request *req, struct ldb_module *module)
59 struct partition_context *ac;
62 h = talloc_zero(req, struct ldb_handle);
64 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
70 ac = talloc_zero(h, struct partition_context);
72 ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
77 h->private_data = (void *)ac;
85 struct ldb_module *make_module_for_next_request(TALLOC_CTX *mem_ctx,
86 struct ldb_context *ldb,
87 struct ldb_module *module)
89 struct ldb_module *current;
90 static const struct ldb_module_ops ops; /* zero */
91 current = talloc_zero(mem_ctx, struct ldb_module);
92 if (current == NULL) {
99 current->next = module;
103 struct ldb_module *find_backend(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
106 struct partition_private_data *data = talloc_get_type(module->private_data,
107 struct partition_private_data);
108 /* Look at base DN */
109 /* Figure out which partition it is under */
110 /* Skip the lot if 'data' isn't here yet (initialistion) */
111 for (i=0; data && data->partitions && data->partitions[i]; i++) {
112 if (ldb_dn_compare_base(module->ldb,
113 data->partitions[i]->dn,
115 return make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
124 fire the caller's callback for every entry, but only send 'done' once.
126 static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
128 struct partition_context *ac;
130 if (!context || !ares) {
131 ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
135 ac = talloc_get_type(context, struct partition_context);
137 if (ares->type == LDB_REPLY_ENTRY) {
138 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
140 ac->finished_requests++;
141 if (ac->finished_requests == ac->num_requests) {
142 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
150 return LDB_ERR_OPERATIONS_ERROR;
154 only fire the 'last' callback, and only for START-TLS for now
156 static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
158 struct partition_context *ac;
160 if (!context || !ares) {
161 ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
165 ac = talloc_get_type(context, struct partition_context);
167 if (ares->type == LDB_REPLY_EXTENDED && strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID)) {
168 ac->finished_requests++;
169 if (ac->finished_requests == ac->num_requests) {
170 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
175 ldb_set_errstring(ldb, talloc_asprintf(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS"));
178 return LDB_ERR_OPERATIONS_ERROR;
182 static int partition_send_request(struct partition_context *ac, struct ldb_module *partition)
185 struct ldb_module *next = make_module_for_next_request(ac->module, ac->module->ldb, partition);
187 ac->down_req = talloc_realloc(ac, ac->down_req,
188 struct ldb_request *, ac->num_requests + 1);
190 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
191 return LDB_ERR_OPERATIONS_ERROR;
193 ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);
194 if (ac->down_req[ac->num_requests] == NULL) {
195 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
196 return LDB_ERR_OPERATIONS_ERROR;
199 *ac->down_req[ac->num_requests] = *ac->orig_req; /* copy the request */
201 if (ac->down_req[ac->num_requests]->operation == LDB_SEARCH) {
202 ac->down_req[ac->num_requests]->callback = partition_search_callback;
203 ac->down_req[ac->num_requests]->context = ac;
205 ac->down_req[ac->num_requests]->callback = partition_other_callback;
206 ac->down_req[ac->num_requests]->context = ac;
209 /* Spray off search requests to all backends */
210 ret = ldb_next_request(next, ac->down_req[ac->num_requests]);
211 if (ret != LDB_SUCCESS) {
219 /* Send a request down to all the partitions */
220 static int partition_send_all(struct ldb_module *module,
221 struct partition_context *ac, struct ldb_request *req)
224 struct partition_private_data *data = talloc_get_type(module->private_data,
225 struct partition_private_data);
226 int ret = partition_send_request(ac, module->next);
227 if (ret != LDB_SUCCESS) {
230 for (i=0; data && data->partitions && data->partitions[i]; i++) {
231 ret = partition_send_request(ac, data->partitions[i]->module);
232 if (ret != LDB_SUCCESS) {
239 /* Figure out which backend a request needs to be aimed at. Some
240 * requests must be replicated to all backends */
241 static int partition_replicate(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
244 struct ldb_module *backend;
245 struct partition_private_data *data = talloc_get_type(module->private_data,
246 struct partition_private_data);
248 /* Is this a special DN, we need to replicate to every backend? */
249 for (i=0; data->replicate && data->replicate[i]; i++) {
250 if (ldb_dn_compare(module->ldb,
253 struct ldb_handle *h;
254 struct partition_context *ac;
256 h = partition_init_handle(req, module);
258 return LDB_ERR_OPERATIONS_ERROR;
260 /* return our own handle to deal with this call */
263 ac = talloc_get_type(h->private_data, struct partition_context);
265 return partition_send_all(module, ac, req);
269 /* Otherwise, we need to find the backend to fire it to */
272 backend = find_backend(module, req, req->op.add.message->dn);
275 return ldb_next_request(backend, req);
280 static int partition_search(struct ldb_module *module, struct ldb_request *req)
283 struct partition_private_data *data = talloc_get_type(module->private_data,
284 struct partition_private_data);
287 /* (later) consider if we should be searching multiple
288 * partitions (for 'invisible' partition behaviour */
289 if (ldb_get_opaque(module->ldb, "global_catalog")) {
291 struct ldb_handle *h;
292 struct partition_context *ac;
294 h = partition_init_handle(req, module);
296 return LDB_ERR_OPERATIONS_ERROR;
298 /* return our own handle to deal with this call */
301 ac = talloc_get_type(h->private_data, struct partition_context);
303 for (i=0; data && data->partitions && data->partitions[i]; i++) {
304 /* Find all partitions under the search base */
305 if (ldb_dn_compare_base(module->ldb,
307 data->partitions[i]->dn) == 0) {
308 ret = partition_send_request(ac, data->partitions[i]->module);
309 if (ret != LDB_SUCCESS) {
315 /* Perhaps we didn't match any partitions. Try the main partition, then all partitions */
316 if (ac->num_requests == 0) {
317 return partition_send_all(module, ac, req);
322 struct ldb_module *backend = find_backend(module, req, req->op.search.base);
324 return ldb_next_request(backend, req);
329 static int partition_add(struct ldb_module *module, struct ldb_request *req)
331 return partition_replicate(module, req, req->op.add.message->dn);
335 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
337 return partition_replicate(module, req, req->op.mod.message->dn);
341 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
343 return partition_replicate(module, req, req->op.del.dn);
347 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
350 struct ldb_module *backend = find_backend(module, req, req->op.rename.olddn);
351 struct ldb_module *backend2 = find_backend(module, req, req->op.rename.newdn);
353 if (backend->next != backend2->next) {
354 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
357 return partition_replicate(module, req, req->op.rename.olddn);
360 /* start a transaction */
361 static int partition_start_trans(struct ldb_module *module)
364 struct partition_private_data *data = talloc_get_type(module->private_data,
365 struct partition_private_data);
366 /* Look at base DN */
367 /* Figure out which partition it is under */
368 /* Skip the lot if 'data' isn't here yet (initialistion) */
369 ret = ldb_next_start_trans(module);
370 if (ret != LDB_SUCCESS) {
374 for (i=0; data && data->partitions && data->partitions[i]; i++) {
375 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
377 ret = ldb_next_start_trans(next);
379 if (ret != LDB_SUCCESS) {
380 /* Back it out, if it fails on one */
381 for (i--; i >= 0; i--) {
382 next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
383 ldb_next_del_trans(next);
392 /* end a transaction */
393 static int partition_end_trans(struct ldb_module *module)
395 int i, ret, ret2 = LDB_SUCCESS;
396 struct partition_private_data *data = talloc_get_type(module->private_data,
397 struct partition_private_data);
398 ret = ldb_next_end_trans(module);
399 if (ret != LDB_SUCCESS) {
403 /* Look at base DN */
404 /* Figure out which partition it is under */
405 /* Skip the lot if 'data' isn't here yet (initialistion) */
406 for (i=0; data && data->partitions && data->partitions[i]; i++) {
407 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
409 ret = ldb_next_end_trans(next);
411 if (ret != LDB_SUCCESS) {
416 if (ret != LDB_SUCCESS) {
417 /* Back it out, if it fails on one */
418 for (i=0; data && data->partitions && data->partitions[i]; i++) {
419 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
420 ldb_next_del_trans(next);
427 /* delete a transaction */
428 static int partition_del_trans(struct ldb_module *module)
430 int i, ret, ret2 = LDB_SUCCESS;
431 struct partition_private_data *data = talloc_get_type(module->private_data,
432 struct partition_private_data);
433 ret = ldb_next_del_trans(module);
434 if (ret != LDB_SUCCESS) {
438 /* Look at base DN */
439 /* Figure out which partition it is under */
440 /* Skip the lot if 'data' isn't here yet (initialistion) */
441 for (i=0; data && data->partitions && data->partitions[i]; i++) {
442 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
444 ret = ldb_next_del_trans(next);
446 if (ret != LDB_SUCCESS) {
453 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
456 uint64_t seq_number = 0;
457 struct partition_private_data *data = talloc_get_type(module->private_data,
458 struct partition_private_data);
459 ret = ldb_next_request(module, req);
460 if (ret != LDB_SUCCESS) {
463 seq_number = seq_number + req->op.seq_num.seq_num;
465 /* Look at base DN */
466 /* Figure out which partition it is under */
467 /* Skip the lot if 'data' isn't here yet (initialistion) */
468 for (i=0; data && data->partitions && data->partitions[i]; i++) {
469 struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
471 ret = ldb_next_request(next, req);
473 if (ret != LDB_SUCCESS) {
476 seq_number = seq_number + req->op.seq_num.seq_num;
478 req->op.seq_num.seq_num = seq_number;
482 static int sort_compare(void *void1,
483 void *void2, void *opaque)
485 struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
486 struct partition **pp1 = void1;
487 struct partition **pp2 = void2;
488 struct partition *partition1 = talloc_get_type(*pp1, struct partition);
489 struct partition *partition2 = talloc_get_type(*pp2, struct partition);
491 return ldb_dn_compare(ldb, partition1->dn, partition2->dn);
494 static int partition_init(struct ldb_module *module)
497 TALLOC_CTX *mem_ctx = talloc_new(module);
498 static const char *attrs[] = { "partition", "replicateEntries", NULL };
499 struct ldb_result *res;
500 struct ldb_message *msg;
501 struct ldb_message_element *partition_attributes;
502 struct ldb_message_element *replicate_attributes;
504 struct partition_private_data *data;
507 return LDB_ERR_OPERATIONS_ERROR;
510 data = talloc(mem_ctx, struct partition_private_data);
512 return LDB_ERR_OPERATIONS_ERROR;
515 ret = ldb_search(module->ldb, ldb_dn_explode(mem_ctx, "@PARTITION"),
519 if (ret != LDB_SUCCESS) {
520 talloc_free(mem_ctx);
523 talloc_steal(mem_ctx, res);
524 if (res->count == 0) {
525 talloc_free(mem_ctx);
526 return ldb_next_init(module);
529 if (res->count > 1) {
530 talloc_free(mem_ctx);
531 return LDB_ERR_CONSTRAINT_VIOLATION;
536 partition_attributes = ldb_msg_find_element(msg, "partition");
537 if (!partition_attributes) {
538 ldb_set_errstring(module->ldb,
539 talloc_asprintf(module, "partition_init: "
540 "no partitions specified"));
541 return LDB_ERR_CONSTRAINT_VIOLATION;
543 data->partitions = talloc_array(data, struct partition *, partition_attributes->num_values + 1);
544 if (!data->partitions) {
545 talloc_free(mem_ctx);
546 return LDB_ERR_OPERATIONS_ERROR;
548 for (i=0; i < partition_attributes->num_values; i++) {
549 char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
550 char *p = strchr(base, ':');
552 ldb_set_errstring(module->ldb,
553 talloc_asprintf(module, "partition_init: "
554 "invalid form for partition record (missing ':'): %s", base));
555 return LDB_ERR_CONSTRAINT_VIOLATION;
560 ldb_set_errstring(module->ldb,
561 talloc_asprintf(module, "partition_init: "
562 "invalid form for partition record (missing backend database): %s", base));
563 return LDB_ERR_CONSTRAINT_VIOLATION;
565 data->partitions[i] = talloc(data->partitions, struct partition);
566 if (!data->partitions[i]) {
567 talloc_free(mem_ctx);
568 return LDB_ERR_OPERATIONS_ERROR;
571 data->partitions[i]->dn = ldb_dn_explode(data->partitions[i], base);
572 if (!data->partitions[i]->dn) {
573 ldb_set_errstring(module->ldb,
574 talloc_asprintf(module, "partition_init: "
575 "invalid DN in partition record: %s", base));
576 return LDB_ERR_CONSTRAINT_VIOLATION;
579 data->partitions[i]->backend = private_path(data->partitions[i], p);
580 ret = ldb_connect_backend(module->ldb, data->partitions[i]->backend, NULL, &data->partitions[i]->module);
581 if (ret != LDB_SUCCESS) {
585 data->partitions[i] = NULL;
587 /* sort these into order, most to least specific */
588 ldb_qsort(data->partitions, partition_attributes->num_values, sizeof(*data->partitions),
589 module->ldb, sort_compare);
591 for (i=0; data->partitions[i]; i++) {
592 struct ldb_request *req;
593 req = talloc_zero(mem_ctx, struct ldb_request);
595 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Out of memory!\n");
596 return LDB_ERR_OPERATIONS_ERROR;
599 req->operation = LDB_REQ_REGISTER_PARTITION;
600 req->op.reg_partition.dn = data->partitions[i]->dn;
602 ret = ldb_request(module->ldb, req);
603 if (ret != LDB_SUCCESS) {
604 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
605 return LDB_ERR_OTHER;
610 replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
611 if (!replicate_attributes) {
612 ldb_set_errstring(module->ldb,
613 talloc_asprintf(module, "partition_init: "
614 "no entries to replicate specified"));
615 data->replicate = NULL;
617 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
618 if (!data->replicate) {
619 talloc_free(mem_ctx);
620 return LDB_ERR_OPERATIONS_ERROR;
623 for (i=0; i < replicate_attributes->num_values; i++) {
624 data->replicate[i] = ldb_dn_explode(data->replicate[i], replicate_attributes->values[i].data);
625 if (!data->replicate[i]) {
626 ldb_set_errstring(module->ldb,
627 talloc_asprintf(module, "partition_init: "
628 "invalid DN in partition replicate record: %s",
629 replicate_attributes->values[i].data));
630 return LDB_ERR_CONSTRAINT_VIOLATION;
633 data->replicate[i] = NULL;
636 module->private_data = data;
637 talloc_steal(module, data);
639 talloc_free(mem_ctx);
640 return ldb_next_init(module);
643 static int partition_wait_none(struct ldb_handle *handle) {
644 struct partition_context *ac;
648 if (!handle || !handle->private_data) {
649 return LDB_ERR_OPERATIONS_ERROR;
652 if (handle->state == LDB_ASYNC_DONE) {
653 return handle->status;
656 handle->state = LDB_ASYNC_PENDING;
657 handle->status = LDB_SUCCESS;
659 ac = talloc_get_type(handle->private_data, struct partition_context);
661 for (i=0; i < ac->num_requests; i++) {
662 ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
664 if (ret != LDB_SUCCESS) {
665 handle->status = ret;
668 if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
669 handle->status = ac->down_req[i]->handle->status;
673 if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
681 handle->state = LDB_ASYNC_DONE;
686 static int partition_wait_all(struct ldb_handle *handle) {
690 while (handle->state != LDB_ASYNC_DONE) {
691 ret = partition_wait_none(handle);
692 if (ret != LDB_SUCCESS) {
697 return handle->status;
700 static int partition_wait(struct ldb_handle *handle, enum ldb_wait_type type)
702 if (type == LDB_WAIT_ALL) {
703 return partition_wait_all(handle);
705 return partition_wait_none(handle);
709 static const struct ldb_module_ops partition_ops = {
711 .init_context = partition_init,
712 .search = partition_search,
713 .add = partition_add,
714 .modify = partition_modify,
715 .del = partition_delete,
716 .rename = partition_rename,
717 .start_transaction = partition_start_trans,
718 .end_transaction = partition_end_trans,
719 .del_transaction = partition_del_trans,
720 .sequence_number = partition_sequence_number,
721 .wait = partition_wait
724 int ldb_partition_init(void)
726 return ldb_register_module(&partition_ops);