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
33 #include "lib/ldb/include/ldb.h"
34 #include "lib/ldb/include/ldb_errors.h"
35 #include "lib/ldb/include/ldb_module.h"
36 #include "lib/ldb/include/ldb_private.h"
37 #include "dsdb/samdb/samdb.h"
39 struct dsdb_partition {
40 struct ldb_module *module;
41 struct dsdb_control_current_partition *ctrl;
44 struct partition_private_data {
45 struct dsdb_partition **partitions;
46 struct ldb_dn **replicate;
50 struct ldb_module *module;
51 struct ldb_request *req;
54 struct partition_context {
55 struct ldb_module *module;
56 struct ldb_request *req;
59 struct part_request *part_req;
61 int finished_requests;
64 static struct partition_context *partition_init_ctx(struct ldb_module *module, struct ldb_request *req)
66 struct partition_context *ac;
68 ac = talloc_zero(req, struct partition_context);
70 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
80 #define PARTITION_FIND_OP_NOERROR(module, op) do { \
81 while (module && module->ops->op == NULL) module = module->next; \
84 #define PARTITION_FIND_OP(module, op) do { \
85 PARTITION_FIND_OP_NOERROR(module, op); \
86 if (module == NULL) { \
87 ldb_asprintf_errstring(ldb_module_get_ctx(module), \
88 "Unable to find backend operation for " #op ); \
89 return LDB_ERR_OPERATIONS_ERROR; \
94 * helper functions to call the next module in chain
97 static int partition_request(struct ldb_module *module, struct ldb_request *request)
100 switch (request->operation) {
102 PARTITION_FIND_OP(module, search);
103 ret = module->ops->search(module, request);
106 PARTITION_FIND_OP(module, add);
107 ret = module->ops->add(module, request);
110 PARTITION_FIND_OP(module, modify);
111 ret = module->ops->modify(module, request);
114 PARTITION_FIND_OP(module, del);
115 ret = module->ops->del(module, request);
118 PARTITION_FIND_OP(module, rename);
119 ret = module->ops->rename(module, request);
122 PARTITION_FIND_OP(module, extended);
123 ret = module->ops->extended(module, request);
126 PARTITION_FIND_OP(module, request);
127 ret = module->ops->request(module, request);
130 if (ret == LDB_SUCCESS) {
133 if (!ldb_errstring(ldb_module_get_ctx(module))) {
134 /* Set a default error string, to place the blame somewhere */
135 ldb_asprintf_errstring(ldb_module_get_ctx(module),
136 "error in module %s: %s (%d)",
138 ldb_strerror(ret), ret);
143 static struct dsdb_partition *find_partition(struct partition_private_data *data,
145 struct ldb_request *req)
148 struct ldb_control *partition_ctrl;
150 /* see if the request has the partition DN specified in a
151 * control. The repl_meta_data module can specify this to
152 * ensure that replication happens to the right partition
154 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
155 if (partition_ctrl) {
156 const struct dsdb_control_current_partition *partition;
157 partition = talloc_get_type(partition_ctrl->data,
158 struct dsdb_control_current_partition);
159 if (partition != NULL) {
164 /* Look at base DN */
165 /* Figure out which partition it is under */
166 /* Skip the lot if 'data' isn't here yet (initialisation) */
167 for (i=0; data && data->partitions && data->partitions[i]; i++) {
168 if (ldb_dn_compare_base(data->partitions[i]->ctrl->dn, dn) == 0) {
169 return data->partitions[i];
177 * fire the caller's callback for every entry, but only send 'done' once.
179 static int partition_req_callback(struct ldb_request *req,
180 struct ldb_reply *ares)
182 struct partition_context *ac;
183 struct ldb_module *module;
184 struct ldb_request *nreq;
187 ac = talloc_get_type(req->context, struct partition_context);
190 return ldb_module_done(ac->req, NULL, NULL,
191 LDB_ERR_OPERATIONS_ERROR);
194 if (ares->error != LDB_SUCCESS && !ac->got_success) {
195 return ldb_module_done(ac->req, ares->controls,
196 ares->response, ares->error);
199 switch (ares->type) {
200 case LDB_REPLY_REFERRAL:
201 /* ignore referrals for now */
204 case LDB_REPLY_ENTRY:
205 if (ac->req->operation != LDB_SEARCH) {
206 ldb_set_errstring(ldb_module_get_ctx(ac->module),
207 "partition_req_callback:"
208 " Unsupported reply type for this request");
209 return ldb_module_done(ac->req, NULL, NULL,
210 LDB_ERR_OPERATIONS_ERROR);
212 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
215 if (ares->error == LDB_SUCCESS) {
216 ac->got_success = true;
218 if (ac->req->operation == LDB_EXTENDED) {
219 /* FIXME: check for ares->response, replmd does not fill it ! */
220 if (ares->response) {
221 if (strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID) != 0) {
222 ldb_set_errstring(ldb_module_get_ctx(ac->module),
223 "partition_req_callback:"
224 " Unknown extended reply, "
225 "only supports START_TLS");
227 return ldb_module_done(ac->req, NULL, NULL,
228 LDB_ERR_OPERATIONS_ERROR);
233 ac->finished_requests++;
234 if (ac->finished_requests == ac->num_requests) {
235 /* this was the last one, call callback */
236 return ldb_module_done(ac->req, ares->controls,
238 ac->got_success?LDB_SUCCESS:ares->error);
241 /* not the last, now call the next one */
242 module = ac->part_req[ac->finished_requests].module;
243 nreq = ac->part_req[ac->finished_requests].req;
245 ret = partition_request(module, nreq);
246 if (ret != LDB_SUCCESS) {
248 return ldb_module_done(ac->req, NULL, NULL, ret);
258 static int partition_prep_request(struct partition_context *ac,
259 struct dsdb_partition *partition)
262 struct ldb_request *req;
264 ac->part_req = talloc_realloc(ac, ac->part_req,
266 ac->num_requests + 1);
267 if (ac->part_req == NULL) {
268 ldb_oom(ldb_module_get_ctx(ac->module));
269 return LDB_ERR_OPERATIONS_ERROR;
272 switch (ac->req->operation) {
274 ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(ac->module),
276 ac->req->op.search.base,
277 ac->req->op.search.scope,
278 ac->req->op.search.tree,
279 ac->req->op.search.attrs,
281 ac, partition_req_callback,
285 ret = ldb_build_add_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
286 ac->req->op.add.message,
288 ac, partition_req_callback,
292 ret = ldb_build_mod_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
293 ac->req->op.mod.message,
295 ac, partition_req_callback,
299 ret = ldb_build_del_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
302 ac, partition_req_callback,
306 ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
307 ac->req->op.rename.olddn,
308 ac->req->op.rename.newdn,
310 ac, partition_req_callback,
314 ret = ldb_build_extended_req(&req, ldb_module_get_ctx(ac->module),
316 ac->req->op.extended.oid,
317 ac->req->op.extended.data,
319 ac, partition_req_callback,
323 ldb_set_errstring(ldb_module_get_ctx(ac->module),
324 "Unsupported request type!");
325 ret = LDB_ERR_UNWILLING_TO_PERFORM;
328 if (ret != LDB_SUCCESS) {
332 ac->part_req[ac->num_requests].req = req;
334 if (ac->req->controls) {
335 req->controls = talloc_memdup(req, ac->req->controls,
336 talloc_get_size(ac->req->controls));
337 if (req->controls == NULL) {
338 ldb_oom(ldb_module_get_ctx(ac->module));
339 return LDB_ERR_OPERATIONS_ERROR;
344 ac->part_req[ac->num_requests].module = partition->module;
346 if (!ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
347 ret = ldb_request_add_control(req,
348 DSDB_CONTROL_CURRENT_PARTITION_OID,
349 false, partition->ctrl);
350 if (ret != LDB_SUCCESS) {
355 if (req->operation == LDB_SEARCH) {
356 /* If the search is for 'more' than this partition,
357 * then change the basedn, so a remote LDAP server
359 if (ldb_dn_compare_base(partition->ctrl->dn,
360 req->op.search.base) != 0) {
361 req->op.search.base = partition->ctrl->dn;
366 /* make sure you put the NEXT module here, or
367 * partition_request() will simply loop forever on itself */
368 ac->part_req[ac->num_requests].module = ac->module->next;
376 static int partition_call_first(struct partition_context *ac)
378 return partition_request(ac->part_req[0].module, ac->part_req[0].req);
382 * Send a request down to all the partitions
384 static int partition_send_all(struct ldb_module *module,
385 struct partition_context *ac,
386 struct ldb_request *req)
389 struct partition_private_data *data = talloc_get_type(module->private_data,
390 struct partition_private_data);
391 int ret = partition_prep_request(ac, NULL);
392 if (ret != LDB_SUCCESS) {
395 for (i=0; data && data->partitions && data->partitions[i]; i++) {
396 ret = partition_prep_request(ac, data->partitions[i]);
397 if (ret != LDB_SUCCESS) {
402 /* fire the first one */
403 return partition_call_first(ac);
407 * Figure out which backend a request needs to be aimed at. Some
408 * requests must be replicated to all backends
410 static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
412 struct partition_context *ac;
415 struct dsdb_partition *partition;
416 struct partition_private_data *data = talloc_get_type(module->private_data,
417 struct partition_private_data);
418 if (!data || !data->partitions) {
419 return ldb_next_request(module, req);
422 if (req->operation != LDB_SEARCH) {
423 /* Is this a special DN, we need to replicate to every backend? */
424 for (i=0; data->replicate && data->replicate[i]; i++) {
425 if (ldb_dn_compare(data->replicate[i],
428 ac = partition_init_ctx(module, req);
430 return LDB_ERR_OPERATIONS_ERROR;
433 return partition_send_all(module, ac, req);
438 /* Otherwise, we need to find the partition to fire it to */
441 partition = find_partition(data, dn, req);
444 * if we haven't found a matching partition
445 * pass the request to the main ldb
447 * TODO: we should maybe return an error here
448 * if it's not a special dn
451 return ldb_next_request(module, req);
454 ac = partition_init_ctx(module, req);
456 return LDB_ERR_OPERATIONS_ERROR;
459 /* we need to add a control but we never touch the original request */
460 ret = partition_prep_request(ac, partition);
461 if (ret != LDB_SUCCESS) {
465 /* fire the first one */
466 return partition_call_first(ac);
470 static int partition_search(struct ldb_module *module, struct ldb_request *req)
472 struct ldb_control **saved_controls;
475 struct partition_private_data *data = talloc_get_type(module->private_data,
476 struct partition_private_data);
479 /* (later) consider if we should be searching multiple
480 * partitions (for 'invisible' partition behaviour */
482 struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
483 struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);
485 struct ldb_search_options_control *search_options = NULL;
486 if (search_control) {
487 search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);
490 /* Remove the domain_scope control, so we don't confuse a backend server */
491 if (domain_scope_control && !save_controls(domain_scope_control, req, &saved_controls)) {
492 ldb_oom(ldb_module_get_ctx(module));
493 return LDB_ERR_OPERATIONS_ERROR;
497 * for now pass down the LDB_CONTROL_SEARCH_OPTIONS_OID control
498 * down as uncritical to make windows 2008 dcpromo happy.
500 if (search_control) {
501 search_control->critical = 0;
505 Generate referrals (look for a partition under this DN) if we don't have the above control specified
508 if (search_options && (search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
510 struct partition_context *ac;
511 if ((search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
512 /* We have processed this flag, so we are done with this control now */
514 /* Remove search control, so we don't confuse a backend server */
515 if (search_control && !save_controls(search_control, req, &saved_controls)) {
516 ldb_oom(ldb_module_get_ctx(module));
517 return LDB_ERR_OPERATIONS_ERROR;
520 ac = partition_init_ctx(module, req);
522 return LDB_ERR_OPERATIONS_ERROR;
525 /* Search from the base DN */
526 if (!req->op.search.base || ldb_dn_is_null(req->op.search.base)) {
527 return partition_send_all(module, ac, req);
529 for (i=0; data && data->partitions && data->partitions[i]; i++) {
530 bool match = false, stop = false;
531 /* Find all partitions under the search base
535 1) the DN we are looking for exactly matches the partition
537 2) the DN we are looking for is a parent of the partition and it isn't
540 3) the DN we are looking for is a child of the partition
542 if (ldb_dn_compare(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) {
544 if (req->op.search.scope == LDB_SCOPE_BASE) {
549 (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->ctrl->dn) == 0 &&
550 req->op.search.scope != LDB_SCOPE_BASE)) {
554 ldb_dn_compare_base(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) {
556 stop = true; /* note that this relies on partition ordering */
559 ret = partition_prep_request(ac, data->partitions[i]);
560 if (ret != LDB_SUCCESS) {
567 /* Perhaps we didn't match any partitions. Try the main partition, only */
568 if (ac->num_requests == 0) {
570 return ldb_next_request(module, req);
573 /* fire the first one */
574 return partition_call_first(ac);
577 /* Handle this like all other requests */
578 if (search_control && (search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
579 /* We have processed this flag, so we are done with this control now */
581 /* Remove search control, so we don't confuse a backend server */
582 if (search_control && !save_controls(search_control, req, &saved_controls)) {
583 ldb_oom(ldb_module_get_ctx(module));
584 return LDB_ERR_OPERATIONS_ERROR;
588 return partition_replicate(module, req, req->op.search.base);
593 static int partition_add(struct ldb_module *module, struct ldb_request *req)
595 return partition_replicate(module, req, req->op.add.message->dn);
599 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
601 return partition_replicate(module, req, req->op.mod.message->dn);
605 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
607 return partition_replicate(module, req, req->op.del.dn);
611 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
614 struct dsdb_partition *backend, *backend2;
616 struct partition_private_data *data = talloc_get_type(module->private_data,
617 struct partition_private_data);
619 /* Skip the lot if 'data' isn't here yet (initialisation) */
621 return LDB_ERR_OPERATIONS_ERROR;
624 backend = find_partition(data, req->op.rename.olddn, req);
625 backend2 = find_partition(data, req->op.rename.newdn, req);
627 if ((backend && !backend2) || (!backend && backend2)) {
628 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
631 if (backend != backend2) {
632 ldb_asprintf_errstring(ldb_module_get_ctx(module),
633 "Cannot rename from %s in %s to %s in %s: %s",
634 ldb_dn_get_linearized(req->op.rename.olddn),
635 ldb_dn_get_linearized(backend->ctrl->dn),
636 ldb_dn_get_linearized(req->op.rename.newdn),
637 ldb_dn_get_linearized(backend2->ctrl->dn),
638 ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));
639 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
642 return partition_replicate(module, req, req->op.rename.olddn);
645 /* start a transaction */
646 static int partition_start_trans(struct ldb_module *module)
649 struct partition_private_data *data = talloc_get_type(module->private_data,
650 struct partition_private_data);
651 /* Look at base DN */
652 /* Figure out which partition it is under */
653 /* Skip the lot if 'data' isn't here yet (initialization) */
654 ret = ldb_next_start_trans(module);
655 if (ret != LDB_SUCCESS) {
659 for (i=0; data && data->partitions && data->partitions[i]; i++) {
660 struct ldb_module *next = data->partitions[i]->module;
661 PARTITION_FIND_OP(next, start_transaction);
663 ret = next->ops->start_transaction(next);
664 if (ret != LDB_SUCCESS) {
665 /* Back it out, if it fails on one */
666 for (i--; i >= 0; i--) {
667 next = data->partitions[i]->module;
668 PARTITION_FIND_OP(next, del_transaction);
670 next->ops->del_transaction(next);
672 ldb_next_del_trans(module);
679 /* prepare for a commit */
680 static int partition_prepare_commit(struct ldb_module *module)
683 struct partition_private_data *data = talloc_get_type(module->private_data,
684 struct partition_private_data);
686 for (i=0; data && data->partitions && data->partitions[i]; i++) {
687 struct ldb_module *next_prepare = data->partitions[i]->module;
690 PARTITION_FIND_OP_NOERROR(next_prepare, prepare_commit);
691 if (next_prepare == NULL) {
695 ret = next_prepare->ops->prepare_commit(next_prepare);
696 if (ret != LDB_SUCCESS) {
701 return ldb_next_prepare_commit(module);
705 /* end a transaction */
706 static int partition_end_trans(struct ldb_module *module)
709 struct partition_private_data *data = talloc_get_type(module->private_data,
710 struct partition_private_data);
711 for (i=0; data && data->partitions && data->partitions[i]; i++) {
712 struct ldb_module *next_end = data->partitions[i]->module;
715 PARTITION_FIND_OP(next_end, end_transaction);
717 ret = next_end->ops->end_transaction(next_end);
718 if (ret != LDB_SUCCESS) {
723 return ldb_next_end_trans(module);
726 /* delete a transaction */
727 static int partition_del_trans(struct ldb_module *module)
729 int i, ret, final_ret = LDB_SUCCESS;
730 struct partition_private_data *data = talloc_get_type(module->private_data,
731 struct partition_private_data);
732 for (i=0; data && data->partitions && data->partitions[i]; i++) {
733 struct ldb_module *next = data->partitions[i]->module;
734 PARTITION_FIND_OP(next, del_transaction);
736 ret = next->ops->del_transaction(next);
737 if (ret != LDB_SUCCESS) {
742 ret = ldb_next_del_trans(module);
743 if (ret != LDB_SUCCESS) {
750 /* FIXME: This function is still semi-async */
751 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
754 uint64_t seq_number = 0;
755 uint64_t timestamp_sequence = 0;
756 uint64_t timestamp = 0;
757 struct partition_private_data *data = talloc_get_type(module->private_data,
758 struct partition_private_data);
759 struct ldb_seqnum_request *seq;
760 struct ldb_seqnum_result *seqr;
761 struct ldb_request *treq;
762 struct ldb_seqnum_request *tseq;
763 struct ldb_seqnum_result *tseqr;
764 struct ldb_extended *ext;
765 struct ldb_result *res;
766 struct dsdb_partition *p;
768 p = find_partition(NULL, NULL, req);
770 /* the caller specified what partition they want the
771 * sequence number operation on - just pass it on
773 return ldb_next_request(p->module, req);
776 seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
780 case LDB_SEQ_HIGHEST_SEQ:
781 res = talloc_zero(req, struct ldb_result);
783 return LDB_ERR_OPERATIONS_ERROR;
785 tseq = talloc_zero(res, struct ldb_seqnum_request);
788 return LDB_ERR_OPERATIONS_ERROR;
790 tseq->type = seq->type;
792 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
793 LDB_EXTENDED_SEQUENCE_NUMBER,
797 ldb_extended_default_callback,
799 ret = ldb_next_request(module, treq);
800 if (ret == LDB_SUCCESS) {
801 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
803 if (ret != LDB_SUCCESS) {
807 seqr = talloc_get_type(res->extended->data,
808 struct ldb_seqnum_result);
809 if (seqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
810 timestamp_sequence = seqr->seq_num;
812 seq_number += seqr->seq_num;
816 /* Skip the lot if 'data' isn't here yet (initialisation) */
817 for (i=0; data && data->partitions && data->partitions[i]; i++) {
819 res = talloc_zero(req, struct ldb_result);
821 return LDB_ERR_OPERATIONS_ERROR;
823 tseq = talloc_zero(res, struct ldb_seqnum_request);
826 return LDB_ERR_OPERATIONS_ERROR;
828 tseq->type = seq->type;
830 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
831 LDB_EXTENDED_SEQUENCE_NUMBER,
835 ldb_extended_default_callback,
837 if (ret != LDB_SUCCESS) {
842 if (!ldb_request_get_control(treq, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
843 ret = ldb_request_add_control(treq,
844 DSDB_CONTROL_CURRENT_PARTITION_OID,
845 false, data->partitions[i]->ctrl);
846 if (ret != LDB_SUCCESS) {
852 ret = partition_request(data->partitions[i]->module, treq);
853 if (ret != LDB_SUCCESS) {
857 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
858 if (ret != LDB_SUCCESS) {
862 tseqr = talloc_get_type(res->extended->data,
863 struct ldb_seqnum_result);
864 if (tseqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
865 timestamp_sequence = MAX(timestamp_sequence,
868 seq_number += tseqr->seq_num;
873 case LDB_SEQ_HIGHEST_TIMESTAMP:
875 res = talloc_zero(req, struct ldb_result);
877 return LDB_ERR_OPERATIONS_ERROR;
880 tseq = talloc_zero(res, struct ldb_seqnum_request);
883 return LDB_ERR_OPERATIONS_ERROR;
885 tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
887 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
888 LDB_EXTENDED_SEQUENCE_NUMBER,
892 ldb_extended_default_callback,
894 if (ret != LDB_SUCCESS) {
899 ret = ldb_next_request(module, treq);
900 if (ret != LDB_SUCCESS) {
904 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
905 if (ret != LDB_SUCCESS) {
910 tseqr = talloc_get_type(res->extended->data,
911 struct ldb_seqnum_result);
912 timestamp = tseqr->seq_num;
916 /* Skip the lot if 'data' isn't here yet (initialisation) */
917 for (i=0; data && data->partitions && data->partitions[i]; i++) {
919 res = talloc_zero(req, struct ldb_result);
921 return LDB_ERR_OPERATIONS_ERROR;
924 tseq = talloc_zero(res, struct ldb_seqnum_request);
927 return LDB_ERR_OPERATIONS_ERROR;
929 tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
931 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
932 LDB_EXTENDED_SEQUENCE_NUMBER,
936 ldb_extended_default_callback,
938 if (ret != LDB_SUCCESS) {
943 if (!ldb_request_get_control(treq, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
944 ret = ldb_request_add_control(treq,
945 DSDB_CONTROL_CURRENT_PARTITION_OID,
946 false, data->partitions[i]->ctrl);
947 if (ret != LDB_SUCCESS) {
953 ret = partition_request(data->partitions[i]->module, treq);
954 if (ret != LDB_SUCCESS) {
958 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
959 if (ret != LDB_SUCCESS) {
964 tseqr = talloc_get_type(res->extended->data,
965 struct ldb_seqnum_result);
966 timestamp = MAX(timestamp, tseqr->seq_num);
974 ext = talloc_zero(req, struct ldb_extended);
976 return LDB_ERR_OPERATIONS_ERROR;
978 seqr = talloc_zero(ext, struct ldb_seqnum_result);
981 return LDB_ERR_OPERATIONS_ERROR;
983 ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
988 case LDB_SEQ_HIGHEST_SEQ:
990 /* Has someone above set a timebase sequence? */
991 if (timestamp_sequence) {
992 seqr->seq_num = (((unsigned long long)timestamp << 24) | (seq_number & 0xFFFFFF));
994 seqr->seq_num = seq_number;
997 if (timestamp_sequence > seqr->seq_num) {
998 seqr->seq_num = timestamp_sequence;
999 seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
1002 seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
1004 case LDB_SEQ_HIGHEST_TIMESTAMP:
1005 seqr->seq_num = timestamp;
1009 if (seq->type == LDB_SEQ_NEXT) {
1013 /* send request done */
1014 return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
1017 static int partition_extended_schema_update_now(struct ldb_module *module, struct ldb_request *req)
1019 struct dsdb_partition *partition;
1020 struct partition_private_data *data;
1021 struct ldb_dn *schema_dn;
1022 struct partition_context *ac;
1025 schema_dn = talloc_get_type(req->op.extended.data, struct ldb_dn);
1027 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_FATAL, "partition_extended: invalid extended data\n");
1028 return LDB_ERR_PROTOCOL_ERROR;
1031 data = talloc_get_type(module->private_data, struct partition_private_data);
1033 return LDB_ERR_OPERATIONS_ERROR;
1036 partition = find_partition( data, schema_dn, req);
1038 return ldb_next_request(module, req);
1041 ac = partition_init_ctx(module, req);
1043 return LDB_ERR_OPERATIONS_ERROR;
1046 /* we need to add a control but we never touch the original request */
1047 ret = partition_prep_request(ac, partition);
1048 if (ret != LDB_SUCCESS) {
1052 /* fire the first one */
1053 ret = partition_call_first(ac);
1055 if (ret != LDB_SUCCESS){
1059 return ldb_request_done(req, ret);
1064 static int partition_extended(struct ldb_module *module, struct ldb_request *req)
1066 struct partition_private_data *data;
1067 struct partition_context *ac;
1069 data = talloc_get_type(module->private_data, struct partition_private_data);
1070 if (!data || !data->partitions) {
1071 return ldb_next_request(module, req);
1074 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1075 return partition_sequence_number(module, req);
1078 /* forward schemaUpdateNow operation to schema_fsmo module*/
1079 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) == 0) {
1080 return partition_extended_schema_update_now( module, req );
1084 * as the extended operation has no dn
1085 * we need to send it to all partitions
1088 ac = partition_init_ctx(module, req);
1090 return LDB_ERR_OPERATIONS_ERROR;
1093 return partition_send_all(module, ac, req);
1096 static int partition_sort_compare(const void *v1, const void *v2)
1098 const struct dsdb_partition *p1;
1099 const struct dsdb_partition *p2;
1101 p1 = *((struct dsdb_partition * const*)v1);
1102 p2 = *((struct dsdb_partition * const*)v2);
1104 return ldb_dn_compare(p1->ctrl->dn, p2->ctrl->dn);
1107 static int partition_init(struct ldb_module *module)
1110 TALLOC_CTX *mem_ctx = talloc_new(module);
1111 const char *attrs[] = { "partition", "replicateEntries", "modules", NULL };
1112 struct ldb_result *res;
1113 struct ldb_message *msg;
1114 struct ldb_message_element *partition_attributes;
1115 struct ldb_message_element *replicate_attributes;
1116 struct ldb_message_element *modules_attributes;
1118 struct partition_private_data *data;
1121 return LDB_ERR_OPERATIONS_ERROR;
1124 data = talloc(mem_ctx, struct partition_private_data);
1126 return LDB_ERR_OPERATIONS_ERROR;
1129 ret = ldb_search(ldb_module_get_ctx(module), mem_ctx, &res,
1130 ldb_dn_new(mem_ctx, ldb_module_get_ctx(module), "@PARTITION"),
1131 LDB_SCOPE_BASE, attrs, NULL);
1132 if (ret != LDB_SUCCESS) {
1133 talloc_free(mem_ctx);
1136 if (res->count == 0) {
1137 talloc_free(mem_ctx);
1138 return ldb_next_init(module);
1141 if (res->count > 1) {
1142 talloc_free(mem_ctx);
1143 return LDB_ERR_CONSTRAINT_VIOLATION;
1148 partition_attributes = ldb_msg_find_element(msg, "partition");
1149 if (!partition_attributes) {
1150 ldb_set_errstring(ldb_module_get_ctx(module), "partition_init: no partitions specified");
1151 talloc_free(mem_ctx);
1152 return LDB_ERR_CONSTRAINT_VIOLATION;
1154 data->partitions = talloc_array(data, struct dsdb_partition *, partition_attributes->num_values + 1);
1155 if (!data->partitions) {
1156 talloc_free(mem_ctx);
1157 return LDB_ERR_OPERATIONS_ERROR;
1159 for (i=0; i < partition_attributes->num_values; i++) {
1160 char *base = talloc_strdup(data->partitions, (char *)partition_attributes->values[i].data);
1161 char *p = strchr(base, ':');
1162 const char *backend;
1165 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1167 "invalid form for partition record (missing ':'): %s", base);
1168 talloc_free(mem_ctx);
1169 return LDB_ERR_CONSTRAINT_VIOLATION;
1174 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1176 "invalid form for partition record (missing backend database): %s", base);
1177 talloc_free(mem_ctx);
1178 return LDB_ERR_CONSTRAINT_VIOLATION;
1180 data->partitions[i] = talloc(data->partitions, struct dsdb_partition);
1181 if (!data->partitions[i]) {
1182 talloc_free(mem_ctx);
1183 return LDB_ERR_OPERATIONS_ERROR;
1185 data->partitions[i]->ctrl = talloc(data->partitions[i], struct dsdb_control_current_partition);
1186 if (!data->partitions[i]->ctrl) {
1187 talloc_free(mem_ctx);
1188 return LDB_ERR_OPERATIONS_ERROR;
1190 data->partitions[i]->ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
1191 data->partitions[i]->ctrl->dn = ldb_dn_new(data->partitions[i], ldb_module_get_ctx(module), base);
1192 if (!data->partitions[i]->ctrl->dn) {
1193 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1194 "partition_init: invalid DN in partition record: %s", base);
1195 talloc_free(mem_ctx);
1196 return LDB_ERR_CONSTRAINT_VIOLATION;
1199 backend = samdb_relative_path(ldb_module_get_ctx(module),
1200 data->partitions[i],
1203 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1204 "partition_init: unable to determine an relative path for partition: %s", base);
1205 talloc_free(mem_ctx);
1207 ret = ldb_connect_backend(ldb_module_get_ctx(module), backend, NULL, &data->partitions[i]->module);
1208 if (ret != LDB_SUCCESS) {
1209 talloc_free(mem_ctx);
1213 data->partitions[i] = NULL;
1215 /* sort these into order, most to least specific */
1216 qsort(data->partitions, partition_attributes->num_values,
1217 sizeof(*data->partitions), partition_sort_compare);
1219 for (i=0; data->partitions[i]; i++) {
1220 struct ldb_request *req;
1221 req = talloc_zero(mem_ctx, struct ldb_request);
1223 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Out of memory!\n");
1224 talloc_free(mem_ctx);
1225 return LDB_ERR_OPERATIONS_ERROR;
1228 req->operation = LDB_REQ_REGISTER_PARTITION;
1229 req->op.reg_partition.dn = data->partitions[i]->ctrl->dn;
1230 req->callback = ldb_op_default_callback;
1232 ldb_set_timeout(ldb_module_get_ctx(module), req, 0);
1234 req->handle = ldb_handle_new(req, ldb_module_get_ctx(module));
1235 if (req->handle == NULL) {
1236 return LDB_ERR_OPERATIONS_ERROR;
1239 ret = ldb_request(ldb_module_get_ctx(module), req);
1240 if (ret == LDB_SUCCESS) {
1241 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
1243 if (ret != LDB_SUCCESS) {
1244 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
1245 talloc_free(mem_ctx);
1246 return LDB_ERR_OTHER;
1251 replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
1252 if (!replicate_attributes) {
1253 data->replicate = NULL;
1255 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
1256 if (!data->replicate) {
1257 talloc_free(mem_ctx);
1258 return LDB_ERR_OPERATIONS_ERROR;
1261 for (i=0; i < replicate_attributes->num_values; i++) {
1262 data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb_module_get_ctx(module), &replicate_attributes->values[i]);
1263 if (!ldb_dn_validate(data->replicate[i])) {
1264 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1266 "invalid DN in partition replicate record: %s",
1267 replicate_attributes->values[i].data);
1268 talloc_free(mem_ctx);
1269 return LDB_ERR_CONSTRAINT_VIOLATION;
1272 data->replicate[i] = NULL;
1275 /* Make the private data available to any searches the modules may trigger in initialisation */
1276 module->private_data = data;
1277 talloc_steal(module, data);
1279 modules_attributes = ldb_msg_find_element(msg, "modules");
1280 if (modules_attributes) {
1281 for (i=0; i < modules_attributes->num_values; i++) {
1282 struct ldb_dn *base_dn;
1284 struct dsdb_partition *partition = NULL;
1285 const char **modules = NULL;
1287 char *base = talloc_strdup(data->partitions, (char *)modules_attributes->values[i].data);
1288 char *p = strchr(base, ':');
1290 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1292 "invalid form for partition module record (missing ':'): %s", base);
1293 talloc_free(mem_ctx);
1294 return LDB_ERR_CONSTRAINT_VIOLATION;
1299 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1301 "invalid form for partition module record (missing backend database): %s", base);
1302 talloc_free(mem_ctx);
1303 return LDB_ERR_CONSTRAINT_VIOLATION;
1306 modules = ldb_modules_list_from_string(ldb_module_get_ctx(module), mem_ctx,
1309 base_dn = ldb_dn_new(mem_ctx, ldb_module_get_ctx(module), base);
1310 if (!ldb_dn_validate(base_dn)) {
1311 talloc_free(mem_ctx);
1312 return LDB_ERR_OPERATIONS_ERROR;
1315 for (partition_idx = 0; data->partitions[partition_idx]; partition_idx++) {
1316 if (ldb_dn_compare(data->partitions[partition_idx]->ctrl->dn, base_dn) == 0) {
1317 partition = data->partitions[partition_idx];
1323 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1325 "invalid form for partition module record (no such partition): %s", base);
1326 talloc_free(mem_ctx);
1327 return LDB_ERR_CONSTRAINT_VIOLATION;
1330 ret = ldb_load_modules_list(ldb_module_get_ctx(module), modules, partition->module, &partition->module);
1331 if (ret != LDB_SUCCESS) {
1332 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1334 "loading backend for %s failed: %s",
1335 base, ldb_errstring(ldb_module_get_ctx(module)));
1336 talloc_free(mem_ctx);
1339 ret = ldb_init_module_chain(ldb_module_get_ctx(module), partition->module);
1340 if (ret != LDB_SUCCESS) {
1341 ldb_asprintf_errstring(ldb_module_get_ctx(module),
1343 "initialising backend for %s failed: %s",
1344 base, ldb_errstring(ldb_module_get_ctx(module)));
1345 talloc_free(mem_ctx);
1351 ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
1352 if (ret != LDB_SUCCESS) {
1353 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1354 "partition: Unable to register control with rootdse!\n");
1355 return LDB_ERR_OPERATIONS_ERROR;
1358 ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
1359 if (ret != LDB_SUCCESS) {
1360 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR,
1361 "partition: Unable to register control with rootdse!\n");
1362 return LDB_ERR_OPERATIONS_ERROR;
1365 talloc_free(mem_ctx);
1366 return ldb_next_init(module);
1369 _PUBLIC_ const struct ldb_module_ops ldb_partition_module_ops = {
1370 .name = "partition",
1371 .init_context = partition_init,
1372 .search = partition_search,
1373 .add = partition_add,
1374 .modify = partition_modify,
1375 .del = partition_delete,
1376 .rename = partition_rename,
1377 .extended = partition_extended,
1378 .start_transaction = partition_start_trans,
1379 .prepare_commit = partition_prepare_commit,
1380 .end_transaction = partition_end_trans,
1381 .del_transaction = partition_del_trans,