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"
35 struct ldb_module *module;
36 struct ldb_request *req;
39 struct partition_context {
40 struct ldb_module *module;
41 struct ldb_request *req;
43 struct part_request *part_req;
45 int finished_requests;
48 static struct partition_context *partition_init_ctx(struct ldb_module *module, struct ldb_request *req)
50 struct partition_context *ac;
52 ac = talloc_zero(req, struct partition_context);
54 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
65 * helper functions to call the next module in chain
68 int partition_request(struct ldb_module *module, struct ldb_request *request)
70 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) { \
71 const struct dsdb_control_current_partition *partition = NULL;
72 struct ldb_control *partition_ctrl = ldb_request_get_control(request, DSDB_CONTROL_CURRENT_PARTITION_OID);
74 partition = talloc_get_type(partition_ctrl->data,
75 struct dsdb_control_current_partition);
78 if (partition != NULL) {
79 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_request() -> %s",
80 ldb_dn_get_linearized(partition->dn));
82 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_request() -> (metadata partition)");
86 return ldb_next_request(module, request);
89 static struct dsdb_partition *find_partition(struct partition_private_data *data,
91 struct ldb_request *req)
94 struct ldb_control *partition_ctrl;
96 /* see if the request has the partition DN specified in a
97 * control. The repl_meta_data module can specify this to
98 * ensure that replication happens to the right partition
100 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
101 if (partition_ctrl) {
102 const struct dsdb_control_current_partition *partition;
103 partition = talloc_get_type(partition_ctrl->data,
104 struct dsdb_control_current_partition);
105 if (partition != NULL) {
114 /* Look at base DN */
115 /* Figure out which partition it is under */
116 /* Skip the lot if 'data' isn't here yet (initialisation) */
117 for (i=0; data && data->partitions && data->partitions[i]; i++) {
118 if (ldb_dn_compare_base(data->partitions[i]->ctrl->dn, dn) == 0) {
119 return data->partitions[i];
127 * fire the caller's callback for every entry, but only send 'done' once.
129 static int partition_req_callback(struct ldb_request *req,
130 struct ldb_reply *ares)
132 struct partition_context *ac;
133 struct ldb_module *module;
134 struct ldb_request *nreq;
136 struct partition_private_data *data;
137 struct ldb_control *partition_ctrl;
139 ac = talloc_get_type(req->context, struct partition_context);
140 data = talloc_get_type(ac->module->private_data, struct partition_private_data);
143 return ldb_module_done(ac->req, NULL, NULL,
144 LDB_ERR_OPERATIONS_ERROR);
147 partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
148 if (partition_ctrl && (ac->num_requests == 1 || ares->type == LDB_REPLY_ENTRY)) {
149 /* If we didn't fan this request out to mulitple partitions,
150 * or this is an individual search result, we can
151 * deterministily tell the caller what partition this was
152 * written to (repl_meta_data likes to know) */
153 ret = ldb_reply_add_control(ares,
154 DSDB_CONTROL_CURRENT_PARTITION_OID,
155 false, partition_ctrl->data);
156 if (ret != LDB_SUCCESS) {
157 return ldb_module_done(ac->req, NULL, NULL,
162 if (ares->error != LDB_SUCCESS) {
163 return ldb_module_done(ac->req, ares->controls,
164 ares->response, ares->error);
167 switch (ares->type) {
168 case LDB_REPLY_REFERRAL:
169 /* ignore referrals for now */
172 case LDB_REPLY_ENTRY:
173 if (ac->req->operation != LDB_SEARCH) {
174 ldb_set_errstring(ldb_module_get_ctx(ac->module),
175 "partition_req_callback:"
176 " Unsupported reply type for this request");
177 return ldb_module_done(ac->req, NULL, NULL,
178 LDB_ERR_OPERATIONS_ERROR);
181 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
184 if (ac->req->operation == LDB_EXTENDED) {
185 /* FIXME: check for ares->response, replmd does not fill it ! */
186 if (ares->response) {
187 if (strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID) != 0) {
188 ldb_set_errstring(ldb_module_get_ctx(ac->module),
189 "partition_req_callback:"
190 " Unknown extended reply, "
191 "only supports START_TLS");
193 return ldb_module_done(ac->req, NULL, NULL,
194 LDB_ERR_OPERATIONS_ERROR);
199 ac->finished_requests++;
200 if (ac->finished_requests == ac->num_requests) {
201 /* this was the last one, call callback */
202 return ldb_module_done(ac->req, ares->controls,
207 /* not the last, now call the next one */
208 module = ac->part_req[ac->finished_requests].module;
209 nreq = ac->part_req[ac->finished_requests].req;
211 ret = partition_request(module, nreq);
212 if (ret != LDB_SUCCESS) {
214 return ldb_module_done(ac->req, NULL, NULL, ret);
224 static int partition_prep_request(struct partition_context *ac,
225 struct dsdb_partition *partition)
228 struct ldb_request *req;
230 ac->part_req = talloc_realloc(ac, ac->part_req,
232 ac->num_requests + 1);
233 if (ac->part_req == NULL) {
234 ldb_oom(ldb_module_get_ctx(ac->module));
235 return LDB_ERR_OPERATIONS_ERROR;
238 switch (ac->req->operation) {
240 ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(ac->module),
242 ac->req->op.search.base,
243 ac->req->op.search.scope,
244 ac->req->op.search.tree,
245 ac->req->op.search.attrs,
247 ac, partition_req_callback,
251 ret = ldb_build_add_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
252 ac->req->op.add.message,
254 ac, partition_req_callback,
258 ret = ldb_build_mod_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
259 ac->req->op.mod.message,
261 ac, partition_req_callback,
265 ret = ldb_build_del_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
268 ac, partition_req_callback,
272 ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
273 ac->req->op.rename.olddn,
274 ac->req->op.rename.newdn,
276 ac, partition_req_callback,
280 ret = ldb_build_extended_req(&req, ldb_module_get_ctx(ac->module),
282 ac->req->op.extended.oid,
283 ac->req->op.extended.data,
285 ac, partition_req_callback,
289 ldb_set_errstring(ldb_module_get_ctx(ac->module),
290 "Unsupported request type!");
291 ret = LDB_ERR_UNWILLING_TO_PERFORM;
294 if (ret != LDB_SUCCESS) {
298 ac->part_req[ac->num_requests].req = req;
300 if (ac->req->controls) {
301 req->controls = talloc_memdup(req, ac->req->controls,
302 talloc_get_size(ac->req->controls));
303 if (req->controls == NULL) {
304 ldb_oom(ldb_module_get_ctx(ac->module));
305 return LDB_ERR_OPERATIONS_ERROR;
310 ac->part_req[ac->num_requests].module = partition->module;
312 if (!ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
313 ret = ldb_request_add_control(req,
314 DSDB_CONTROL_CURRENT_PARTITION_OID,
315 false, partition->ctrl);
316 if (ret != LDB_SUCCESS) {
321 if (req->operation == LDB_SEARCH) {
322 /* If the search is for 'more' than this partition,
323 * then change the basedn, so a remote LDAP server
325 if (ldb_dn_compare_base(partition->ctrl->dn,
326 req->op.search.base) != 0) {
327 req->op.search.base = partition->ctrl->dn;
332 /* make sure you put the module here, or
333 * or ldb_next_request() will skip a module */
334 ac->part_req[ac->num_requests].module = ac->module;
342 static int partition_call_first(struct partition_context *ac)
344 return partition_request(ac->part_req[0].module, ac->part_req[0].req);
348 * Send a request down to all the partitions
350 static int partition_send_all(struct ldb_module *module,
351 struct partition_context *ac,
352 struct ldb_request *req)
355 struct partition_private_data *data = talloc_get_type(module->private_data,
356 struct partition_private_data);
357 int ret = partition_prep_request(ac, NULL);
358 if (ret != LDB_SUCCESS) {
361 for (i=0; data && data->partitions && data->partitions[i]; i++) {
362 ret = partition_prep_request(ac, data->partitions[i]);
363 if (ret != LDB_SUCCESS) {
368 /* fire the first one */
369 return partition_call_first(ac);
373 * Figure out which backend a request needs to be aimed at. Some
374 * requests must be replicated to all backends
376 static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn)
378 struct partition_context *ac;
381 struct dsdb_partition *partition;
382 struct partition_private_data *data = talloc_get_type(module->private_data,
383 struct partition_private_data);
384 if (!data || !data->partitions) {
385 return ldb_next_request(module, req);
388 if (req->operation != LDB_SEARCH && ldb_dn_is_special(dn)) {
389 /* Is this a special DN, we need to replicate to every backend? */
390 for (i=0; data->replicate && data->replicate[i]; i++) {
391 if (ldb_dn_compare(data->replicate[i],
394 ac = partition_init_ctx(module, req);
396 return LDB_ERR_OPERATIONS_ERROR;
399 return partition_send_all(module, ac, req);
404 /* Otherwise, we need to find the partition to fire it to */
407 partition = find_partition(data, dn, req);
410 * if we haven't found a matching partition
411 * pass the request to the main ldb
413 * TODO: we should maybe return an error here
414 * if it's not a special dn
417 return ldb_next_request(module, req);
420 ac = partition_init_ctx(module, req);
422 return LDB_ERR_OPERATIONS_ERROR;
425 /* we need to add a control but we never touch the original request */
426 ret = partition_prep_request(ac, partition);
427 if (ret != LDB_SUCCESS) {
431 /* fire the first one */
432 return partition_call_first(ac);
436 static int partition_search(struct ldb_module *module, struct ldb_request *req)
439 struct ldb_control **saved_controls;
441 struct partition_private_data *data = talloc_get_type(module->private_data,
442 struct partition_private_data);
446 /* (later) consider if we should be searching multiple
447 * partitions (for 'invisible' partition behaviour */
449 struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
450 struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);
452 struct ldb_search_options_control *search_options = NULL;
453 struct dsdb_partition *p;
455 ret = partition_reload_if_required(module, data);
456 if (ret != LDB_SUCCESS) {
460 p = find_partition(data, NULL, req);
462 /* the caller specified what partition they want the
463 * search - just pass it on
465 return ldb_next_request(p->module, req);
469 if (search_control) {
470 search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);
473 /* Remove the domain_scope control, so we don't confuse a backend server */
474 if (domain_scope_control && !save_controls(domain_scope_control, req, &saved_controls)) {
475 ldb_oom(ldb_module_get_ctx(module));
476 return LDB_ERR_OPERATIONS_ERROR;
480 * for now pass down the LDB_CONTROL_SEARCH_OPTIONS_OID control
481 * down as uncritical to make windows 2008 dcpromo happy.
483 if (search_control) {
484 search_control->critical = 0;
488 Generate referrals (look for a partition under this DN) if we don't have the above control specified
491 if (search_options && (search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT)) {
493 struct partition_context *ac;
494 if ((search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
495 /* We have processed this flag, so we are done with this control now */
497 /* Remove search control, so we don't confuse a backend server */
498 if (search_control && !save_controls(search_control, req, &saved_controls)) {
499 ldb_oom(ldb_module_get_ctx(module));
500 return LDB_ERR_OPERATIONS_ERROR;
503 ac = partition_init_ctx(module, req);
505 return LDB_ERR_OPERATIONS_ERROR;
508 /* Search from the base DN */
509 if (!req->op.search.base || ldb_dn_is_null(req->op.search.base)) {
510 return partition_send_all(module, ac, req);
512 for (i=0; data && data->partitions && data->partitions[i]; i++) {
513 bool match = false, stop = false;
514 /* Find all partitions under the search base
518 1) the DN we are looking for exactly matches the partition
520 2) the DN we are looking for is a parent of the partition and it isn't
523 3) the DN we are looking for is a child of the partition
525 if (ldb_dn_compare(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) {
530 (ldb_dn_compare_base(req->op.search.base, data->partitions[i]->ctrl->dn) == 0 &&
531 req->op.search.scope != LDB_SCOPE_BASE)) {
535 ldb_dn_compare_base(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) {
537 stop = true; /* note that this relies on partition ordering */
540 ret = partition_prep_request(ac, data->partitions[i]);
541 if (ret != LDB_SUCCESS) {
548 /* Perhaps we didn't match any partitions. Try the main partition, only */
549 if (ac->num_requests == 0) {
551 return ldb_next_request(module, req);
554 /* fire the first one */
555 return partition_call_first(ac);
558 /* Handle this like all other requests */
559 if (search_control && (search_options->search_options & ~LDB_SEARCH_OPTION_PHANTOM_ROOT) == 0) {
560 /* We have processed this flag, so we are done with this control now */
562 /* Remove search control, so we don't confuse a backend server */
563 if (search_control && !save_controls(search_control, req, &saved_controls)) {
564 ldb_oom(ldb_module_get_ctx(module));
565 return LDB_ERR_OPERATIONS_ERROR;
569 return partition_replicate(module, req, req->op.search.base);
574 static int partition_add(struct ldb_module *module, struct ldb_request *req)
576 return partition_replicate(module, req, req->op.add.message->dn);
580 static int partition_modify(struct ldb_module *module, struct ldb_request *req)
582 return partition_replicate(module, req, req->op.mod.message->dn);
586 static int partition_delete(struct ldb_module *module, struct ldb_request *req)
588 return partition_replicate(module, req, req->op.del.dn);
592 static int partition_rename(struct ldb_module *module, struct ldb_request *req)
595 struct dsdb_partition *backend, *backend2;
597 struct partition_private_data *data = talloc_get_type(module->private_data,
598 struct partition_private_data);
600 /* Skip the lot if 'data' isn't here yet (initialisation) */
602 return LDB_ERR_OPERATIONS_ERROR;
605 backend = find_partition(data, req->op.rename.olddn, req);
606 backend2 = find_partition(data, req->op.rename.newdn, req);
608 if ((backend && !backend2) || (!backend && backend2)) {
609 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
612 if (backend != backend2) {
613 ldb_asprintf_errstring(ldb_module_get_ctx(module),
614 "Cannot rename from %s in %s to %s in %s: %s",
615 ldb_dn_get_linearized(req->op.rename.olddn),
616 ldb_dn_get_linearized(backend->ctrl->dn),
617 ldb_dn_get_linearized(req->op.rename.newdn),
618 ldb_dn_get_linearized(backend2->ctrl->dn),
619 ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));
620 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
623 return partition_replicate(module, req, req->op.rename.olddn);
626 /* start a transaction */
627 static int partition_start_trans(struct ldb_module *module)
630 struct partition_private_data *data = talloc_get_type(module->private_data,
631 struct partition_private_data);
632 /* Look at base DN */
633 /* Figure out which partition it is under */
634 /* Skip the lot if 'data' isn't here yet (initialization) */
635 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
636 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_start_trans() -> (metadata partition)");
638 ret = ldb_next_start_trans(module);
639 if (ret != LDB_SUCCESS) {
643 ret = partition_reload_if_required(module, data);
644 if (ret != LDB_SUCCESS) {
648 for (i=0; data && data->partitions && data->partitions[i]; i++) {
649 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
650 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_start_trans() -> %s",
651 ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
653 ret = ldb_next_start_trans(data->partitions[i]->module);
654 if (ret != LDB_SUCCESS) {
655 /* Back it out, if it fails on one */
656 for (i--; i >= 0; i--) {
657 ldb_next_del_trans(data->partitions[i]->module);
659 ldb_next_del_trans(module);
664 data->in_transaction++;
669 /* prepare for a commit */
670 static int partition_prepare_commit(struct ldb_module *module)
673 struct partition_private_data *data = talloc_get_type(module->private_data,
674 struct partition_private_data);
676 for (i=0; data && data->partitions && data->partitions[i]; i++) {
679 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
680 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_prepare_commit() -> %s",
681 ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
683 ret = ldb_next_prepare_commit(data->partitions[i]->module);
684 if (ret != LDB_SUCCESS) {
685 ldb_asprintf_errstring(module->ldb, "prepare_commit error on %s: %s", ldb_dn_get_linearized(data->partitions[i]->ctrl->dn), ldb_errstring(module->ldb));
690 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
691 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_prepare_commit() -> (metadata partition)");
693 return ldb_next_prepare_commit(module);
697 /* end a transaction */
698 static int partition_end_trans(struct ldb_module *module)
701 struct partition_private_data *data = talloc_get_type(module->private_data,
702 struct partition_private_data);
706 if (data->in_transaction == 0) {
707 DEBUG(0,("partition end transaction mismatch\n"));
708 ret = LDB_ERR_OPERATIONS_ERROR;
710 data->in_transaction--;
713 for (i=0; data && data->partitions && data->partitions[i]; i++) {
714 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
715 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_end_trans() -> %s",
716 ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
718 ret2 = ldb_next_end_trans(data->partitions[i]->module);
719 if (ret2 != LDB_SUCCESS) {
720 ldb_asprintf_errstring(module->ldb, "end_trans error on %s: %s", ldb_dn_get_linearized(data->partitions[i]->ctrl->dn), ldb_errstring(module->ldb));
725 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
726 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_end_trans() -> (metadata partition)");
728 ret2 = ldb_next_end_trans(module);
729 if (ret2 != LDB_SUCCESS) {
735 /* delete a transaction */
736 static int partition_del_trans(struct ldb_module *module)
738 int i, ret, final_ret = LDB_SUCCESS;
739 struct partition_private_data *data = talloc_get_type(module->private_data,
740 struct partition_private_data);
741 for (i=0; data && data->partitions && data->partitions[i]; i++) {
742 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
743 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_del_trans() -> %s",
744 ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
746 ret = ldb_next_del_trans(data->partitions[i]->module);
747 if (ret != LDB_SUCCESS) {
748 ldb_asprintf_errstring(module->ldb, "del_trans error on %s: %s", ldb_dn_get_linearized(data->partitions[i]->ctrl->dn), ldb_errstring(module->ldb));
753 if (data->in_transaction == 0) {
754 DEBUG(0,("partition del transaction mismatch\n"));
755 return LDB_ERR_OPERATIONS_ERROR;
757 data->in_transaction--;
759 if ((module && module->ldb->flags & LDB_FLG_ENABLE_TRACING)) {
760 ldb_debug(module->ldb, LDB_DEBUG_TRACE, "partition_del_trans() -> (metadata partition)");
762 ret = ldb_next_del_trans(module);
763 if (ret != LDB_SUCCESS) {
769 int partition_primary_sequence_number(struct ldb_module *module, TALLOC_CTX *mem_ctx,
770 enum ldb_sequence_type type, uint64_t *seq_number)
773 struct ldb_result *res;
774 struct ldb_seqnum_request *tseq;
775 struct ldb_request *treq;
776 struct ldb_seqnum_result *seqr;
777 res = talloc_zero(mem_ctx, struct ldb_result);
779 return LDB_ERR_OPERATIONS_ERROR;
781 tseq = talloc_zero(res, struct ldb_seqnum_request);
784 return LDB_ERR_OPERATIONS_ERROR;
788 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
789 LDB_EXTENDED_SEQUENCE_NUMBER,
793 ldb_extended_default_callback,
795 if (ret != LDB_SUCCESS) {
800 ret = ldb_next_request(module, treq);
801 if (ret != LDB_SUCCESS) {
805 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
806 if (ret != LDB_SUCCESS) {
811 seqr = talloc_get_type(res->extended->data,
812 struct ldb_seqnum_result);
813 if (seqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
814 ret = LDB_ERR_OPERATIONS_ERROR;
815 ldb_set_errstring(ldb_module_get_ctx(module), "Primary backend in partitions module returned a timestamp based seq number (must return a normal number)");
819 *seq_number = seqr->seq_num;
825 /* FIXME: This function is still semi-async */
826 static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
829 uint64_t seq_number = 0;
830 uint64_t timestamp_sequence = 0;
831 uint64_t timestamp = 0;
832 struct partition_private_data *data = talloc_get_type(module->private_data,
833 struct partition_private_data);
834 struct ldb_seqnum_request *seq;
835 struct ldb_seqnum_result *seqr;
836 struct ldb_request *treq;
837 struct ldb_seqnum_request *tseq;
838 struct ldb_seqnum_result *tseqr;
839 struct ldb_extended *ext;
840 struct ldb_result *res;
841 struct dsdb_partition *p;
843 p = find_partition(data, NULL, req);
845 /* the caller specified what partition they want the
846 * sequence number operation on - just pass it on
848 return ldb_next_request(p->module, req);
851 seq = talloc_get_type(req->op.extended.data, struct ldb_seqnum_request);
855 case LDB_SEQ_HIGHEST_SEQ:
857 ret = partition_primary_sequence_number(module, req, seq->type, &seq_number);
858 if (ret != LDB_SUCCESS) {
862 /* Skip the lot if 'data' isn't here yet (initialisation) */
863 for (i=0; data && data->partitions && data->partitions[i]; i++) {
865 res = talloc_zero(req, struct ldb_result);
867 return LDB_ERR_OPERATIONS_ERROR;
869 tseq = talloc_zero(res, struct ldb_seqnum_request);
872 return LDB_ERR_OPERATIONS_ERROR;
874 tseq->type = seq->type;
876 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
877 LDB_EXTENDED_SEQUENCE_NUMBER,
881 ldb_extended_default_callback,
883 if (ret != LDB_SUCCESS) {
888 if (!ldb_request_get_control(treq, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
889 ret = ldb_request_add_control(treq,
890 DSDB_CONTROL_CURRENT_PARTITION_OID,
891 false, data->partitions[i]->ctrl);
892 if (ret != LDB_SUCCESS) {
898 ret = partition_request(data->partitions[i]->module, treq);
899 if (ret != LDB_SUCCESS) {
903 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
904 if (ret != LDB_SUCCESS) {
908 tseqr = talloc_get_type(res->extended->data,
909 struct ldb_seqnum_result);
910 if (tseqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
911 timestamp_sequence = MAX(timestamp_sequence,
914 seq_number += tseqr->seq_num;
919 case LDB_SEQ_HIGHEST_TIMESTAMP:
921 res = talloc_zero(req, struct ldb_result);
923 return LDB_ERR_OPERATIONS_ERROR;
926 tseq = talloc_zero(res, struct ldb_seqnum_request);
929 return LDB_ERR_OPERATIONS_ERROR;
931 tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
933 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
934 LDB_EXTENDED_SEQUENCE_NUMBER,
938 ldb_extended_default_callback,
940 if (ret != LDB_SUCCESS) {
945 ret = ldb_next_request(module, treq);
946 if (ret != LDB_SUCCESS) {
950 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
951 if (ret != LDB_SUCCESS) {
956 tseqr = talloc_get_type(res->extended->data,
957 struct ldb_seqnum_result);
958 timestamp = tseqr->seq_num;
962 /* Skip the lot if 'data' isn't here yet (initialisation) */
963 for (i=0; data && data->partitions && data->partitions[i]; i++) {
965 res = talloc_zero(req, struct ldb_result);
967 return LDB_ERR_OPERATIONS_ERROR;
970 tseq = talloc_zero(res, struct ldb_seqnum_request);
973 return LDB_ERR_OPERATIONS_ERROR;
975 tseq->type = LDB_SEQ_HIGHEST_TIMESTAMP;
977 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
978 LDB_EXTENDED_SEQUENCE_NUMBER,
982 ldb_extended_default_callback,
984 if (ret != LDB_SUCCESS) {
989 if (!ldb_request_get_control(treq, DSDB_CONTROL_CURRENT_PARTITION_OID)) {
990 ret = ldb_request_add_control(treq,
991 DSDB_CONTROL_CURRENT_PARTITION_OID,
992 false, data->partitions[i]->ctrl);
993 if (ret != LDB_SUCCESS) {
999 ret = partition_request(data->partitions[i]->module, treq);
1000 if (ret != LDB_SUCCESS) {
1004 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
1005 if (ret != LDB_SUCCESS) {
1010 tseqr = talloc_get_type(res->extended->data,
1011 struct ldb_seqnum_result);
1012 timestamp = MAX(timestamp, tseqr->seq_num);
1020 ext = talloc_zero(req, struct ldb_extended);
1022 return LDB_ERR_OPERATIONS_ERROR;
1024 seqr = talloc_zero(ext, struct ldb_seqnum_result);
1027 return LDB_ERR_OPERATIONS_ERROR;
1029 ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
1032 switch (seq->type) {
1034 case LDB_SEQ_HIGHEST_SEQ:
1036 /* Has someone above set a timebase sequence? */
1037 if (timestamp_sequence) {
1038 seqr->seq_num = (((unsigned long long)timestamp << 24) | (seq_number & 0xFFFFFF));
1040 seqr->seq_num = seq_number;
1043 if (timestamp_sequence > seqr->seq_num) {
1044 seqr->seq_num = timestamp_sequence;
1045 seqr->flags |= LDB_SEQ_TIMESTAMP_SEQUENCE;
1048 seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
1050 case LDB_SEQ_HIGHEST_TIMESTAMP:
1051 seqr->seq_num = timestamp;
1055 if (seq->type == LDB_SEQ_NEXT) {
1059 /* send request done */
1060 return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
1064 static int partition_extended(struct ldb_module *module, struct ldb_request *req)
1066 struct partition_private_data *data;
1067 struct partition_context *ac;
1070 data = talloc_get_type(module->private_data, struct partition_private_data);
1072 return ldb_next_request(module, req);
1075 ret = partition_reload_if_required(module, data);
1076 if (ret != LDB_SUCCESS) {
1080 if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
1081 return partition_sequence_number(module, req);
1084 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_PARTITION_OID) == 0) {
1085 return partition_create(module, req);
1089 * as the extended operation has no dn
1090 * we need to send it to all partitions
1093 ac = partition_init_ctx(module, req);
1095 return LDB_ERR_OPERATIONS_ERROR;
1098 return partition_send_all(module, ac, req);
1101 _PUBLIC_ const struct ldb_module_ops ldb_partition_module_ops = {
1102 .name = "partition",
1103 .init_context = partition_init,
1104 .search = partition_search,
1105 .add = partition_add,
1106 .modify = partition_modify,
1107 .del = partition_delete,
1108 .rename = partition_rename,
1109 .extended = partition_extended,
1110 .start_transaction = partition_start_trans,
1111 .prepare_commit = partition_prepare_commit,
1112 .end_transaction = partition_end_trans,
1113 .del_transaction = partition_del_trans,