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, "partition_search_callback: NULL Context or Result in 'search' 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;
161 ldb_set_errstring(ldb, talloc_asprintf(ldb, "partition_other_callback: NULL Context in 'other' callback"));
165 ac = talloc_get_type(context, struct partition_context);
167 if (!ac->orig_req->callback) {
173 || (ares->type == LDB_REPLY_EXTENDED
174 && strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID))) {
175 ac->finished_requests++;
176 if (ac->finished_requests == ac->num_requests) {
177 return ac->orig_req->callback(ldb, ac->orig_req->context, ares);
182 ldb_set_errstring(ldb, talloc_asprintf(ldb, "partition_other_callback: Unknown reply type, only supports START_TLS"));
185 return LDB_ERR_OPERATIONS_ERROR;
189 static int partition_send_request(struct partition_context *ac, struct ldb_module *partition)
192 struct ldb_module *next = make_module_for_next_request(ac->module, ac->module->ldb, partition);
194 ac->down_req = talloc_realloc(ac, ac->down_req,
195 struct ldb_request *, ac->num_requests + 1);
197 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
198 return LDB_ERR_OPERATIONS_ERROR;
200 ac->down_req[ac->num_requests] = talloc(ac, struct ldb_request);
201 if (ac->down_req[ac->num_requests] == NULL) {
202 ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac->module->ldb, "Out of memory!"));
203 return LDB_ERR_OPERATIONS_ERROR;
206 *ac->down_req[ac->num_requests] = *ac->orig_req; /* copy the request */
208 if (ac->down_req[ac->num_requests]->operation == LDB_SEARCH) {
209 ac->down_req[ac->num_requests]->callback = partition_search_callback;
210 ac->down_req[ac->num_requests]->context = ac;
212 ac->down_req[ac->num_requests]->callback = partition_other_callback;
213 ac->down_req[ac->num_requests]->context = ac;
216 /* Spray off search requests to all backends */
217 ret = ldb_next_request(next, ac->down_req[ac->num_requests]);
218 if (ret != LDB_SUCCESS) {
226 /* Send a request down to all the partitions */
227 static int partition_send_all(struct ldb_module *module,
228 struct partition_context *ac, struct ldb_request *req)
231 struct partition_private_data *data = talloc_get_type(module->private_data,
232 struct partition_private_data);
233 int ret = partition_send_request(ac, module->next);
234 if (ret != LDB_SUCCESS) {
237 for (i=0; data && data->partitions && data->partitions[i]; i++) {
238 ret = partition_send_request(ac, data->partitions[i]->module);
239 if (ret != LDB_SUCCESS) {
246 /* Figure out which backend a request needs to be aimed at. Some
247 * requests must be replicated to all backends */
248 static int partition_replicate(struct ldb_module *module, struct ldb_request *req, const struct ldb_dn *dn)
251 struct ldb_module *backend;
252 struct partition_private_data *data = talloc_get_type(module->private_data,
253 struct partition_private_data);
255 /* Is this a special DN, we need to replicate to every backend? */
256 for (i=0; data->replicate && data->replicate[i]; i++) {
257 if (ldb_dn_compare(module->ldb,
260 struct ldb_handle *h;
261 struct partition_context *ac;
263 h = partition_init_handle(req, module);
265 return LDB_ERR_OPERATIONS_ERROR;
267 /* return our own handle to deal with this call */
270 ac = talloc_get_type(h->private_data, struct partition_context);
272 return partition_send_all(module, ac, req);
276 /* Otherwise, we need to find the backend to fire it to */
279 backend = find_backend(module, req, dn);
282 return ldb_next_request(backend, req);
287 static int partition_search(struct ldb_module *module, struct ldb_request *req)
290 struct partition_private_data *data = talloc_get_type(module->private_data,
291 struct partition_private_data);
294 /* (later) consider if we should be searching multiple
295 * partitions (for 'invisible' partition behaviour */
296 if (ldb_get_opaque(module->ldb, "global_catalog")) {
298 struct ldb_handle *h;
299 struct partition_context *ac;
301 h = partition_init_handle(req, module);
303 return LDB_ERR_OPERATIONS_ERROR;
305 /* return our own handle to deal with this call */
308 ac = talloc_get_type(h->private_data, struct partition_context);
310 for (i=0; data && data->partitions && data->partitions[i]; i++) {
311 /* Find all partitions under the search base */
312 if (ldb_dn_compare_base(module->ldb,
314 data->partitions[i]->dn) == 0) {
315 ret = partition_send_request(ac, data->partitions[i]->module);
316 if (ret != LDB_SUCCESS) {
322 /* Perhaps we didn't match any partitions. Try the main partition, then all partitions */
323 if (ac->num_requests == 0) {
324 return partition_send_all(module, ac, req);
329 struct ldb_module *backend = find_backend(module, req, req->op.search.base);
331 return ldb_next_request(backend, req);
336 static int partition_add(struct ldb_module *module, struct ldb_request *req)
338 return partition_replicate(module, req, req->op.add.message->dn);
342 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
344 return partition_replicate(module, req, req->op.mod.message->dn);
348 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
350 return partition_replicate(module, req, req->op.del.dn);
354 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
357 struct ldb_module *backend = find_backend(module, req, req->op.rename.olddn);
358 struct ldb_module *backend2 = find_backend(module, req, req->op.rename.newdn);
360 if (backend->next != backend2->next) {
361 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
364 return partition_replicate(module, req, req->op.rename.olddn);
367 /* start a transaction */
368 static int partition_start_trans(struct ldb_module *module)
371 struct partition_private_data *data = talloc_get_type(module->private_data,
372 struct partition_private_data);
373 /* Look at base DN */
374 /* Figure out which partition it is under */
375 /* Skip the lot if 'data' isn't here yet (initialistion) */
376 ret = ldb_next_start_trans(module);
377 if (ret != LDB_SUCCESS) {
381 for (i=0; data && data->partitions && data->partitions[i]; i++) {
382 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
384 ret = ldb_next_start_trans(next);
386 if (ret != LDB_SUCCESS) {
387 /* Back it out, if it fails on one */
388 for (i--; i >= 0; i--) {
389 next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
390 ldb_next_del_trans(next);
399 /* end a transaction */
400 static int partition_end_trans(struct ldb_module *module)
402 int i, ret, ret2 = LDB_SUCCESS;
403 struct partition_private_data *data = talloc_get_type(module->private_data,
404 struct partition_private_data);
405 ret = ldb_next_end_trans(module);
406 if (ret != LDB_SUCCESS) {
410 /* Look at base DN */
411 /* Figure out which partition it is under */
412 /* Skip the lot if 'data' isn't here yet (initialistion) */
413 for (i=0; data && data->partitions && data->partitions[i]; i++) {
414 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
416 ret = ldb_next_end_trans(next);
418 if (ret != LDB_SUCCESS) {
423 if (ret != LDB_SUCCESS) {
424 /* Back it out, if it fails on one */
425 for (i=0; data && data->partitions && data->partitions[i]; i++) {
426 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
427 ldb_next_del_trans(next);
434 /* delete a transaction */
435 static int partition_del_trans(struct ldb_module *module)
437 int i, ret, ret2 = LDB_SUCCESS;
438 struct partition_private_data *data = talloc_get_type(module->private_data,
439 struct partition_private_data);
440 ret = ldb_next_del_trans(module);
441 if (ret != LDB_SUCCESS) {
445 /* Look at base DN */
446 /* Figure out which partition it is under */
447 /* Skip the lot if 'data' isn't here yet (initialistion) */
448 for (i=0; data && data->partitions && data->partitions[i]; i++) {
449 struct ldb_module *next = make_module_for_next_request(module, module->ldb, data->partitions[i]->module);
451 ret = ldb_next_del_trans(next);
453 if (ret != LDB_SUCCESS) {
460 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
463 uint64_t seq_number = 0;
464 struct partition_private_data *data = talloc_get_type(module->private_data,
465 struct partition_private_data);
466 ret = ldb_next_request(module, req);
467 if (ret != LDB_SUCCESS) {
470 seq_number = seq_number + req->op.seq_num.seq_num;
472 /* Look at base DN */
473 /* Figure out which partition it is under */
474 /* Skip the lot if 'data' isn't here yet (initialistion) */
475 for (i=0; data && data->partitions && data->partitions[i]; i++) {
476 struct ldb_module *next = make_module_for_next_request(req, module->ldb, data->partitions[i]->module);
478 ret = ldb_next_request(next, req);
480 if (ret != LDB_SUCCESS) {
483 seq_number = seq_number + req->op.seq_num.seq_num;
485 req->op.seq_num.seq_num = seq_number;
489 static int sort_compare(void *void1,
490 void *void2, void *opaque)
492 struct ldb_context *ldb = talloc_get_type(opaque, struct ldb_context);
493 struct partition **pp1 = void1;
494 struct partition **pp2 = void2;
495 struct partition *partition1 = talloc_get_type(*pp1, struct partition);
496 struct partition *partition2 = talloc_get_type(*pp2, struct partition);
498 return ldb_dn_compare(ldb, partition1->dn, partition2->dn);
501 static int partition_init(struct ldb_module *module)
504 TALLOC_CTX *mem_ctx = talloc_new(module);
505 static const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
506 struct ldb_result *res;
507 struct ldb_message *msg;
508 struct ldb_message_element *partition_attributes;
509 struct ldb_message_element *replicate_attributes;
510 struct ldb_message_element *modules_attributes;
512 struct partition_private_data *data;
515 return LDB_ERR_OPERATIONS_ERROR;
518 data = talloc(mem_ctx, struct partition_private_data);
520 return LDB_ERR_OPERATIONS_ERROR;
523 ret = ldb_search(module->ldb, ldb_dn_explode(mem_ctx, "@PARTITION"),
527 if (ret != LDB_SUCCESS) {
528 talloc_free(mem_ctx);
531 talloc_steal(mem_ctx, res);
532 if (res->count == 0) {
533 talloc_free(mem_ctx);
534 return ldb_next_init(module);
537 if (res->count > 1) {
538 talloc_free(mem_ctx);
539 return LDB_ERR_CONSTRAINT_VIOLATION;
544 partition_attributes = ldb_msg_find_element(msg, "partition");
545 if (!partition_attributes) {
546 ldb_set_errstring(module->ldb,
547 talloc_asprintf(module, "partition_init: "
548 "no partitions specified"));
549 talloc_free(mem_ctx);
550 return LDB_ERR_CONSTRAINT_VIOLATION;
552 data->partitions = talloc_array(data, struct partition *, partition_attributes->num_values + 1);
553 if (!data->partitions) {
554 talloc_free(mem_ctx);
555 return LDB_ERR_OPERATIONS_ERROR;
557 for (i=0; i < partition_attributes->num_values; i++) {
558 char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
559 char *p = strchr(base, ':');
561 ldb_set_errstring(module->ldb,
562 talloc_asprintf(module, "partition_init: "
563 "invalid form for partition record (missing ':'): %s", base));
564 talloc_free(mem_ctx);
565 return LDB_ERR_CONSTRAINT_VIOLATION;
570 ldb_set_errstring(module->ldb,
571 talloc_asprintf(module, "partition_init: "
572 "invalid form for partition record (missing backend database): %s", base));
573 talloc_free(mem_ctx);
574 return LDB_ERR_CONSTRAINT_VIOLATION;
576 data->partitions[i] = talloc(data->partitions, struct partition);
577 if (!data->partitions[i]) {
578 talloc_free(mem_ctx);
579 return LDB_ERR_OPERATIONS_ERROR;
582 data->partitions[i]->dn = ldb_dn_explode(data->partitions[i], base);
583 if (!data->partitions[i]->dn) {
584 ldb_set_errstring(module->ldb,
585 talloc_asprintf(module, "partition_init: "
586 "invalid DN in partition record: %s", base));
587 talloc_free(mem_ctx);
588 return LDB_ERR_CONSTRAINT_VIOLATION;
591 data->partitions[i]->backend = private_path(data->partitions[i], p);
592 ret = ldb_connect_backend(module->ldb, data->partitions[i]->backend, NULL, &data->partitions[i]->module);
593 if (ret != LDB_SUCCESS) {
594 talloc_free(mem_ctx);
598 data->partitions[i] = NULL;
600 /* sort these into order, most to least specific */
601 ldb_qsort(data->partitions, partition_attributes->num_values, sizeof(*data->partitions),
602 module->ldb, sort_compare);
604 for (i=0; data->partitions[i]; i++) {
605 struct ldb_request *req;
606 req = talloc_zero(mem_ctx, struct ldb_request);
608 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Out of memory!\n");
609 talloc_free(mem_ctx);
610 return LDB_ERR_OPERATIONS_ERROR;
613 req->operation = LDB_REQ_REGISTER_PARTITION;
614 req->op.reg_partition.dn = data->partitions[i]->dn;
616 ret = ldb_request(module->ldb, req);
617 if (ret != LDB_SUCCESS) {
618 ldb_debug(module->ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
619 talloc_free(mem_ctx);
620 return LDB_ERR_OTHER;
625 replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
626 if (!replicate_attributes) {
627 data->replicate = NULL;
629 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
630 if (!data->replicate) {
631 talloc_free(mem_ctx);
632 return LDB_ERR_OPERATIONS_ERROR;
635 for (i=0; i < replicate_attributes->num_values; i++) {
636 data->replicate[i] = ldb_dn_explode(data->replicate, replicate_attributes->values[i].data);
637 if (!data->replicate[i]) {
638 ldb_set_errstring(module->ldb,
639 talloc_asprintf(module, "partition_init: "
640 "invalid DN in partition replicate record: %s",
641 replicate_attributes->values[i].data));
642 talloc_free(mem_ctx);
643 return LDB_ERR_CONSTRAINT_VIOLATION;
646 data->replicate[i] = NULL;
649 modules_attributes = ldb_msg_find_element(msg, "modules");
650 if (modules_attributes) {
651 for (i=0; i < modules_attributes->num_values; i++) {
652 struct ldb_dn *base_dn;
654 struct partition *partition = NULL;
655 const char **modules = NULL;
657 char *base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
658 char *p = strchr(base, ':');
660 ldb_set_errstring(module->ldb,
661 talloc_asprintf(mem_ctx, "partition_init: "
662 "invalid form for partition module record (missing ':'): %s", base));
663 talloc_free(mem_ctx);
664 return LDB_ERR_CONSTRAINT_VIOLATION;
669 ldb_set_errstring(module->ldb,
670 talloc_asprintf(mem_ctx, "partition_init: "
671 "invalid form for partition module record (missing backend database): %s", base));
672 talloc_free(mem_ctx);
673 return LDB_ERR_CONSTRAINT_VIOLATION;
676 modules = ldb_modules_list_from_string(module->ldb, mem_ctx,
679 base_dn = ldb_dn_explode(mem_ctx, base);
681 talloc_free(mem_ctx);
682 return LDB_ERR_OPERATIONS_ERROR;
685 for (partition_idx = 0; data->partitions[partition_idx]; partition_idx++) {
686 if (ldb_dn_compare(module->ldb, data->partitions[partition_idx]->dn,
688 partition = data->partitions[partition_idx];
694 ldb_set_errstring(module->ldb,
695 talloc_asprintf(mem_ctx, "partition_init: "
696 "invalid form for partition module record (no such partition): %s", base));
697 talloc_free(mem_ctx);
698 return LDB_ERR_CONSTRAINT_VIOLATION;
701 ret = ldb_load_modules_list(module->ldb, modules, partition->module, &partition->module);
702 if (ret != LDB_SUCCESS) {
703 talloc_free(mem_ctx);
706 ret = ldb_init_module_chain(module->ldb, partition->module);
707 if (ret != LDB_SUCCESS) {
708 talloc_free(mem_ctx);
714 module->private_data = data;
715 talloc_steal(module, data);
717 talloc_free(mem_ctx);
718 return ldb_next_init(module);
721 static int partition_wait_none(struct ldb_handle *handle) {
722 struct partition_context *ac;
726 if (!handle || !handle->private_data) {
727 return LDB_ERR_OPERATIONS_ERROR;
730 if (handle->state == LDB_ASYNC_DONE) {
731 return handle->status;
734 handle->state = LDB_ASYNC_PENDING;
735 handle->status = LDB_SUCCESS;
737 ac = talloc_get_type(handle->private_data, struct partition_context);
739 for (i=0; i < ac->num_requests; i++) {
740 ret = ldb_wait(ac->down_req[i]->handle, LDB_WAIT_NONE);
742 if (ret != LDB_SUCCESS) {
743 handle->status = ret;
746 if (ac->down_req[i]->handle->status != LDB_SUCCESS) {
747 handle->status = ac->down_req[i]->handle->status;
751 if (ac->down_req[i]->handle->state != LDB_ASYNC_DONE) {
759 handle->state = LDB_ASYNC_DONE;
764 static int partition_wait_all(struct ldb_handle *handle) {
768 while (handle->state != LDB_ASYNC_DONE) {
769 ret = partition_wait_none(handle);
770 if (ret != LDB_SUCCESS) {
775 return handle->status;
778 static int partition_wait(struct ldb_handle *handle, enum ldb_wait_type type)
780 if (type == LDB_WAIT_ALL) {
781 return partition_wait_all(handle);
783 return partition_wait_none(handle);
787 static const struct ldb_module_ops partition_ops = {
789 .init_context = partition_init,
790 .search = partition_search,
791 .add = partition_add,
792 .modify = partition_modify,
793 .del = partition_delete,
794 .rename = partition_rename,
795 .start_transaction = partition_start_trans,
796 .end_transaction = partition_end_trans,
797 .del_transaction = partition_del_trans,
798 .sequence_number = partition_sequence_number,
799 .wait = partition_wait
802 int ldb_partition_init(void)
804 return ldb_register_module(&partition_ops);