LDB ASYNC: core modules
authorSimo Sorce <idra@samba.org>
Thu, 11 Sep 2008 22:35:38 +0000 (18:35 -0400)
committerStefan Metzmacher <metze@samba.org>
Mon, 29 Sep 2008 02:22:19 +0000 (04:22 +0200)
source4/lib/ldb/ldb_map/ldb_map.c
source4/lib/ldb/ldb_map/ldb_map.h
source4/lib/ldb/ldb_map/ldb_map_inbound.c
source4/lib/ldb/ldb_map/ldb_map_outbound.c
source4/lib/ldb/ldb_map/ldb_map_private.h
source4/lib/ldb/modules/asq.c
source4/lib/ldb/modules/operational.c
source4/lib/ldb/modules/paged_results.c
source4/lib/ldb/modules/paged_searches.c
source4/lib/ldb/modules/rdn_name.c
source4/lib/ldb/modules/sort.c

index e9129c812b27cd354aea138a693ac3c53646c7c9..fafbb63b0a7c55ca8ebd2818555f68c5985afe1a 100644 (file)
@@ -3,6 +3,7 @@
 
    Copyright (C) Jelmer Vernooij 2005
    Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+   Copyright (C) Simo Sorce 2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -106,69 +107,23 @@ const struct ldb_map_context *map_get_context(struct ldb_module *module)
 }
 
 /* Create a generic request context. */
-static struct map_context *map_init_context(struct ldb_handle *h, struct ldb_request *req)
+struct map_context *map_init_context(struct ldb_module *module,
+                                       struct ldb_request *req)
 {
        struct map_context *ac;
 
-       ac = talloc_zero(h, struct map_context);
+       ac = talloc_zero(req, struct map_context);
        if (ac == NULL) {
-               map_oom(h->module);
+               ldb_set_errstring(module->ldb, "Out of Memory");
                return NULL;
        }
 
-       ac->module = h->module;
-       ac->orig_req = req;
+       ac->module = module;
+       ac->req = req;
 
        return ac;
 }
 
-/* Create a search request context. */
-struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares)
-{
-       struct map_search_context *sc;
-
-       sc = talloc_zero(ac, struct map_search_context);
-       if (sc == NULL) {
-               map_oom(ac->module);
-               return NULL;
-       }
-
-       sc->ac = ac;
-       sc->local_res = NULL;
-       sc->remote_res = ares;
-
-       return sc;
-}
-
-/* Create a request context and handle. */
-struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module)
-{
-       struct map_context *ac;
-       struct ldb_handle *h;
-
-       h = talloc_zero(req, struct ldb_handle);
-       if (h == NULL) {
-               map_oom(module);
-               return NULL;
-       }
-
-       h->module = module;
-
-       ac = map_init_context(h, req);
-       if (ac == NULL) {
-               talloc_free(h);
-               return NULL;
-       }
-
-       h->private_data = (void *)ac;
-
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
-
-       return h;
-}
-
-
 /* Dealing with DNs for different partitions
  * ========================================= */
 
@@ -888,113 +843,52 @@ static int map_objectclass_convert_operator(struct ldb_module *module, void *mem
 /* Auxiliary request construction
  * ============================== */
 
-/* Store the DN of a single search result in context. */
-static int map_search_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
-       struct map_context *ac;
-
-       if (context == NULL || ares == NULL) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ac = talloc_get_type(context, struct map_context);
-
-       /* We are interested only in the single reply */
-       if (ares->type != LDB_REPLY_ENTRY) {
-               talloc_free(ares);
-               return LDB_SUCCESS;
-       }
-
-       /* We have already found a remote DN */
-       if (ac->local_dn) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results to base search"));
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       /* Store local DN */
-       ac->local_dn = ares->message->dn;
-
-       return LDB_SUCCESS;
-}
-
 /* Build a request to search a record by its DN. */
-struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback)
+struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_map_callback_t callback)
 {
+       const struct ldb_parse_tree *search_tree;
        struct ldb_request *req;
-
-       req = talloc_zero(ac, struct ldb_request);
-       if (req == NULL) {
-               map_oom(ac->module);
-               return NULL;
-       }
-
-       req->operation = LDB_SEARCH;
-       req->op.search.base = dn;
-       req->op.search.scope = LDB_SCOPE_BASE;
-       req->op.search.attrs = attrs;
+       int ret;
 
        if (tree) {
-               req->op.search.tree = tree;
+               search_tree = tree;
        } else {
-               req->op.search.tree = ldb_parse_tree(req, NULL);
-               if (req->op.search.tree == NULL) {
-                       talloc_free(req);
+               search_tree = ldb_parse_tree(ac, NULL);
+               if (search_tree == NULL) {
                        return NULL;
                }
        }
 
-       req->controls = NULL;
-       req->context = context;
-       req->callback = callback;
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, req);
-
-       return req;
-}
-
-/* Build a request to search the local record by its DN. */
-struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn)
-{
-       /* attrs[] is returned from this function in
-        * ac->search_req->op.search.attrs, so it must be static, as
-        * otherwise the compiler can put it on the stack */
-       static const char * const attrs[] = { IS_MAPPED, NULL };
-       struct ldb_parse_tree *tree;
-
-       /* Limit search to records with 'IS_MAPPED' present */
-       /* TODO: `tree = ldb_parse_tree(ac, IS_MAPPED);' won't do. */
-       tree = talloc_zero(ac, struct ldb_parse_tree);
-       if (tree == NULL) {
-               map_oom(ac->module);
+       ret = ldb_build_search_req_ex(&req, ac->module->ldb, ac,
+                                       dn, LDB_SCOPE_BASE,
+                                       search_tree, attrs,
+                                       NULL,
+                                       context, callback,
+                                       ac->req);
+       if (ret != LDB_SUCCESS) {
                return NULL;
        }
 
-       tree->operation = LDB_OP_PRESENT;
-       tree->u.present.attr = talloc_strdup(tree, IS_MAPPED);
-
-       return map_search_base_req(ac, dn, attrs, tree, ac, map_search_self_callback);
+       return req;
 }
 
 /* Build a request to update the 'IS_MAPPED' attribute */
-struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn)
+struct ldb_request *map_build_fixup_req(struct map_context *ac,
+                                       struct ldb_dn *olddn,
+                                       struct ldb_dn *newdn,
+                                       void *context,
+                                       ldb_map_callback_t callback)
 {
        struct ldb_request *req;
        struct ldb_message *msg;
        const char *dn;
-
-       /* Prepare request */
-       req = talloc_zero(ac, struct ldb_request);
-       if (req == NULL) {
-               map_oom(ac->module);
-               return NULL;
-       }
+       int ret;
 
        /* Prepare message */
-       msg = ldb_msg_new(req);
+       msg = ldb_msg_new(ac);
        if (msg == NULL) {
                map_oom(ac->module);
-               goto failed;
+               return NULL;
        }
 
        /* Update local 'IS_MAPPED' to the new remote DN */
@@ -1010,193 +904,22 @@ struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *o
                goto failed;
        }
 
-       req->operation = LDB_MODIFY;
-       req->op.mod.message = msg;
-       req->controls = NULL;
-       req->handle = NULL;
-       req->context = NULL;
-       req->callback = NULL;
+       /* Prepare request */
+       ret = ldb_build_mod_req(&req, ac->module->ldb,
+                               ac, msg, NULL,
+                               context, callback,
+                               ac->req);
+       if (ret != LDB_SUCCESS) {
+               goto failed;
+       }
+       talloc_steal(req, msg);
 
        return req;
-
 failed:
-       talloc_free(req);
+       talloc_free(msg);
        return NULL;
 }
 
-
-/* Asynchronous call structure
- * =========================== */
-
-/* Figure out which request is currently pending. */
-static struct ldb_request *map_get_req(struct map_context *ac)
-{
-       switch (ac->step) {
-       case MAP_SEARCH_SELF_MODIFY:
-       case MAP_SEARCH_SELF_DELETE:
-       case MAP_SEARCH_SELF_RENAME:
-               return ac->search_req;
-
-       case MAP_ADD_REMOTE:
-       case MAP_MODIFY_REMOTE:
-       case MAP_DELETE_REMOTE:
-       case MAP_RENAME_REMOTE:
-               return ac->remote_req;
-
-       case MAP_RENAME_FIXUP:
-               return ac->down_req;
-
-       case MAP_ADD_LOCAL:
-       case MAP_MODIFY_LOCAL:
-       case MAP_DELETE_LOCAL:
-       case MAP_RENAME_LOCAL:
-               return ac->local_req;
-
-       case MAP_SEARCH_REMOTE:
-               /* Can't happen */
-               break;
-       }
-
-       return NULL;            /* unreachable; silences a warning */
-}
-
-typedef int (*map_next_function)(struct ldb_handle *handle);
-
-/* Figure out the next request to run. */
-static map_next_function map_get_next(struct map_context *ac)
-{
-       switch (ac->step) {
-       case MAP_SEARCH_REMOTE:
-               return NULL;
-
-       case MAP_ADD_LOCAL:
-               return map_add_do_remote;
-       case MAP_ADD_REMOTE:
-               return NULL;
-
-       case MAP_SEARCH_SELF_MODIFY:
-               return map_modify_do_local;
-       case MAP_MODIFY_LOCAL:
-               return map_modify_do_remote;
-       case MAP_MODIFY_REMOTE:
-               return NULL;
-
-       case MAP_SEARCH_SELF_DELETE:
-               return map_delete_do_local;
-       case MAP_DELETE_LOCAL:
-               return map_delete_do_remote;
-       case MAP_DELETE_REMOTE:
-               return NULL;
-
-       case MAP_SEARCH_SELF_RENAME:
-               return map_rename_do_local;
-       case MAP_RENAME_LOCAL:
-               return map_rename_do_fixup;
-       case MAP_RENAME_FIXUP:
-               return map_rename_do_remote;
-       case MAP_RENAME_REMOTE:
-               return NULL;
-       }
-
-       return NULL;            /* unreachable; silences a warning */
-}
-
-/* Wait for the current pending request to finish and continue with the next. */
-static int map_wait_next(struct ldb_handle *handle)
-{
-       struct map_context *ac;
-       struct ldb_request *req;
-       map_next_function next;
-       int ret;
-
-       if (handle == NULL || handle->private_data == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (handle->state == LDB_ASYNC_DONE) {
-               return handle->status;
-       }
-
-       handle->state = LDB_ASYNC_PENDING;
-       handle->status = LDB_SUCCESS;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       if (ac->step == MAP_SEARCH_REMOTE) {
-               int i;
-               for (i = 0; i < ac->num_searches; i++) {
-                       req = ac->search_reqs[i];
-                       ret = ldb_wait(req->handle, LDB_WAIT_NONE);
-
-                       if (ret != LDB_SUCCESS) {
-                               handle->status = ret;
-                               goto done;
-                       }
-                       if (req->handle->status != LDB_SUCCESS) {
-                               handle->status = req->handle->status;
-                               goto done;
-                       }
-                       if (req->handle->state != LDB_ASYNC_DONE) {
-                               return LDB_SUCCESS;
-                       }
-               }
-       } else {
-
-               req = map_get_req(ac);
-
-               ret = ldb_wait(req->handle, LDB_WAIT_NONE);
-
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-               if (req->handle->status != LDB_SUCCESS) {
-                       handle->status = req->handle->status;
-                       goto done;
-               }
-               if (req->handle->state != LDB_ASYNC_DONE) {
-                       return LDB_SUCCESS;
-               }
-
-               next = map_get_next(ac);
-               if (next) {
-                       return next(handle);
-               }
-       }
-
-       ret = LDB_SUCCESS;
-
-done:
-       handle->state = LDB_ASYNC_DONE;
-       return ret;
-}
-
-/* Wait for all current pending requests to finish. */
-static int map_wait_all(struct ldb_handle *handle)
-{
-       int ret;
-
-       while (handle->state != LDB_ASYNC_DONE) {
-               ret = map_wait_next(handle);
-               if (ret != LDB_SUCCESS) {
-                       return ret;
-               }
-       }
-
-       return handle->status;
-}
-
-/* Wait for pending requests to finish. */
-int map_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
-       if (type == LDB_WAIT_ALL) {
-               return map_wait_all(handle);
-       } else {
-               return map_wait_next(handle);
-       }
-}
-
-
 /* Module initialization
  * ===================== */
 
index e40bb9cd7e3aadb5a9d02eb204fbf7c085ded130..7f92c15b986b1cff4bad1e5bb7805d2da3f8811f 100644 (file)
@@ -160,14 +160,12 @@ int map_search(struct ldb_module *module, struct ldb_request *req);
 int map_rename(struct ldb_module *module, struct ldb_request *req);
 int map_delete(struct ldb_module *module, struct ldb_request *req);
 int map_modify(struct ldb_module *module, struct ldb_request *req);
-int map_wait(struct ldb_handle *handle, enum ldb_wait_type type);
 
 #define LDB_MAP_OPS \
        .add            = map_add, \
        .modify         = map_modify, \
        .del            = map_delete, \
        .rename         = map_rename, \
-       .search         = map_search, \
-       .wait           = map_wait,
+       .search         = map_search,
 
 #endif /* __LDB_MAP_H__ */
index 7fc3ac4ed5ee660b8d78d44526f8c5671617517e..96605f23ebcc0214405f87aaa0da45e011871eab 100644 (file)
@@ -3,6 +3,7 @@
 
    Copyright (C) Jelmer Vernooij 2005
    Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
+   Copyright (C) Simo Sorce <idra@samba.org> 2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -178,51 +179,181 @@ static int ldb_msg_partition(struct ldb_module *module, struct ldb_message *loca
 }
 
 
-/* Inbound requests: add, modify, rename, delete
- * ============================================= */
+static int map_add_do_local(struct map_context *ac);
+static int map_modify_do_local(struct map_context *ac);
+static int map_delete_do_local(struct map_context *ac);
+static int map_rename_do_local(struct map_context *ac);
+static int map_rename_do_fixup(struct map_context *ac);
+static int map_rename_local_callback(struct ldb_request *req,
+                                    struct ldb_reply *ares);
 
-/* Add the remote record. */
-int map_add_do_remote(struct ldb_handle *handle)
+
+/*****************************************************************************
+ * COMMON INBOUND functions
+*****************************************************************************/
+
+/* Store the DN of a single search result in context. */
+static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct map_context *ac;
+       int ret;
 
-       ac = talloc_get_type(handle->private_data, struct map_context);
+       ac = talloc_get_type(req->context, struct map_context);
 
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
 
-       ac->step = MAP_ADD_REMOTE;
+       /* We are interested only in the single reply */
+       switch(ares->type) {
+       case LDB_REPLY_ENTRY:
+               /* We have already found a remote DN */
+               if (ac->local_dn) {
+                       ldb_set_errstring(ac->module->ldb,
+                                         "Too many results!");
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
 
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
+               /* Store local DN */
+               ac->local_dn = talloc_steal(ac, ares->message->dn);
+               break;
 
-       return ldb_next_remote_request(ac->module, ac->remote_req);
+       case LDB_REPLY_DONE:
+
+               switch (ac->req->operation) {
+               case LDB_MODIFY:
+                       ret = map_modify_do_local(ac);
+                       break;
+               case LDB_DELETE:
+                       ret = map_delete_do_local(ac);
+                       break;
+               case LDB_RENAME:
+                       ret = map_rename_do_local(ac);
+                       break;
+               default:
+                       /* if we get here we have definitely a problem */
+                       ret = LDB_ERR_OPERATIONS_ERROR;
+               }
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+
+       default:
+               /* ignore referrals */
+               break;
+       }
+
+       talloc_free(ares);
+       return LDB_SUCCESS;
 }
 
-/* Add the local record. */
-int map_add_do_local(struct ldb_handle *handle)
+/* Build a request to search the local record by its DN. */
+static int map_search_self_req(struct ldb_request **req,
+                               struct map_context *ac,
+                               struct ldb_dn *dn)
+{
+       /* attrs[] is returned from this function in
+        * ac->search_req->op.search.attrs, so it must be static, as
+        * otherwise the compiler can put it on the stack */
+       static const char * const attrs[] = { IS_MAPPED, NULL };
+       struct ldb_parse_tree *tree;
+
+       /* Limit search to records with 'IS_MAPPED' present */
+       tree = ldb_parse_tree(ac, "(" IS_MAPPED "=*)");
+       if (tree == NULL) {
+               map_oom(ac->module);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       *req = map_search_base_req(ac, dn, attrs, tree,
+                                  ac, map_search_self_callback);
+       if (*req == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int map_op_local_callback(struct ldb_request *req,
+                                struct ldb_reply *ares)
 {
        struct map_context *ac;
+       int ret;
 
-       ac = talloc_get_type(handle->private_data, struct map_context);
+       ac = talloc_get_type(req->context, struct map_context);
 
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
 
-       ac->step = MAP_ADD_LOCAL;
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
 
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
+       /* Do the remote request. */
+       ret = ldb_next_remote_request(ac->module, ac->remote_req);
+       if (ret != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
 
-       return ldb_next_request(ac->module, ac->local_req);
+       return LDB_SUCCESS;
 }
 
+static int map_op_remote_callback(struct ldb_request *req,
+                                 struct ldb_reply *ares)
+{
+       struct map_context *ac;
+
+       ac = talloc_get_type(req->context, struct map_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+}
+
+
+/*****************************************************************************
+ * ADD operations
+*****************************************************************************/
+
+
 /* Add a record. */
 int map_add(struct ldb_module *module, struct ldb_request *req)
 {
        const struct ldb_message *msg = req->op.add.message;
-       struct ldb_handle *h;
        struct map_context *ac;
-       struct ldb_message *local, *remote;
+       struct ldb_message *remote_msg;
        const char *dn;
+       int ret;
 
        /* Do not manipulate our control entries */
        if (ldb_dn_is_special(msg->dn)) {
@@ -240,141 +371,88 @@ int map_add(struct ldb_module *module, struct ldb_request *req)
        }
 
        /* Prepare context and handle */
-       h = map_init_handle(req, module);
-       if (h == NULL) {
+       ac = map_init_context(module, req);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct map_context);
-
-       /* Prepare the local operation */
-       ac->local_req = talloc(ac, struct ldb_request);
-       if (ac->local_req == NULL) {
-               goto oom;
-       }
 
-       *(ac->local_req) = *req;        /* copy the request */
-
-       ac->local_req->context = NULL;
-       ac->local_req->callback = NULL;
-
-       /* Prepare the remote operation */
-       ac->remote_req = talloc(ac, struct ldb_request);
-       if (ac->remote_req == NULL) {
-               goto oom;
-       }
-
-       *(ac->remote_req) = *req;       /* copy the request */
-
-       ac->remote_req->context = NULL;
-       ac->remote_req->callback = NULL;
 
        /* Prepare the local message */
-       local = ldb_msg_new(ac->local_req);
-       if (local == NULL) {
-               goto oom;
+       ac->local_msg = ldb_msg_new(ac);
+       if (ac->local_msg == NULL) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-       local->dn = msg->dn;
+       ac->local_msg->dn = msg->dn;
 
        /* Prepare the remote message */
-       remote = ldb_msg_new(ac->remote_req);
-       if (remote == NULL) {
-               goto oom;
+       remote_msg = ldb_msg_new(ac);
+       if (remote_msg == NULL) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-       remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
+       remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
 
        /* Split local from remote message */
-       ldb_msg_partition(module, local, remote, msg);
-       ac->local_req->op.add.message = local;
-       ac->remote_req->op.add.message = remote;
+       ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
+
+       /* Prepare the remote operation */
+       ret = ldb_build_add_req(&ac->remote_req, module->ldb,
+                               ac, remote_msg,
+                               req->controls,
+                               ac, map_op_remote_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
+       if ((ac->local_msg->num_elements == 0) ||
+           ( ! map_check_local_db(ac->module))) {
                /* No local data or db, just run the remote request */
-               talloc_free(ac->local_req);
-               req->handle = h;        /* return our own handle to deal with this call */
-               return map_add_do_remote(h);
+               return ldb_next_remote_request(ac->module, ac->remote_req);
        }
 
        /* Store remote DN in 'IS_MAPPED' */
        /* TODO: use GUIDs here instead */
-       dn = ldb_dn_alloc_linearized(local, remote->dn);
-       if (ldb_msg_add_string(local, IS_MAPPED, dn) != 0) {
-               goto failed;
+       dn = ldb_dn_alloc_linearized(ac->local_msg, remote_msg->dn);
+       if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       req->handle = h;                /* return our own handle to deal with this call */
-       return map_add_do_local(h);
-
-oom:
-       map_oom(module);
-failed:
-       talloc_free(h);
-       return LDB_ERR_OPERATIONS_ERROR;
-}
-
-/* Modify the remote record. */
-int map_modify_do_remote(struct ldb_handle *handle)
-{
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
-
-       ac->step = MAP_MODIFY_REMOTE;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_remote_request(ac->module, ac->remote_req);
+       return map_add_do_local(ac);
 }
 
-/* Modify the local record. */
-int map_modify_do_local(struct ldb_handle *handle)
+/* Add the local record. */
+static int map_add_do_local(struct map_context *ac)
 {
-       struct map_context *ac;
-       struct ldb_message *msg;
-       char *dn;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       if (ac->local_dn == NULL) {
-               /* No local record present, add it instead */
-               msg = discard_const_p(struct ldb_message, ac->local_req->op.mod.message);
-
-               /* Add local 'IS_MAPPED' */
-               /* TODO: use GUIDs here instead */
-               if (ldb_msg_add_empty(msg, IS_MAPPED, LDB_FLAG_MOD_ADD, NULL) != 0) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-               dn = ldb_dn_alloc_linearized(msg, ac->remote_req->op.mod.message->dn);
-               if (ldb_msg_add_string(msg, IS_MAPPED, dn) != 0) {
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
+       struct ldb_request *local_req;
+       int ret;
 
-               /* Turn request into 'add' */
-               ac->local_req->operation = LDB_ADD;
-               ac->local_req->op.add.message = msg;
-               /* TODO: Could I just leave msg in there?  I think so,
-                *       but it looks clearer this way. */
+       /* Prepare the local operation */
+       ret = ldb_build_add_req(&local_req, ac->module->ldb, ac,
+                               ac->local_msg,
+                               ac->req->controls,
+                               ac,
+                               map_op_local_callback,
+                               ac->req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
-
-       ac->step = MAP_MODIFY_LOCAL;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_request(ac->module, ac->local_req);
+       return ldb_next_request(ac->module, local_req);
 }
 
+/*****************************************************************************
+ * MODIFY operations
+*****************************************************************************/
+
 /* Modify a record. */
 int map_modify(struct ldb_module *module, struct ldb_request *req)
 {
        const struct ldb_message *msg = req->op.mod.message;
-       struct ldb_handle *h;
+       struct ldb_request *search_req;
+       struct ldb_message *remote_msg;
        struct map_context *ac;
-       struct ldb_message *local, *remote;
+       int ret;
 
        /* Do not manipulate our control entries */
        if (ldb_dn_is_special(msg->dn)) {
@@ -395,257 +473,200 @@ int map_modify(struct ldb_module *module, struct ldb_request *req)
        }
 
        /* Prepare context and handle */
-       h = map_init_handle(req, module);
-       if (h == NULL) {
+       ac = map_init_context(module, req);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct map_context);
-
-       /* Prepare the local operation */
-       ac->local_req = talloc(ac, struct ldb_request);
-       if (ac->local_req == NULL) {
-               goto oom;
-       }
-
-       *(ac->local_req) = *req;        /* copy the request */
-
-       ac->local_req->context = NULL;
-       ac->local_req->callback = NULL;
-
-       /* Prepare the remote operation */
-       ac->remote_req = talloc(ac, struct ldb_request);
-       if (ac->remote_req == NULL) {
-               goto oom;
-       }
-
-       *(ac->remote_req) = *req;       /* copy the request */
-
-       ac->remote_req->context = NULL;
-       ac->remote_req->callback = NULL;
 
        /* Prepare the local message */
-       local = ldb_msg_new(ac->local_req);
-       if (local == NULL) {
-               goto oom;
+       ac->local_msg = ldb_msg_new(ac);
+       if (ac->local_msg == NULL) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-       local->dn = msg->dn;
+       ac->local_msg->dn = msg->dn;
 
        /* Prepare the remote message */
-       remote = ldb_msg_new(ac->remote_req);
-       if (remote == NULL) {
-               goto oom;
+       remote_msg = ldb_msg_new(ac->remote_req);
+       if (remote_msg == NULL) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-       remote->dn = ldb_dn_map_local(ac->module, remote, msg->dn);
+       remote_msg->dn = ldb_dn_map_local(ac->module, remote_msg, msg->dn);
 
        /* Split local from remote message */
-       ldb_msg_partition(module, local, remote, msg);
-       ac->local_req->op.mod.message = local;
-       ac->remote_req->op.mod.message = remote;
+       ldb_msg_partition(module, ac->local_msg, remote_msg, msg);
+
+       /* Prepare the remote operation */
+       ret = ldb_build_mod_req(&ac->remote_req, module->ldb,
+                               ac, remote_msg,
+                               req->controls,
+                               ac, map_op_remote_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       if ((local->num_elements == 0) || (!map_check_local_db(ac->module))) {
+       if ((ac->local_msg->num_elements == 0) ||
+           ( ! map_check_local_db(ac->module))) {
                /* No local data or db, just run the remote request */
-               talloc_free(ac->local_req);
-               req->handle = h;        /* return our own handle to deal with this call */
-               return map_modify_do_remote(h);
+               return ldb_next_remote_request(ac->module, ac->remote_req);
        }
 
        /* prepare the search operation */
-       ac->search_req = map_search_self_req(ac, msg->dn);
-       if (ac->search_req == NULL) {
-               goto failed;
+       ret = map_search_self_req(&search_req, ac, msg->dn);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ac->step = MAP_SEARCH_SELF_MODIFY;
-
-       req->handle = h;                /* return our own handle to deal with this call */
-       return ldb_next_request(module, ac->search_req);
-
-oom:
-       map_oom(module);
-failed:
-       talloc_free(h);
-       return LDB_ERR_OPERATIONS_ERROR;
-}
-
-/* Delete the remote record. */
-int map_delete_do_remote(struct ldb_handle *handle)
-{
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
-
-       ac->step = MAP_DELETE_REMOTE;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_remote_request(ac->module, ac->remote_req);
+       return ldb_next_request(module, search_req);
 }
 
-/* Delete the local record. */
-int map_delete_do_local(struct ldb_handle *handle)
+/* Modify the local record. */
+static int map_modify_do_local(struct map_context *ac)
 {
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
+       struct ldb_request *local_req;
+       char *dn;
+       int ret;
 
-       /* No local record, continue remotely */
        if (ac->local_dn == NULL) {
-               return map_delete_do_remote(handle);
-       }
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
-
-       ac->step = MAP_DELETE_LOCAL;
+               /* No local record present, add it instead */
+               /* Add local 'IS_MAPPED' */
+               /* TODO: use GUIDs here instead */
+               if (ldb_msg_add_empty(ac->local_msg, IS_MAPPED,
+                                       LDB_FLAG_MOD_ADD, NULL) != 0) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               dn = ldb_dn_alloc_linearized(ac->local_msg,
+                                       ac->remote_req->op.mod.message->dn);
+               if (ldb_msg_add_string(ac->local_msg, IS_MAPPED, dn) != 0) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
 
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
+               /* Prepare the local operation */
+               ret = ldb_build_add_req(&local_req, ac->module->ldb, ac,
+                                       ac->local_msg,
+                                       ac->req->controls,
+                                       ac,
+                                       map_op_local_callback,
+                                       ac->req);
+               if (ret != LDB_SUCCESS) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       } else {
+               /* Prepare the local operation */
+               ret = ldb_build_mod_req(&local_req, ac->module->ldb, ac,
+                                       ac->local_msg,
+                                       ac->req->controls,
+                                       ac,
+                                       map_op_local_callback,
+                                       ac->req);
+               if (ret != LDB_SUCCESS) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+       }
 
-       return ldb_next_request(ac->module, ac->local_req);
+       return ldb_next_request(ac->module, local_req);
 }
 
+/*****************************************************************************
+ * DELETE operations
+*****************************************************************************/
+
 /* Delete a record. */
 int map_delete(struct ldb_module *module, struct ldb_request *req)
 {
-       struct ldb_handle *h;
+       struct ldb_request *search_req;
        struct map_context *ac;
+       int ret;
 
        /* Do not manipulate our control entries */
        if (ldb_dn_is_special(req->op.del.dn)) {
                return ldb_next_request(module, req);
        }
 
-       /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+       /* No mapping requested (perhaps no DN mapping specified).
+        * Skip to next module */
        if (!ldb_dn_check_local(module, req->op.del.dn)) {
                return ldb_next_request(module, req);
        }
 
        /* Prepare context and handle */
-       h = map_init_handle(req, module);
-       if (h == NULL) {
+       ac = map_init_context(module, req);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct map_context);
-
-       /* Prepare the local operation */
-       ac->local_req = talloc(ac, struct ldb_request);
-       if (ac->local_req == NULL) {
-               goto oom;
-       }
-
-       *(ac->local_req) = *req;        /* copy the request */
-       ac->local_req->op.del.dn = req->op.del.dn;
-
-       ac->local_req->context = NULL;
-       ac->local_req->callback = NULL;
 
        /* Prepare the remote operation */
-       ac->remote_req = talloc(ac, struct ldb_request);
-       if (ac->remote_req == NULL) {
-               goto oom;
+       ret = ldb_build_del_req(&ac->remote_req, module->ldb, ac,
+                                  ldb_dn_map_local(module, ac, req->op.del.dn),
+                                  req->controls,
+                                  ac,
+                                  map_op_remote_callback,
+                                  req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       *(ac->remote_req) = *req;       /* copy the request */
-       ac->remote_req->op.del.dn = ldb_dn_map_local(module, ac->remote_req, req->op.del.dn);
-
        /* No local db, just run the remote request */
        if (!map_check_local_db(ac->module)) {
-               req->handle = h;        /* return our own handle to deal with this call */
-               return map_delete_do_remote(h);
+               /* Do the remote request. */
+               return ldb_next_remote_request(ac->module, ac->remote_req);
        }
 
-       ac->remote_req->context = NULL;
-       ac->remote_req->callback = NULL;
-
        /* Prepare the search operation */
-       ac->search_req = map_search_self_req(ac, req->op.del.dn);
-       if (ac->search_req == NULL) {
-               goto failed;
+       ret = map_search_self_req(&search_req, ac, req->op.del.dn);
+       if (ret != LDB_SUCCESS) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       req->handle = h;                /* return our own handle to deal with this call */
-
-       ac->step = MAP_SEARCH_SELF_DELETE;
-
-       return ldb_next_request(module, ac->search_req);
-
-oom:
-       map_oom(module);
-failed:
-       talloc_free(h);
-       return LDB_ERR_OPERATIONS_ERROR;
+       return ldb_next_request(module, search_req);
 }
 
-/* Rename the remote record. */
-int map_rename_do_remote(struct ldb_handle *handle)
-{
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->remote_req);
-
-       ac->step = MAP_RENAME_REMOTE;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_remote_request(ac->module, ac->remote_req);
-}
-
-/* Update the local 'IS_MAPPED' attribute. */
-int map_rename_do_fixup(struct ldb_handle *handle)
-{
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
-
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
-
-       ac->step = MAP_RENAME_FIXUP;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_request(ac->module, ac->down_req);
-}
-
-/* Rename the local record. */
-int map_rename_do_local(struct ldb_handle *handle)
+/* Delete the local record. */
+static int map_delete_do_local(struct map_context *ac)
 {
-       struct map_context *ac;
-
-       ac = talloc_get_type(handle->private_data, struct map_context);
+       struct ldb_request *local_req;
+       int ret;
 
        /* No local record, continue remotely */
        if (ac->local_dn == NULL) {
-               return map_rename_do_remote(handle);
+               /* Do the remote request. */
+               return ldb_next_remote_request(ac->module, ac->remote_req);
        }
 
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->local_req);
-
-       ac->step = MAP_RENAME_LOCAL;
-
-       handle->state = LDB_ASYNC_INIT;
-       handle->status = LDB_SUCCESS;
-
-       return ldb_next_request(ac->module, ac->local_req);
+       /* Prepare the local operation */
+       ret = ldb_build_del_req(&local_req, ac->module->ldb, ac,
+                                  ac->req->op.del.dn,
+                                  ac->req->controls,
+                                  ac,
+                                  map_op_local_callback,
+                                  ac->req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       return ldb_next_request(ac->module, local_req);
 }
 
+/*****************************************************************************
+ * RENAME operations
+*****************************************************************************/
+
 /* Rename a record. */
 int map_rename(struct ldb_module *module, struct ldb_request *req)
 {
-       struct ldb_handle *h;
+       struct ldb_request *search_req;
        struct map_context *ac;
+       int ret;
 
        /* Do not manipulate our control entries */
        if (ldb_dn_is_special(req->op.rename.olddn)) {
                return ldb_next_request(module, req);
        }
 
-       /* No mapping requested (perhaps no DN mapping specified), skip to next module */
+       /* No mapping requested (perhaps no DN mapping specified).
+        * Skip to next module */
        if ((!ldb_dn_check_local(module, req->op.rename.olddn)) &&
            (!ldb_dn_check_local(module, req->op.rename.newdn))) {
                return ldb_next_request(module, req);
@@ -658,66 +679,113 @@ int map_rename(struct ldb_module *module, struct ldb_request *req)
        }
 
        /* Prepare context and handle */
-       h = map_init_handle(req, module);
-       if (h == NULL) {
+       ac = map_init_context(module, req);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct map_context);
 
-       /* Prepare the local operation */
-       ac->local_req = talloc(ac, struct ldb_request);
-       if (ac->local_req == NULL) {
-               goto oom;
+       /* Prepare the remote operation */
+       ret = ldb_build_rename_req(&ac->remote_req, module->ldb, ac,
+                                  ldb_dn_map_local(module, ac, req->op.rename.olddn),
+                                  ldb_dn_map_local(module, ac, req->op.rename.newdn),
+                                  req->controls,
+                                  ac, map_op_remote_callback,
+                                  req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       *(ac->local_req) = *req;        /* copy the request */
-       ac->local_req->op.rename.olddn = req->op.rename.olddn;
-       ac->local_req->op.rename.newdn = req->op.rename.newdn;
+       /* No local db, just run the remote request */
+       if (!map_check_local_db(ac->module)) {
+               /* Do the remote request. */
+               return ldb_next_remote_request(ac->module, ac->remote_req);
+       }
 
-       ac->local_req->context = NULL;
-       ac->local_req->callback = NULL;
+       /* Prepare the search operation */
+       ret = map_search_self_req(&search_req, ac, req->op.rename.olddn);
+       if (ret != LDB_SUCCESS) {
+               map_oom(module);
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       /* Prepare the remote operation */
-       ac->remote_req = talloc(ac, struct ldb_request);
-       if (ac->remote_req == NULL) {
-               goto oom;
+       return ldb_next_request(module, search_req);
+}
+
+/* Rename the local record. */
+static int map_rename_do_local(struct map_context *ac)
+{
+       struct ldb_request *local_req;
+       int ret;
+
+       /* No local record, continue remotely */
+       if (ac->local_dn == NULL) {
+               /* Do the remote request. */
+               return ldb_next_remote_request(ac->module, ac->remote_req);
        }
 
-       *(ac->remote_req) = *req;       /* copy the request */
-       ac->remote_req->op.rename.olddn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.olddn);
-       ac->remote_req->op.rename.newdn = ldb_dn_map_local(module, ac->remote_req, req->op.rename.newdn);
+       /* Prepare the local operation */
+       ret = ldb_build_rename_req(&local_req, ac->module->ldb, ac,
+                                  ac->req->op.rename.olddn,
+                                  ac->req->op.rename.newdn,
+                                  ac->req->controls,
+                                  ac,
+                                  map_rename_local_callback,
+                                  ac->req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       ac->remote_req->context = NULL;
-       ac->remote_req->callback = NULL;
+       return ldb_next_request(ac->module, local_req);
+}
 
-       /* No local db, just run the remote request */
-       if (!map_check_local_db(ac->module)) {
-               req->handle = h;        /* return our own handle to deal with this call */
-               return map_rename_do_remote(h);
+static int map_rename_local_callback(struct ldb_request *req,
+                                    struct ldb_reply *ares)
+{
+       struct map_context *ac;
+       int ret;
+
+       ac = talloc_get_type(req->context, struct map_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
 
-       /* Prepare the fixup operation */
-       /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
-       ac->down_req = map_build_fixup_req(ac, req->op.rename.newdn, ac->remote_req->op.rename.newdn);
-       if (ac->down_req == NULL) {
-               goto failed;
+       if (ares->type != LDB_REPLY_DONE) {
+               ldb_set_errstring(req->handle->ldb, "Invalid reply type!");
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
 
-       /* Prepare the search operation */
-       ac->search_req = map_search_self_req(ac, req->op.rename.olddn);
-       if (ac->search_req == NULL) {
-               goto failed;
+       /* proceed with next step */
+       ret = map_rename_do_fixup(ac);
+       if (ret != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
 
-       req->handle = h;                /* return our own handle to deal with this call */
+       return LDB_SUCCESS;
+}
 
-       ac->step = MAP_SEARCH_SELF_RENAME;
+/* Update the local 'IS_MAPPED' attribute. */
+static int map_rename_do_fixup(struct map_context *ac)
+{
+       struct ldb_request *local_req;
 
-       return ldb_next_request(module, ac->search_req);
+       /* Prepare the fixup operation */
+       /* TODO: use GUIDs here instead -- or skip it when GUIDs are used. */
+       local_req = map_build_fixup_req(ac,
+                                       ac->req->op.rename.newdn,
+                                       ac->remote_req->op.rename.newdn,
+                                       ac,
+                                       map_op_local_callback);
+       if (local_req == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-oom:
-       map_oom(module);
-failed:
-       talloc_free(h);
-       return LDB_ERR_OPERATIONS_ERROR;
+       return ldb_next_request(ac->module, local_req);
 }
index fbc097f31362ad0f3915f241c337562abd7da5b8..5f524a8be3c74109974319e6c2e7285f2758bd33 100644 (file)
@@ -4,6 +4,7 @@
    Copyright (C) Jelmer Vernooij 2005
    Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+   Copyright (C) Simo Sorce <idra@samba.org> 2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -905,7 +906,11 @@ static int map_subtree_collect_remote(struct ldb_module *module, void *mem_ctx,
 
 /* Split subtrees that query attributes in the local partition from
  * those that query the remote partition. */
-static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx, void *remote_ctx, struct ldb_parse_tree **local_tree, struct ldb_parse_tree **remote_tree, const struct ldb_parse_tree *tree)
+static int ldb_parse_tree_partition(struct ldb_module *module,
+                                       void *mem_ctx,
+                                       struct ldb_parse_tree **local_tree,
+                                       struct ldb_parse_tree **remote_tree,
+                                       const struct ldb_parse_tree *tree)
 {
        int ret;
 
@@ -918,13 +923,13 @@ static int ldb_parse_tree_partition(struct ldb_module *module, void *local_ctx,
        }
 
        /* Generate local tree */
-       ret = map_subtree_select_local(module, local_ctx, local_tree, tree);
+       ret = map_subtree_select_local(module, mem_ctx, local_tree, tree);
        if (ret) {
                return ret;
        }
 
        /* Generate remote tree */
-       ret = map_subtree_collect_remote(module, remote_ctx, remote_tree, tree);
+       ret = map_subtree_collect_remote(module, mem_ctx, remote_tree, tree);
        if (ret) {
                talloc_free(*local_tree);
                return ret;
@@ -1008,24 +1013,46 @@ oom:
 /* Outbound requests: search
  * ========================= */
 
-/* Pass a merged search result up the callback chain. */
-int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, struct ldb_reply *ares)
+static int map_remote_search_callback(struct ldb_request *req,
+                                       struct ldb_reply *ares);
+static int map_local_merge_callback(struct ldb_request *req,
+                                       struct ldb_reply *ares);
+static int map_search_local(struct map_context *ac);
+
+static int map_save_entry(struct map_context *ac, struct ldb_reply *ares)
 {
-       int i;
+       struct map_reply *mr;
 
-       /* No callback registered, stop */
-       if (req->callback == NULL) {
-               return LDB_SUCCESS;
+       mr = talloc_zero(ac, struct map_reply);
+       if (mr == NULL) {
+               map_oom(ac->module);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
-
-       /* Only records need special treatment */
-       if (ares->type != LDB_REPLY_ENTRY) {
-               return req->callback(ldb, req->context, ares);
+       mr->remote = talloc_steal(mr, ares);
+       if (ac->r_current) {
+               ac->r_current->next = mr;
+       } else {
+               /* first entry */
+               ac->r_list = mr;
        }
+       ac->r_current = mr;
+
+       return LDB_SUCCESS;
+}
+
+/* Pass a merged search result up the callback chain. */
+int map_return_entry(struct map_context *ac, struct ldb_reply *ares)
+{
+       struct ldb_message_element *el;
+       const char * const *attrs;
+       int i;
 
        /* Merged result doesn't match original query, skip */
-       if (!ldb_match_msg(ldb, ares->message, req->op.search.tree, req->op.search.base, req->op.search.scope)) {
-               ldb_debug(ldb, LDB_DEBUG_TRACE, "ldb_map: "
+       if (!ldb_match_msg(ac->module->ldb, ares->message,
+                          ac->req->op.search.tree,
+                          ac->req->op.search.base,
+                          ac->req->op.search.scope)) {
+               ldb_debug(ac->module->ldb, LDB_DEBUG_TRACE, "ldb_map: "
                          "Skipping record '%s': "
                          "doesn't match original search\n",
                          ldb_dn_get_linearized(ares->message->dn));
@@ -1033,10 +1060,16 @@ int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, stru
        }
 
        /* Limit result to requested attrs */
-       if ((req->op.search.attrs) && (!ldb_attr_in_list(req->op.search.attrs, "*"))) {
-               for (i = 0; i < ares->message->num_elements; ) {
-                       struct ldb_message_element *el = &ares->message->elements[i];
-                       if (!ldb_attr_in_list(req->op.search.attrs, el->name)) {
+       if (ac->req->op.search.attrs &&
+           (! ldb_attr_in_list(ac->req->op.search.attrs, "*"))) {
+
+               attrs = ac->req->op.search.attrs;
+               i = 0;
+
+               while (i < ares->message->num_elements) {
+
+                       el = &ares->message->elements[i];
+                       if ( ! ldb_attr_in_list(attrs, el->name)) {
                                ldb_msg_remove_element(ares->message, el);
                        } else {
                                i++;
@@ -1044,129 +1077,16 @@ int map_up_callback(struct ldb_context *ldb, const struct ldb_request *req, stru
                }
        }
 
-       return req->callback(ldb, req->context, ares);
-}
-
-/* Merge the remote and local parts of a search result. */
-int map_local_merge_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
-       struct map_search_context *sc;
-       int ret;
-
-       if (context == NULL || ares == NULL) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
-                                                      "NULL Context or Result in `map_local_merge_callback`"));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       sc = talloc_get_type(context, struct map_search_context);
-
-       switch (ares->type) {
-       case LDB_REPLY_ENTRY:
-               /* We have already found a local record */
-               if (sc->local_res) {
-                       ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
-                                                              "Too many results to base search for local entry"));
-                       talloc_free(ares);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-
-               /* Store local result */
-               sc->local_res = ares;
-
-               /* Merge remote into local message */
-               ret = ldb_msg_merge_local(sc->ac->module, ares->message, sc->remote_res->message);
-               if (ret) {
-                       talloc_free(ares);
-                       return LDB_ERR_OPERATIONS_ERROR;
-               }
-
-               return map_up_callback(ldb, sc->ac->orig_req, ares);
-
-       case LDB_REPLY_DONE:
-               /* No local record found, continue with remote record */
-               if (sc->local_res == NULL) {
-                       return map_up_callback(ldb, sc->ac->orig_req, sc->remote_res);
-               }
-               return LDB_SUCCESS;
-
-       default:
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
-                                                      "Unexpected result type in base search for local entry"));
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-}
-
-/* Search the local part of a remote search result. */
-int map_remote_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
-{
-       struct map_context *ac;
-       struct map_search_context *sc;
-       struct ldb_request *req;
-       int ret;
-
-       if (context == NULL || ares == NULL) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "ldb_map: "
-                                                      "NULL Context or Result in `map_remote_search_callback`"));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ac = talloc_get_type(context, struct map_context);
-
-       /* It's not a record, stop searching */
-       if (ares->type != LDB_REPLY_ENTRY) {
-               return map_up_callback(ldb, ac->orig_req, ares);
-       }
-
-       /* Map result record into a local message */
-       ret = map_reply_remote(ac, ares);
-       if (ret) {
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       /* There is no local db, stop searching */
-       if (!map_check_local_db(ac->module)) {
-               return map_up_callback(ldb, ac->orig_req, ares);
-       }
-
-       /* Prepare local search context */
-       sc = map_init_search_context(ac, ares);
-       if (sc == NULL) {
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       /* Prepare local search request */
-       /* TODO: use GUIDs here instead? */
-
-       ac->search_reqs = talloc_realloc(ac, ac->search_reqs, struct ldb_request *, ac->num_searches + 2);
-       if (ac->search_reqs == NULL) {
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ac->search_reqs[ac->num_searches]
-               = req = map_search_base_req(ac, ares->message->dn, 
-                                           NULL, NULL, sc, map_local_merge_callback);
-       if (req == NULL) {
-               talloc_free(sc);
-               talloc_free(ares);
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       ac->num_searches++;
-       ac->search_reqs[ac->num_searches] = NULL;
-
-       return ldb_next_request(ac->module, req);
+       return ldb_module_send_entry(ac->req, ares->message);
 }
 
 /* Search a record. */
 int map_search(struct ldb_module *module, struct ldb_request *req)
 {
-       struct ldb_handle *h;
+       struct ldb_parse_tree *remote_tree;
+       struct ldb_parse_tree *local_tree;
+       struct ldb_request *remote_req;
        struct map_context *ac;
-       struct ldb_parse_tree *local_tree, *remote_tree;
        int ret;
 
        const char *wildcard[] = { "*", NULL };
@@ -1176,8 +1096,9 @@ int map_search(struct ldb_module *module, struct ldb_request *req)
                return ldb_next_request(module, req);
 
        /* Do not manipulate our control entries */
-       if (ldb_dn_is_special(req->op.search.base))
+       if (ldb_dn_is_special(req->op.search.base)) {
                return ldb_next_request(module, req);
+       }
 
        /* No mapping requested, skip to next module */
        if ((req->op.search.base) && (!ldb_dn_check_local(module, req->op.search.base))) {
@@ -1188,32 +1109,10 @@ int map_search(struct ldb_module *module, struct ldb_request *req)
         *       targetting when there is no search base? */
 
        /* Prepare context and handle */
-       h = map_init_handle(req, module);
-       if (h == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       ac = talloc_get_type(h->private_data, struct map_context);
-
-       ac->search_reqs = talloc_array(ac, struct ldb_request *, 2);
-       if (ac->search_reqs == NULL) {
-               talloc_free(h);
+       ac = map_init_context(module, req);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac->num_searches = 1;
-       ac->search_reqs[1] = NULL;
-
-       /* Prepare the remote operation */
-       ac->search_reqs[0] = talloc(ac, struct ldb_request);
-       if (ac->search_reqs[0] == NULL) {
-               goto oom;
-       }
-
-       *(ac->search_reqs[0]) = *req;   /* copy the request */
-
-       ac->search_reqs[0]->handle = h; /* return our own handle to deal with this call */
-
-       ac->search_reqs[0]->context = ac;
-       ac->search_reqs[0]->callback = map_remote_search_callback;
 
        /* It is easier to deal with the two different ways of
         * expressing the wildcard in the same codepath */
@@ -1226,17 +1125,15 @@ int map_search(struct ldb_module *module, struct ldb_request *req)
        ret = map_attrs_collect_and_partition(module, ac, 
                                              attrs, req->op.search.tree);
        if (ret) {
-               goto failed;
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ac->search_reqs[0]->op.search.attrs = ac->remote_attrs;
-
        /* Split local from remote tree */
-       ret = ldb_parse_tree_partition(module, ac, ac->search_reqs[0], 
-                                      &local_tree, &remote_tree, 
+       ret = ldb_parse_tree_partition(module, ac,
+                                      &local_tree, &remote_tree,
                                       req->op.search.tree);
        if (ret) {
-               goto failed;
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
        if (((local_tree != NULL) && (remote_tree != NULL)) &&
@@ -1251,7 +1148,7 @@ int map_search(struct ldb_module *module, struct ldb_request *req)
                local_tree = talloc_zero(ac, struct ldb_parse_tree);
                if (local_tree == NULL) {
                        map_oom(ac->module);
-                       goto failed;
+                       return LDB_ERR_OPERATIONS_ERROR;
                }
 
                local_tree->operation = LDB_OP_PRESENT;
@@ -1259,31 +1156,209 @@ int map_search(struct ldb_module *module, struct ldb_request *req)
        }
        if (remote_tree == NULL) {
                /* Construct default remote parse tree */
-               remote_tree = ldb_parse_tree(ac->search_reqs[0], NULL);
+               remote_tree = ldb_parse_tree(ac, NULL);
                if (remote_tree == NULL) {
-                       goto failed;
+                       return LDB_ERR_OPERATIONS_ERROR;
                }
        }
 
        ac->local_tree = local_tree;
-       ac->search_reqs[0]->op.search.tree = remote_tree;
 
-       ldb_set_timeout_from_prev_req(module->ldb, req, ac->search_reqs[0]);
+       /* Prepare the remote operation */
+       ret = ldb_build_search_req_ex(&remote_req, module->ldb, ac,
+                                     req->op.search.base,
+                                     req->op.search.scope,
+                                     remote_tree,
+                                     ac->remote_attrs,
+                                     req->controls,
+                                     ac, map_remote_search_callback,
+                                     req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
+       return ldb_next_remote_request(module, remote_req);
+}
+
+/* Now, search the local part of a remote search result. */
+static int map_remote_search_callback(struct ldb_request *req,
+                                       struct ldb_reply *ares)
+{
+       struct map_context *ac;
+       int ret;
 
-       ac->step = MAP_SEARCH_REMOTE;
+       ac = talloc_get_type(req->context, struct map_context);
 
-       ret = ldb_next_remote_request(module, ac->search_reqs[0]);
-       if (ret == LDB_SUCCESS) {
-               req->handle = h;
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
-       return ret;
 
-oom:
-       map_oom(module);
-failed:
-       talloc_free(h);
-       return LDB_ERR_OPERATIONS_ERROR;
+       switch (ares->type) {
+       case LDB_REPLY_REFERRAL:
+
+               /* ignore referrals */
+               talloc_free(ares);
+               return LDB_SUCCESS;
+
+       case LDB_REPLY_ENTRY:
+
+               /* Map result record into a local message */
+               ret = map_reply_remote(ac, ares);
+               if (ret) {
+                       talloc_free(ares);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+
+               /* if we have no local db, then we can just return the reply to
+                * the upper layer, otherwise we must save it and process it
+                * when all replies ahve been gathered */
+               if ( ! map_check_local_db(ac->module)) {
+                       ret = map_return_entry(ac, ares);
+               } else {
+                       ret = map_save_entry(ac,ares);
+               }
+
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(ares);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+               break;
+
+       case LDB_REPLY_DONE:
+
+               if ( ! map_check_local_db(ac->module)) {
+                       return ldb_module_done(ac->req, ares->controls,
+                                               ares->response, LDB_SUCCESS);
+               }
+
+               talloc_free(ares);
+
+               /* reset the pointer to the start of the list */
+               ac->r_current = ac->r_list;
+
+               /* no entry just return */
+               if (ac->r_current == NULL) {
+                       return ldb_module_done(ac->req, ares->controls,
+                                               ares->response, LDB_SUCCESS);
+               }
+
+               ret = map_search_local(ac);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int map_search_local(struct map_context *ac)
+{
+       struct ldb_request *search_req;
+
+       if (ac->r_current == NULL || ac->r_current->remote == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       /* Prepare local search request */
+       /* TODO: use GUIDs here instead? */
+       search_req = map_search_base_req(ac,
+                                        ac->r_current->remote->message->dn,
+                                        NULL, NULL,
+                                        ac, map_local_merge_callback);
+       if (search_req == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       return ldb_next_request(ac->module, search_req);
+}
+
+/* Merge the remote and local parts of a search result. */
+int map_local_merge_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct map_context *ac;
+       int ret;
+
+       ac = talloc_get_type(req->context, struct map_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               /* We have already found a local record */
+               if (ac->r_current->local) {
+                       talloc_free(ares);
+                       ldb_set_errstring(ac->module->ldb, "ldb_map: Too many results!");
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+
+               /* Store local result */
+               ac->r_current->local = talloc_steal(ac->r_current, ares);
+
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               /* ignore referrals */
+               talloc_free(ares);
+               break;
+
+       case LDB_REPLY_DONE:
+               talloc_free(ares);
+
+               /* No local record found, map and send remote record */
+               if (ac->r_current->local != NULL) {
+                       /* Merge remote into local message */
+                       ret = ldb_msg_merge_local(ac->module,
+                                                 ac->r_current->local->message,
+                                                 ac->r_current->remote->message);
+                       if (ret == LDB_SUCCESS) {
+                               ret = map_return_entry(ac, ac->r_current->local);
+                       }
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req, NULL, NULL,
+                                                       LDB_ERR_OPERATIONS_ERROR);
+                       }
+               } else {
+                       ret = map_return_entry(ac, ac->r_current->remote);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req,
+                                                       NULL, NULL, ret);
+                       }
+               }
+
+               if (ac->r_current->next != NULL) {
+                       ac->r_current = ac->r_current->next;
+                       if (ac->r_current->remote->type == LDB_REPLY_ENTRY) {
+                               ret = map_search_local(ac);
+                               if (ret != LDB_SUCCESS) {
+                                       return ldb_module_done(ac->req,
+                                                              NULL, NULL, ret);
+                               }
+                               break;
+                       }
+               }
+
+               /* ok we are done with all search, finally it is time to
+                * finish operations for this module */
+               return ldb_module_done(ac->req,
+                                       ac->r_current->remote->controls,
+                                       ac->r_current->remote->response,
+                                       ac->r_current->remote->error);
+       }
+
+       return LDB_SUCCESS;
 }
index 58a9f2704ef8eafd65457cb339304e1b57637cff..5522125344e84394e44bc67b2d8116443ef3b172 100644 (file)
@@ -3,7 +3,7 @@
 #define map_oom(module) ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
 
 /* The type of search callback functions */
-typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_reply *);
+typedef int (*ldb_map_callback_t)(struct ldb_request *, struct ldb_reply *);
 
 /* The special DN from which the local and remote base DNs are fetched */
 #define MAP_DN_NAME    "@MAP"
@@ -13,25 +13,17 @@ typedef int (*ldb_search_callback)(struct ldb_context *, void *, struct ldb_repl
 /* Private data structures
  * ======================= */
 
+struct map_reply {
+       struct map_reply *next;
+       struct ldb_reply *remote;
+       struct ldb_reply *local;
+};
+
 /* Context data for mapped requests */
 struct map_context {
-       enum map_step {
-               MAP_SEARCH_REMOTE,
-               MAP_ADD_REMOTE,
-               MAP_ADD_LOCAL,
-               MAP_SEARCH_SELF_MODIFY,
-               MAP_MODIFY_REMOTE,
-               MAP_MODIFY_LOCAL,
-               MAP_SEARCH_SELF_DELETE,
-               MAP_DELETE_REMOTE,
-               MAP_DELETE_LOCAL,
-               MAP_SEARCH_SELF_RENAME,
-               MAP_RENAME_REMOTE,
-               MAP_RENAME_FIXUP,
-               MAP_RENAME_LOCAL
-       } step;
 
        struct ldb_module *module;
+       struct ldb_request *req;
 
        struct ldb_dn *local_dn;
        const struct ldb_parse_tree *local_tree;
@@ -39,32 +31,20 @@ struct map_context {
        const char * const *remote_attrs;
        const char * const *all_attrs;
 
-       struct ldb_request *orig_req;
-       struct ldb_request *local_req;
+       struct ldb_message *local_msg;
        struct ldb_request *remote_req;
-       struct ldb_request *down_req;
-       struct ldb_request *search_req;
-
-       /* for search, we may have a lot of contexts */
-       int num_searches;
-       struct ldb_request **search_reqs;
-};
 
-/* Context data for mapped search requests */
-struct map_search_context {
-       struct map_context *ac;
-       struct ldb_reply *local_res;
-       struct ldb_reply *remote_res;
+       struct map_reply *r_list;
+       struct map_reply *r_current;
 };
 
-
 /* Common operations
  * ================= */
 
 /* The following definitions come from lib/ldb/modules/ldb_map.c */
 const struct ldb_map_context *map_get_context(struct ldb_module *module);
-struct map_search_context *map_init_search_context(struct map_context *ac, struct ldb_reply *ares);
-struct ldb_handle *map_init_handle(struct ldb_request *req, struct ldb_module *module);
+struct map_context *map_init_context(struct ldb_module *module,
+                                       struct ldb_request *req);
 
 int ldb_next_remote_request(struct ldb_module *module, struct ldb_request *request);
 
@@ -86,25 +66,23 @@ struct ldb_dn *ldb_dn_map_local(struct ldb_module *module, void *mem_ctx, struct
 struct ldb_dn *ldb_dn_map_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
 struct ldb_dn *ldb_dn_map_rebase_remote(struct ldb_module *module, void *mem_ctx, struct ldb_dn *dn);
 
-struct ldb_request *map_search_base_req(struct map_context *ac, struct ldb_dn *dn, const char * const *attrs, const struct ldb_parse_tree *tree, void *context, ldb_search_callback callback);
-struct ldb_request *map_search_self_req(struct map_context *ac, struct ldb_dn *dn);
-struct ldb_request *map_build_fixup_req(struct map_context *ac, struct ldb_dn *olddn, struct ldb_dn *newdn);
-
-int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx, struct ldb_parse_tree **new, const struct ldb_parse_tree *tree, const struct ldb_map_attribute *map);
-
-/* LDB Requests
- * ============ */
-
-/* The following definitions come from lib/ldb/modules/ldb_map_inbound.c */
-int map_add_do_remote(struct ldb_handle *handle);
-int map_add_do_local(struct ldb_handle *handle);
-
-int map_modify_do_remote(struct ldb_handle *handle);
-int map_modify_do_local(struct ldb_handle *handle);
-
-int map_delete_do_remote(struct ldb_handle *handle);
-int map_delete_do_local(struct ldb_handle *handle);
-
-int map_rename_do_remote(struct ldb_handle *handle);
-int map_rename_do_fixup(struct ldb_handle *handle);
-int map_rename_do_local(struct ldb_handle *handle);
+struct ldb_request *map_search_base_req(struct map_context *ac,
+                                       struct ldb_dn *dn,
+                                       const char * const *attrs,
+                                       const struct ldb_parse_tree *tree,
+                                       void *context,
+                                       ldb_map_callback_t callback);
+struct ldb_request *map_build_fixup_req(struct map_context *ac,
+                                       struct ldb_dn *olddn,
+                                       struct ldb_dn *newdn,
+                                       void *context,
+                                       ldb_map_callback_t callback);
+int map_subtree_collect_remote_simple(struct ldb_module *module, void *mem_ctx,
+                                       struct ldb_parse_tree **new,
+                                       const struct ldb_parse_tree *tree,
+                                       const struct ldb_map_attribute *map);
+int map_return_fatal_error(struct ldb_request *req,
+                          struct ldb_reply *ares);
+int map_return_normal_error(struct ldb_request *req,
+                           struct ldb_reply *ares,
+                           int error);
index eb27263b16ffe2a0fc13f241665b4061bec36bc0..17896a006a313cbb1d5c39539acea5e28e16019d 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Simo Sorce  2005
+   Copyright (C) Simo Sorce  2005-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
 
 struct asq_context {
 
-       enum {ASQ_INIT, ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
+       enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
 
        struct ldb_module *module;
-       struct ldb_request *orig_req;
+       struct ldb_request *req;
 
        struct ldb_asq_control *asq_ctrl;
 
@@ -52,7 +52,6 @@ struct asq_context {
                ASQ_CTRL_AFFECTS_MULTIPLE_DSA           = 71
        } asq_ret;
 
-       struct ldb_request *base_req;
        struct ldb_reply *base_res;
 
        struct ldb_request **reqs;
@@ -62,192 +61,200 @@ struct asq_context {
        struct ldb_control **controls;
 };
 
-static struct ldb_handle *init_handle(struct ldb_request *req, struct ldb_module *module)
+static struct asq_context *asq_context_init(struct ldb_module *module, struct ldb_request *req)
 {
        struct asq_context *ac;
-       struct ldb_handle *h;
-
-       h = talloc_zero(req, struct ldb_handle);
-       if (h == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               return NULL;
-       }
 
-       h->module = module;
-
-       ac = talloc_zero(h, struct asq_context);
+       ac = talloc_zero(req, struct asq_context);
        if (ac == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               talloc_free(h);
+               ldb_oom(module->ldb);
                return NULL;
        }
 
-       h->private_data = (void *)ac;
-
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
-
-       ac->step = ASQ_INIT;
        ac->module = module;
-       ac->orig_req = req;
+       ac->req = req;
 
-       return h;
+       return ac;
 }
 
-static int asq_terminate(struct ldb_handle *handle)
+static int asq_search_continue(struct asq_context *ac);
+
+static int asq_search_terminate(struct asq_context *ac)
 {
-       struct asq_context *ac;
-       struct ldb_reply *ares;
        struct ldb_asq_control *asq;
        int i;
 
-       ac = talloc_get_type(handle->private_data, struct asq_context);
-       if (ac == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       handle->status = LDB_SUCCESS;
-       handle->state = LDB_ASYNC_DONE;
-
-       ares = talloc_zero(ac, struct ldb_reply);
-       if (ares == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
-
-       ares->type = LDB_REPLY_DONE;
-
        if (ac->controls) {
-               for (i = 0; ac->controls[i]; i++);
-               ares->controls = talloc_move(ares, &ac->controls);
+               for (i = 0; ac->controls[i]; i++) /* count em */ ;
        } else {
                i = 0;
        }
 
-       ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, i + 2);
-       
-       if (ares->controls == NULL)
+       ac->controls = talloc_realloc(ac, ac->controls, struct ldb_control *, i + 2);
+
+       if (ac->controls == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       ares->controls[i] = talloc(ares->controls, struct ldb_control);
-       if (ares->controls[i] == NULL)
+       ac->controls[i] = talloc(ac->controls, struct ldb_control);
+       if (ac->controls[i] == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       ares->controls[i]->oid = LDB_CONTROL_ASQ_OID;
-       ares->controls[i]->critical = 0;
+       ac->controls[i]->oid = LDB_CONTROL_ASQ_OID;
+       ac->controls[i]->critical = 0;
 
-       asq = talloc_zero(ares->controls[i], struct ldb_asq_control);
+       asq = talloc_zero(ac->controls[i], struct ldb_asq_control);
        if (asq == NULL)
                return LDB_ERR_OPERATIONS_ERROR;
 
        asq->result = ac->asq_ret;
-       
-       ares->controls[i]->data = asq;
 
-       ares->controls[i + 1] = NULL;
+       ac->controls[i]->data = asq;
 
-       ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares);
+       ac->controls[i + 1] = NULL;
 
-       return LDB_SUCCESS;
+       return ldb_module_done(ac->req, ac->controls, NULL, LDB_SUCCESS);
 }
 
-static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int asq_base_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct asq_context *ac;
+       int ret;
 
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
-       }
+       ac = talloc_get_type(req->context, struct asq_context);
 
-       ac = talloc_get_type(context, struct asq_context);
-       if (ac == NULL) {
-               goto error;
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
 
-       /* we are interested only in the single reply (base search) we receive here */
-       if (ares->type == LDB_REPLY_ENTRY) {
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
                ac->base_res = talloc_move(ac, &ares);
-       } else {
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               /* ignore referrals */
                talloc_free(ares);
-       }
+               break;
 
+       case LDB_REPLY_DONE:
+
+               talloc_free(ares);
+
+               /* next step */
+               ret = asq_search_continue(ac);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+               break;
+
+       }
        return LDB_SUCCESS;
-error:
-       talloc_free(ares);
-       return LDB_ERR_OPERATIONS_ERROR;
 }
 
-static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int asq_reqs_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct asq_context *ac;
+       int ret;
 
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
-       }
+       ac = talloc_get_type(req->context, struct asq_context);
 
-       ac = talloc_get_type(context, struct asq_context);
-       if (ac == NULL) {
-               goto error;
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
 
-       /* we are interested only in the single reply (base search) we receive here */
-       if (ares->type == LDB_REPLY_ENTRY) {
-
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
                /* pass the message up to the original callback as we
                 * do not have to elaborate on it any further */
-               return ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares);
-               
-       } else { /* ignore any REFERRAL or DONE reply */
+               ret = ldb_module_send_entry(ac->req, ares->message);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+               talloc_free(ares);
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               /* ignore referrals */
+               talloc_free(ares);
+               break;
+
+       case LDB_REPLY_DONE:
+
                talloc_free(ares);
+
+               ret = asq_search_continue(ac);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
+               break;
        }
 
        return LDB_SUCCESS;
-error:
-       talloc_free(ares);
-       return LDB_ERR_OPERATIONS_ERROR;
 }
 
-static int asq_build_first_request(struct asq_context *ac)
+static int asq_build_first_request(struct asq_context *ac, struct ldb_request **base_req)
 {
-       char **base_attrs;
+       const char **base_attrs;
+       int ret;
 
-       ac->base_req = talloc_zero(ac, struct ldb_request);
-       if (ac->base_req == NULL) return LDB_ERR_OPERATIONS_ERROR;
+       ac->req_attrs = ac->req->op.search.attrs;
+       ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
+       if (ac->req_attribute == NULL)
+               return LDB_ERR_OPERATIONS_ERROR;
 
-       ac->base_req->operation = ac->orig_req->operation;
-       ac->base_req->op.search.base = ac->orig_req->op.search.base;
-       ac->base_req->op.search.scope = LDB_SCOPE_BASE;
-       ac->base_req->op.search.tree = ac->orig_req->op.search.tree;
-       base_attrs = talloc_array(ac->base_req, char *, 2);
+       base_attrs = talloc_array(ac, const char *, 2);
        if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
        base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
        if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
        base_attrs[1] = NULL;
-       ac->base_req->op.search.attrs = (const char * const *)base_attrs;
 
-       ac->base_req->context = ac;
-       ac->base_req->callback = asq_base_callback;
-       ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->base_req);
+       ret = ldb_build_search_req_ex(base_req, ac->module->ldb, ac,
+                                       ac->req->op.search.base,
+                                       LDB_SCOPE_BASE,
+                                       ac->req->op.search.tree,
+                                       (const char * const *)base_attrs,
+                                       NULL,
+                                       ac, asq_base_callback,
+                                       ac->req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
        return LDB_SUCCESS;
 }
 
-static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle *handle)
+static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated)
 {
+       struct ldb_control **saved_controls;
+       struct ldb_control *control;
+       struct ldb_dn *dn;
        struct ldb_message_element *el;
-       int i;
+       int ret, i;
 
-       /* look up the DNs */
        if (ac->base_res == NULL) {
                return LDB_ERR_NO_SUCH_OBJECT;
        }
+
        el = ldb_msg_find_element(ac->base_res->message, ac->req_attribute);
        /* no values found */
        if (el == NULL) {
                ac->asq_ret = ASQ_CTRL_SUCCESS;
-               return asq_terminate(handle);
+               *terminated = true;
+               return asq_search_terminate(ac);
        }
 
        ac->num_reqs = el->num_values;
@@ -259,144 +266,75 @@ static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle
 
        for (i = 0; i < el->num_values; i++) {
 
-               ac->reqs[i] = talloc_zero(ac->reqs, struct ldb_request);
-               if (ac->reqs[i] == NULL)
-                       return LDB_ERR_OPERATIONS_ERROR;
-               ac->reqs[i]->operation = LDB_SEARCH;
-               ac->reqs[i]->op.search.base = ldb_dn_new(ac->reqs[i], ac->module->ldb, (const char *)el->values[i].data);
-               if ( ! ldb_dn_validate(ac->reqs[i]->op.search.base)) {
+               dn = ldb_dn_new(ac, ac->module->ldb,
+                               (const char *)el->values[i].data);
+               if ( ! ldb_dn_validate(dn)) {
                        ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
-                       return asq_terminate(handle);
+                       *terminated = true;
+                       return asq_search_terminate(ac);
+               }
+
+               ret = ldb_build_search_req_ex(&ac->reqs[i],
+                                               ac->module->ldb, ac,
+                                               dn, LDB_SCOPE_BASE,
+                                               ac->req->op.search.tree,
+                                               ac->req_attrs,
+                                               ac->req->controls,
+                                               ac, asq_reqs_callback,
+                                               ac->req);
+               if (ret != LDB_SUCCESS) {
+                       return LDB_ERR_OPERATIONS_ERROR;
                }
-               ac->reqs[i]->op.search.scope = LDB_SCOPE_BASE;
-               ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree;
-               ac->reqs[i]->op.search.attrs = ac->req_attrs;
 
-               ac->reqs[i]->context = ac;
-               ac->reqs[i]->callback = asq_reqs_callback;
-               ldb_set_timeout_from_prev_req(ac->module->ldb, ac->base_req, ac->reqs[i]);
+               /* remove the ASQ control itself */
+               control = ldb_request_get_control(ac->req, LDB_CONTROL_ASQ_OID);
+               if (!save_controls(control, ac->reqs[i], &saved_controls)) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
        }
 
        return LDB_SUCCESS;
 }
 
-static int asq_search_continue(struct ldb_handle *handle)
+static int asq_search_continue(struct asq_context *ac)
 {
-       struct asq_context *ac;
+       bool terminated = false;
        int ret;
-    
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (handle->state == LDB_ASYNC_DONE) {
-               return handle->status;
-       }
-
-       ac = talloc_get_type(handle->private_data, struct asq_context);
-       if (ac == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
 
        switch (ac->step) {
-       case ASQ_INIT:
-               /* check the search is well formed */
-               if (ac->orig_req->op.search.scope != LDB_SCOPE_BASE) {
-                       ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
-                       return asq_terminate(handle);
-               }
-
-               ac->req_attrs = ac->orig_req->op.search.attrs;
-               ac->req_attribute = talloc_strdup(ac, ac->asq_ctrl->source_attribute);
-               if (ac->req_attribute == NULL)
-                       return LDB_ERR_OPERATIONS_ERROR;
-
-               /* get the object to retrieve the DNs to search */
-               ret = asq_build_first_request(ac);
-               if (ret != LDB_SUCCESS) {
-                       return ret;
-               }
-       
-               ac->step = ASQ_SEARCH_BASE;
-
-               handle->state = LDB_ASYNC_PENDING;
-               handle->status = LDB_SUCCESS;
-
-               return ldb_request(ac->module->ldb, ac->base_req);
-
        case ASQ_SEARCH_BASE:
 
-               ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE);
-               
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-
-               if (ac->base_req->handle->status != LDB_SUCCESS) {
-                       handle->status = ac->base_req->handle->status;
-                       goto done;
+               /* build up the requests call chain */
+               ret = asq_build_multiple_requests(ac, &terminated);
+               if (ret != LDB_SUCCESS || terminated) {
+                       return ret;
                }
 
-               if (ac->base_req->handle->state == LDB_ASYNC_DONE) {
+               ac->step = ASQ_SEARCH_MULTI;
 
-                       /* build up the requests call chain */
-                       ret = asq_build_multiple_requests(ac, handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-                       if (handle->state == LDB_ASYNC_DONE) {
-                               return LDB_SUCCESS;
-                       }
-
-                       ac->step = ASQ_SEARCH_MULTI;
-
-                       return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
-               }
-
-               /* request still pending, return to cycle again */
-               return LDB_SUCCESS;
+               return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
 
        case ASQ_SEARCH_MULTI:
 
-               ret = ldb_wait(ac->reqs[ac->cur_req]->handle, LDB_WAIT_NONE);
-               
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-               if (ac->reqs[ac->cur_req]->handle->status != LDB_SUCCESS) {
-                       handle->status = ac->reqs[ac->cur_req]->handle->status;
-               }
-
-               if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) {
-                       ac->cur_req++;
+               ac->cur_req++;
 
-                       if (ac->cur_req < ac->num_reqs) {
-                               return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
-                       }
-
-                       return asq_terminate(handle);
+               if (ac->cur_req == ac->num_reqs) {
+                       /* done */
+                       return asq_search_terminate(ac);
                }
 
-               /* request still pending, return to cycle again */
-               return LDB_SUCCESS;
-
-       default:
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               break;
+               return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
        }
 
-done:
-       handle->state = LDB_ASYNC_DONE;
-       return ret;
+       return LDB_ERR_OPERATIONS_ERROR;
 }
 
 static int asq_search(struct ldb_module *module, struct ldb_request *req)
 {
+       struct ldb_request *base_req;
        struct ldb_control *control;
        struct asq_context *ac;
-       struct ldb_handle *h;
+       int ret;
 
        /* check if there's a paged request control */
        control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
@@ -405,67 +343,37 @@ static int asq_search(struct ldb_module *module, struct ldb_request *req)
                return ldb_next_request(module, req);
        }
 
-       req->handle = NULL;
-
-       if (!req->callback || !req->context) {
-               ldb_set_errstring(module->ldb,
-                                 "Async interface called with NULL callback function or NULL context");
+       ac = asq_context_init(module, req);
+       if (!ac) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       h = init_handle(req, module);
-       if (!h) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       /* check the search is well formed */
+       if (req->op.search.scope != LDB_SCOPE_BASE) {
+               ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
+               return asq_search_terminate(ac);
        }
-       ac = talloc_get_type(h->private_data, struct asq_context);
 
        ac->asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
        if (!ac->asq_ctrl) {
                return LDB_ERR_PROTOCOL_ERROR;
        }
 
-       req->handle = h;
-
-       return asq_search_continue(h);
-}
-
-static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
-       int ret;
-
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       ret = asq_build_first_request(ac, &base_req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
        }
 
-       if (type == LDB_WAIT_ALL) {
-               while (handle->state != LDB_ASYNC_DONE) {
-                       ret = asq_search_continue(handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-               }
-
-               return handle->status;
-       }
+       ac->step = ASQ_SEARCH_BASE;
 
-       return asq_search_continue(handle);
+       return ldb_request(module->ldb, base_req);
 }
 
 static int asq_init(struct ldb_module *module)
 {
-       struct ldb_request *req;
        int ret;
 
-       req = talloc_zero(module, struct ldb_request);
-       if (req == NULL) {
-               ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Out of memory!\n");
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       req->operation = LDB_REQ_REGISTER_CONTROL;
-       req->op.reg_control.oid = LDB_CONTROL_ASQ_OID;
-
-       ret = ldb_request(module->ldb, req);
+       ret = ldb_mod_register_control(module, LDB_CONTROL_ASQ_OID);
        if (ret != LDB_SUCCESS) {
                ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
        }
@@ -476,6 +384,5 @@ static int asq_init(struct ldb_module *module)
 const struct ldb_module_ops ldb_asq_module_ops = {
        .name              = "asq",
        .search            = asq_search,
-       .wait              = asq_wait,
        .init_context      = asq_init
 };
index a59e81becdd4e50eb764484eba6b2ae1a27254ce..abb1d4ca1af66a4ea10db59e9acea69c6d848a8a 100644 (file)
@@ -2,7 +2,7 @@
    ldb database library
 
    Copyright (C) Andrew Tridgell 2005
-   Copyright (C) Simo Sorce 2006
+   Copyright (C) Simo Sorce 2006-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -173,38 +173,53 @@ failed:
 */
 
 struct operational_context {
-
        struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
+       struct ldb_request *req;
 
        const char * const *attrs;
 };
 
-static int operational_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int operational_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct operational_context *ac;
+       int ret;
 
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
-       }
+       ac = talloc_get_type(req->context, struct operational_context);
 
-       ac = talloc_get_type(context, struct operational_context);
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
 
-       if (ares->type == LDB_REPLY_ENTRY) {
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
                /* for each record returned post-process to add any derived
                   attributes that have been asked for */
-               if (operational_search_post_process(ac->module, ares->message, ac->attrs) != 0) {
-                       goto error;
+               ret = operational_search_post_process(ac->module,
+                                                       ares->message,
+                                                       ac->attrs);
+               if (ret != 0) {
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
                }
-       }
+               return ldb_module_send_entry(ac->req, ares->message);
 
-       return ac->up_callback(ldb, ac->up_context, ares);
+       case LDB_REPLY_REFERRAL:
+               /* ignore referrals */
+               break;
+
+       case LDB_REPLY_DONE:
+
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, LDB_SUCCESS);
+       }
 
-error:
        talloc_free(ares);
-       return LDB_ERR_OPERATIONS_ERROR;
+       return LDB_SUCCESS;
 }
 
 static int operational_search(struct ldb_module *module, struct ldb_request *req)
@@ -212,9 +227,8 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
        struct operational_context *ac;
        struct ldb_request *down_req;
        const char **search_attrs = NULL;
-       int i, a, ret;
-
-       req->handle = NULL;
+       int i, a;
+       int ret;
 
        ac = talloc(req, struct operational_context);
        if (ac == NULL) {
@@ -222,21 +236,10 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
        }
 
        ac->module = module;
-       ac->up_context = req->context;
-       ac->up_callback = req->callback;
+       ac->req = req;
        ac->attrs = req->op.search.attrs;
 
-       down_req = talloc_zero(req, struct ldb_request);
-       if (down_req == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       down_req->operation = req->operation;
-       down_req->op.search.base = req->op.search.base;
-       down_req->op.search.scope = req->op.search.scope;
-       down_req->op.search.tree = req->op.search.tree;
-
-       /*  FIXME: I hink we should copy the tree and keep the original
+       /*  FIXME: We must copy the tree and keep the original
         *  unmodified. SSS */
        /* replace any attributes in the parse tree that are
           searchable, but are stored using a different name in the
@@ -264,27 +267,26 @@ static int operational_search(struct ldb_module *module, struct ldb_request *req
                        }
                }
        }
-       
-       /* use new set of attrs if any */
-       if (search_attrs) down_req->op.search.attrs = search_attrs;
-       else down_req->op.search.attrs = req->op.search.attrs;
-       
-       down_req->controls = req->controls;
-
-       down_req->context = ac;
-       down_req->callback = operational_callback;
-       ldb_set_timeout_from_prev_req(module->ldb, req, down_req);
 
-       /* perform the search */
-       ret = ldb_next_request(module, down_req);
+       /* use new set of attrs if any */
+       if (search_attrs == NULL) {
+               search_attrs = req->op.search.attrs;
+       }
 
-       /* do not free down_req as the call results may be linked to it,
-        * it will be freed when the upper level request get freed */
-       if (ret == LDB_SUCCESS) {
-               req->handle = down_req->handle;
+       ret = ldb_build_search_req_ex(&down_req, module->ldb, ac,
+                                       req->op.search.base,
+                                       req->op.search.scope,
+                                       req->op.search.tree,
+                                       (const char * const *)search_attrs,
+                                       req->controls,
+                                       ac, operational_callback,
+                                       req);
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       return ret;
+       /* perform the search */
+       return ldb_next_request(module, down_req);
 }
 
 static int operational_init(struct ldb_module *ctx)
index b62b1f92cbd7d0271fffbbef452664bfb89662fe..d3bb83bbcd9ec6bbe8a568784b8b226b0252b8cc 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Simo Sorce  2005-2006
+   Copyright (C) Simo Sorce  2005-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -51,9 +51,8 @@ struct results_store {
        char *cookie;
        time_t timestamp;
 
-       struct results_store *prev;
        struct results_store *next;
-       
+
        struct message_store *first;
        struct message_store *last;
        int num_entries;
@@ -62,8 +61,6 @@ struct results_store {
        struct message_store *last_ref;
 
        struct ldb_control **controls;
-
-       struct ldb_request *req;
 };
 
 struct private_data {
@@ -73,20 +70,25 @@ struct private_data {
        
 };
 
-int store_destructor(struct results_store *store)
+int store_destructor(struct results_store *del)
 {
-       if (store->prev) {
-               store->prev->next = store->next;
-       }
-       if (store->next) {
-               store->next->prev = store->prev;
+       struct private_data *priv = del->priv;
+       struct results_store *loop;
+
+       if (priv->store == del) {
+               priv->store = del->next;
+               return 0;
        }
 
-       if (store == store->priv->store) {
-               store->priv->store = NULL;
+       for (loop = priv->store; loop; loop = loop->next) {
+               if (loop->next == del) {
+                       loop->next = del->next;
+                       return 0;
+               }
        }
 
-       return 0;
+       /* is not in list ? */
+       return -1;
 }
 
 static struct results_store *new_store(struct private_data *priv)
@@ -116,10 +118,7 @@ static struct results_store *new_store(struct private_data *priv)
        newr->first_ref = NULL;
        newr->controls = NULL;
 
-       /* put this entry as first */
-       newr->prev = NULL;
        newr->next = priv->store;
-       if (priv->store != NULL) priv->store->prev = newr;
        priv->store = newr;
 
        talloc_set_destructor(newr, store_destructor);
@@ -129,101 +128,164 @@ static struct results_store *new_store(struct private_data *priv)
 
 struct paged_context {
        struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
-       int size;
+       struct ldb_request *req;
 
        struct results_store *store;
+       int size;
+       struct ldb_control **controls;
 };
 
-static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
-                                           void *context,
-                                           int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+static int paged_results(struct paged_context *ac)
 {
-       struct paged_context *ac;
-       struct ldb_handle *h;
+       struct ldb_paged_control *paged;
+       struct message_store *msg;
+       int i, num_ctrls, ret;
 
-       h = talloc_zero(mem_ctx, struct ldb_handle);
-       if (h == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               return NULL;
+       if (ac->store == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       h->module = module;
+       while (ac->store->num_entries > 0 && ac->size > 0) {
+               msg = ac->store->first;
+               ret = ldb_module_send_entry(ac->req, msg->r->message);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
 
-       ac = talloc_zero(h, struct paged_context);
-       if (ac == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               talloc_free(h);
-               return NULL;
+               ac->store->first = msg->next;
+               talloc_free(msg);
+               ac->store->num_entries--;
+               ac->size--;
        }
 
-       h->private_data = (void *)ac;
+       while (ac->store->first_ref != NULL) {
+               msg = ac->store->first_ref;
+               ret = ldb_module_send_referral(ac->req, msg->r->referral);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
 
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
+               ac->store->first_ref = msg->next;
+               talloc_free(msg);
+       }
 
-       ac->module = module;
-       ac->up_context = context;
-       ac->up_callback = callback;
+       /* return result done */
+       num_ctrls = 1;
+       i = 0;
+
+       if (ac->store->controls != NULL) {
+               while (ac->store->controls[i]) i++; /* counting */
+
+               num_ctrls += i;
+       }
+
+       ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls +1);
+       if (ac->controls == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       ac->controls[num_ctrls] = NULL;
+
+       for (i = 0; i < (num_ctrls -1); i++) {
+               ac->controls[i] = talloc_reference(ac->controls, ac->store->controls[i]);
+       }
+
+       ac->controls[i] = talloc(ac->controls, struct ldb_control);
+       if (ac->controls[i] == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       return h;
+       ac->controls[i]->oid = talloc_strdup(ac->controls[i],
+                                               LDB_CONTROL_PAGED_RESULTS_OID);
+       if (ac->controls[i]->oid == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ac->controls[i]->critical = 0;
+
+       paged = talloc(ac->controls[i], struct ldb_paged_control);
+       if (paged == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+
+       ac->controls[i]->data = paged;
+
+       if (ac->size > 0) {
+               paged->size = 0;
+               paged->cookie = NULL;
+               paged->cookie_len = 0;
+       } else {
+               paged->size = ac->store->num_entries;
+               paged->cookie = talloc_strdup(paged, ac->store->cookie);
+               paged->cookie_len = strlen(paged->cookie) + 1;
+       }
+
+       return LDB_SUCCESS;
 }
 
-static int paged_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int paged_search_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
-       struct paged_context *ac = NULL;
+       struct paged_context *ac ;
+       struct message_store *msg_store;
+       int ret;
 
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
+       ac = talloc_get_type(req->context, struct paged_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
 
-       ac = talloc_get_type(context, struct paged_context);
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
+               msg_store = talloc(ac->store, struct message_store);
+               if (msg_store == NULL) {
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+               msg_store->next = NULL;
+               msg_store->r = talloc_steal(msg_store, ares);
 
-       if (ares->type == LDB_REPLY_ENTRY) {
                if (ac->store->first == NULL) {
-                       ac->store->first = ac->store->last = talloc(ac->store, struct message_store);
+                       ac->store->first = msg_store;
                } else {
-                       ac->store->last->next = talloc(ac->store, struct message_store);
-                       ac->store->last = ac->store->last->next;
-               }
-               if (ac->store->last == NULL) {
-                       goto error;
+                       ac->store->last->next = msg_store;
                }
+               ac->store->last = msg_store;
 
                ac->store->num_entries++;
 
-               ac->store->last->r = talloc_steal(ac->store->last, ares);
-               ac->store->last->next = NULL;
-       }
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               msg_store = talloc(ac->store, struct message_store);
+               if (msg_store == NULL) {
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
+               }
+               msg_store->next = NULL;
+               msg_store->r = talloc_steal(msg_store, ares);
 
-       if (ares->type == LDB_REPLY_REFERRAL) {
                if (ac->store->first_ref == NULL) {
-                       ac->store->first_ref = ac->store->last_ref = talloc(ac->store, struct message_store);
+                       ac->store->first_ref = msg_store;
                } else {
-                       ac->store->last_ref->next = talloc(ac->store, struct message_store);
-                       ac->store->last_ref = ac->store->last_ref->next;
-               }
-               if (ac->store->last_ref == NULL) {
-                       goto error;
+                       ac->store->last_ref->next = msg_store;
                }
+               ac->store->last_ref = msg_store;
 
-               ac->store->last_ref->r = talloc_steal(ac->store->last, ares);
-               ac->store->last_ref->next = NULL;
-       }
+               break;
 
-       if (ares->type == LDB_REPLY_DONE) {
+       case LDB_REPLY_DONE:
                ac->store->controls = talloc_move(ac->store, &ares->controls);
-               talloc_free(ares);
+               ret = paged_results(ac);
+               return ldb_module_done(ac->req, ac->controls,
+                                       ares->response, ret);
        }
 
        return LDB_SUCCESS;
-
-error:
-       talloc_free(ares);
-       return LDB_ERR_OPERATIONS_ERROR;
 }
 
 static int paged_search(struct ldb_module *module, struct ldb_request *req)
@@ -232,8 +294,8 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
        struct private_data *private_data;
        struct ldb_paged_control *paged_ctrl;
        struct ldb_control **saved_controls;
+       struct ldb_request *search_req;
        struct paged_context *ac;
-       struct ldb_handle *h;
        int ret;
 
        /* check if there's a paged request control */
@@ -243,65 +305,57 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
                return ldb_next_request(module, req);
        }
 
-       private_data = talloc_get_type(module->private_data, struct private_data);
-
-       req->handle = NULL;
-
-       if (!req->callback || !req->context) {
-               ldb_set_errstring(module->ldb,
-                                 "Async interface called with NULL callback function or NULL context");
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
        paged_ctrl = talloc_get_type(control->data, struct ldb_paged_control);
        if (!paged_ctrl) {
                return LDB_ERR_PROTOCOL_ERROR;
        }
 
-       h = init_handle(req, module, req->context, req->callback);
-       if (!h) {
+       private_data = talloc_get_type(module->private_data, struct private_data);
+
+       ac = talloc_zero(req, struct paged_context);
+       if (ac == NULL) {
+               ldb_set_errstring(module->ldb, "Out of Memory");
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct paged_context);
 
+       ac->module = module;
+       ac->req = req;
        ac->size = paged_ctrl->size;
 
        /* check if it is a continuation search the store */
        if (paged_ctrl->cookie_len == 0) {
-               
-               ac->store = new_store(private_data);
-               if (ac->store == NULL) {
-                       talloc_free(h);
-                       return LDB_ERR_UNWILLING_TO_PERFORM;
+               if (paged_ctrl->size == 0) {
+                       return LDB_ERR_OPERATIONS_ERROR;
                }
 
-               ac->store->req = talloc(ac->store, struct ldb_request);
-               if (!ac->store->req)
+               ac->store = new_store(private_data);
+               if (ac->store == NULL) {
                        return LDB_ERR_OPERATIONS_ERROR;
+               }
 
-               ac->store->req->operation = req->operation;
-               ac->store->req->op.search.base = req->op.search.base;
-               ac->store->req->op.search.scope = req->op.search.scope;
-               ac->store->req->op.search.tree = req->op.search.tree;
-               ac->store->req->op.search.attrs = req->op.search.attrs;
-               ac->store->req->controls = req->controls;
+               ret = ldb_build_search_req_ex(&search_req, module->ldb, ac,
+                                               req->op.search.base,
+                                               req->op.search.scope,
+                                               req->op.search.tree,
+                                               req->op.search.attrs,
+                                               req->controls,
+                                               ac,
+                                               paged_search_callback,
+                                               req);
 
                /* save it locally and remove it from the list */
                /* we do not need to replace them later as we
                 * are keeping the original req intact */
-               if (!save_controls(control, ac->store->req, &saved_controls)) {
+               if (!save_controls(control, search_req, &saved_controls)) {
                        return LDB_ERR_OPERATIONS_ERROR;
                }
 
-               ac->store->req->context = ac;
-               ac->store->req->callback = paged_search_callback;
-               ldb_set_timeout_from_prev_req(module->ldb, req, ac->store->req);
-
-               ret = ldb_next_request(module, ac->store->req);
+               return ldb_next_request(module, search_req);
 
        } else {
                struct results_store *current = NULL;
 
+               /* TODO: age out old outstanding requests */
                for (current = private_data->store; current; current = current->next) {
                        if (strcmp(current->cookie, paged_ctrl->cookie) == 0) {
                                current->timestamp = time(NULL);
@@ -309,249 +363,52 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
                        }
                }
                if (current == NULL) {
-                       talloc_free(h);
                        return LDB_ERR_UNWILLING_TO_PERFORM;
                }
 
                ac->store = current;
-               ret = LDB_SUCCESS;
-       }
-
-       req->handle = h;
-
-       /* check if it is an abandon */
-       if (ac->size == 0) {
-               talloc_free(ac->store);
-               h->status = LDB_SUCCESS;
-               h->state = LDB_ASYNC_DONE;
-               return LDB_SUCCESS;
-       }
-
-       /* TODO: age out old outstanding requests */
-
-       return ret;
-
-}
-
-static int paged_results(struct ldb_handle *handle)
-{
-       struct paged_context *ac;
-       struct ldb_paged_control *paged;
-       struct ldb_reply *ares;
-       struct message_store *msg;
-       int i, num_ctrls, ret;
-
-       ac = talloc_get_type(handle->private_data, struct paged_context);
-
-       if (ac->store == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
 
-       while (ac->store->num_entries > 0 && ac->size > 0) {
-               msg = ac->store->first;
-               ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       handle->state = LDB_ASYNC_DONE;
-                       return ret;
+               /* check if it is an abandon */
+               if (ac->size == 0) {
+                       return ldb_module_done(req, NULL, NULL,
+                                                               LDB_SUCCESS);
                }
 
-               ac->store->first = msg->next;
-               talloc_free(msg);
-               ac->store->num_entries--;
-               ac->size--;
-       }
-
-       handle->state = LDB_ASYNC_DONE;
-
-       while (ac->store->first_ref != NULL) {
-               msg = ac->store->first_ref;
-               ret = ac->up_callback(ac->module->ldb, ac->up_context, msg->r);
+               ret = paged_results(ac);
                if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       handle->state = LDB_ASYNC_DONE;
-                       return ret;
+                       return ldb_module_done(req, NULL, NULL, ret);
                }
-
-               ac->store->first_ref = msg->next;
-               talloc_free(msg);
-       }
-
-       ares = talloc_zero(ac->store, struct ldb_reply);
-       if (ares == NULL) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
-       }
-       num_ctrls = 2;
-       i = 0;
-
-       if (ac->store->controls != NULL) {
-               ares->controls = ac->store->controls;
-               while (ares->controls[i]) i++; /* counting */
-
-               ares->controls = talloc_move(ares, &ac->store->controls);
-               num_ctrls += i;
-       }
-
-       ares->controls = talloc_realloc(ares, ares->controls, struct ldb_control *, num_ctrls);
-       if (ares->controls == NULL) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
+               return ldb_module_done(req, ac->controls, NULL,
+                                                               LDB_SUCCESS);
        }
-
-       ares->controls[i] = talloc(ares->controls, struct ldb_control);
-       if (ares->controls[i] == NULL) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
-       }
-
-       ares->controls[i]->oid = talloc_strdup(ares->controls[i], LDB_CONTROL_PAGED_RESULTS_OID);
-       if (ares->controls[i]->oid == NULL) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
-       }
-               
-       ares->controls[i]->critical = 0;
-       ares->controls[i + 1] = NULL;
-
-       paged = talloc(ares->controls[i], struct ldb_paged_control);
-       if (paged == NULL) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
-       }
-       
-       ares->controls[i]->data = paged;
-
-       if (ac->size > 0) {
-               paged->size = 0;
-               paged->cookie = NULL;
-               paged->cookie_len = 0;
-       } else {
-               paged->size = ac->store->num_entries;
-               paged->cookie = talloc_strdup(paged, ac->store->cookie);
-               paged->cookie_len = strlen(paged->cookie) + 1;
-       }
-
-       ares->type = LDB_REPLY_DONE;
-
-       ret = ac->up_callback(ac->module->ldb, ac->up_context, ares);
-
-       handle->status = ret;
-
-       return ret;
-}
-
-static int paged_wait_once(struct ldb_handle *handle) {
-       struct paged_context *ac;
-       int ret;
-    
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (handle->state == LDB_ASYNC_DONE) {
-               return handle->status;
-       }
-
-       handle->state = LDB_ASYNC_PENDING;
-
-       ac = talloc_get_type(handle->private_data, struct paged_context);
-
-       if (ac->store->req->handle->state == LDB_ASYNC_DONE) {
-               /* if lower level is finished we do not need to call it anymore */
-               /* return all we have until size == 0 or we empty storage */
-               ret = paged_results(handle);
-
-               /* we are done, if num_entries is zero free the storage
-                * as that mean we delivered the last batch */
-               if (ac->store->num_entries == 0) {
-                       talloc_free(ac->store);
-               }
-
-               return ret;
-       }
-
-       ret = ldb_wait(ac->store->req->handle, LDB_WAIT_NONE);
-       if (ret != LDB_SUCCESS) {
-               handle->state = LDB_ASYNC_DONE;
-               handle->status = ret;
-               return ret;
-       }
-
-       handle->status = ret;
-
-       if (ac->store->num_entries >= ac->size ||
-           ac->store->req->handle->state == LDB_ASYNC_DONE) {
-
-               ret = paged_results(handle);
-
-               /* we are done, if num_entries is zero free the storage
-                * as that mean we delivered the last batch */
-               if (ac->store->num_entries == 0) {
-                       talloc_free(ac->store);
-               }
-       }
-
-       return ret;
-}
-
-static int paged_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
-       int ret;
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (type == LDB_WAIT_ALL) {
-               while (handle->state != LDB_ASYNC_DONE) {
-                       ret = paged_wait_once(handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-               }
-
-               return handle->status;
-       }
-
-       return paged_wait_once(handle);
 }
 
 static int paged_request_init(struct ldb_module *module)
 {
        struct private_data *data;
-       struct ldb_request *req;
        int ret;
 
        data = talloc(module, struct private_data);
        if (data == NULL) {
                return LDB_ERR_OTHER;
        }
-       
+
        data->next_free_id = 1;
        data->store = NULL;
        module->private_data = data;
 
-       req = talloc(module, struct ldb_request);
-       if (req == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       req->operation = LDB_REQ_REGISTER_CONTROL;
-       req->op.reg_control.oid = LDB_CONTROL_PAGED_RESULTS_OID;
-       req->controls = NULL;
-
-       ret = ldb_request(module->ldb, req);
+       ret = ldb_mod_register_control(module, LDB_CONTROL_PAGED_RESULTS_OID);
        if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_WARNING, "paged_request: Unable to register control with rootdse!\n");
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+                       "paged_request:"
+                       "Unable to register control with rootdse!\n");
        }
 
-       talloc_free(req);
        return ldb_next_init(module);
 }
 
 const struct ldb_module_ops ldb_paged_results_module_ops = {
        .name           = "paged_results",
        .search         = paged_search,
-       .wait           = paged_wait,
        .init_context   = paged_request_init
 };
index 40e87f70d60c83e124a5e7ae0877d941c6102c67..7a728e3bb0e3d090140a2cbaa919630e7ce3f496 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Simo Sorce  2005-2006
+   Copyright (C) Simo Sorce  2005-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -46,12 +46,7 @@ struct private_data {
 
 struct ps_context {
        struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
-
-       struct ldb_request *orig_req;
-
-       struct ldb_request *new_req;
+       struct ldb_request *req;
 
        bool pending;
 
@@ -59,51 +54,13 @@ struct ps_context {
        int num_referrals;
 };
 
-static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
-                                           void *context,
-                                           int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
+static int check_ps_continuation(struct ldb_request *req, struct ldb_reply *ares)
 {
        struct ps_context *ac;
-       struct ldb_handle *h;
-
-       h = talloc_zero(mem_ctx, struct ldb_handle);
-       if (h == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               return NULL;
-       }
-
-       h->module = module;
-
-       ac = talloc_zero(h, struct ps_context);
-       if (ac == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               talloc_free(h);
-               return NULL;
-       }
-
-       h->private_data = (void *)ac;
-
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
-
-       ac->module = module;
-       ac->up_context = context;
-       ac->up_callback = callback;
-
-       ac->pending = false;
-
-
-
-       ac->saved_referrals = NULL;
-       ac->num_referrals = 0;
-
-       return h;
-}
-
-static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac)
-{
        struct ldb_paged_control *rep_control, *req_control;
 
+       ac = talloc_get_type(req->context, struct ps_context);
+
        /* look up our paged control */
        if (!ares->controls || strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ares->controls[0]->oid) != 0) {
                /* something wrong here */
@@ -122,12 +79,12 @@ static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac)
        /* if there's a reply control we must find a request
         * control matching it */
 
-       if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, ac->new_req->controls[0]->oid) != 0) {
+       if (strcmp(LDB_CONTROL_PAGED_RESULTS_OID, req->controls[0]->oid) != 0) {
                /* something wrong here */
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       req_control = talloc_get_type(ac->new_req->controls[0]->data, struct ldb_paged_control);
+       req_control = talloc_get_type(req->controls[0]->data, struct ldb_paged_control);
 
        if (req_control->cookie) {
                talloc_free(req_control->cookie);
@@ -142,7 +99,7 @@ static int check_ps_continuation(struct ldb_reply *ares, struct ps_context *ac)
        return LDB_SUCCESS;
 }
 
-static int store_referral(char *referral, struct ps_context *ac)
+static int store_referral(struct ps_context *ac, char *referral)
 {
        ac->saved_referrals = talloc_realloc(ac, ac->saved_referrals, char *, ac->num_referrals + 2);
        if (!ac->saved_referrals) {
@@ -160,13 +117,14 @@ static int store_referral(char *referral, struct ps_context *ac)
        return LDB_SUCCESS;
 }
 
-static int send_referrals(struct ldb_context *ldb, struct ps_context *ac)
+static int send_referrals(struct ps_context *ac)
 {
        struct ldb_reply *ares;
+       int ret;
        int i;
 
        for (i = 0; i < ac->num_referrals; i++) {
-               ares = talloc_zero(ac, struct ldb_reply);
+               ares = talloc_zero(ac->req, struct ldb_reply);
                if (!ares) {
                        return LDB_ERR_OPERATIONS_ERROR;
                }
@@ -174,69 +132,87 @@ static int send_referrals(struct ldb_context *ldb, struct ps_context *ac)
                ares->type = LDB_REPLY_REFERRAL;
                ares->referral = ac->saved_referrals[i];
 
-               ac->up_callback(ldb, ac->up_context, ares);
+               ret = ldb_module_send_referral(ac->req, ares->referral);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
        }
 
        return LDB_SUCCESS;
 }
 
-static int ps_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int ps_next_request(struct ps_context *ac);
+
+static int ps_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
-       struct ps_context *ac = NULL;
-       int ret = LDB_ERR_OPERATIONS_ERROR;
+       struct ps_context *ac;
+       int ret;
 
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
-       }
+       ac = talloc_get_type(req->context, struct ps_context);
 
-       ac = talloc_get_type(context, struct ps_context);
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
 
        switch (ares->type) {
        case LDB_REPLY_ENTRY:
-               ac->up_callback(ldb, ac->up_context, ares);
+               ret = ldb_module_send_entry(ac->req, ares->message);
+               if (ret != LDB_SUCCESS) {
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
+               }
                break;
 
        case LDB_REPLY_REFERRAL:
-               ret = store_referral(ares->referral, ac);
+               ret = store_referral(ac, ares->referral);
                if (ret != LDB_SUCCESS) {
-                       goto error;
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
                }
                break;
 
        case LDB_REPLY_DONE:
-               ret = check_ps_continuation(ares, ac);
+
+               ret = check_ps_continuation(req, ares);
                if (ret != LDB_SUCCESS) {
-                       goto error;
+                       return ldb_module_done(ac->req, NULL, NULL, ret);
                }
-               if (!ac->pending) {
+
+               if (ac->pending) {
+
+                       ret = ps_next_request(ac);
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(ac->req,
+                                                       NULL, NULL, ret);
+                       }
+
+               } else {
+
                        /* send referrals */
-                       ret = send_referrals(ldb, ac);
+                       ret = send_referrals(ac);
                        if (ret != LDB_SUCCESS) {
-                               goto error;
+                               return ldb_module_done(ac->req,
+                                                       NULL, NULL, ret);
                        }
 
                        /* send REPLY_DONE */
-                       ac->up_callback(ldb, ac->up_context, ares);
+                       return ldb_module_done(ac->req, ares->controls,
+                                               ares->response, LDB_SUCCESS);
                }
                break;
-       default:
-               goto error;
        }
 
-       return LDB_SUCCESS;
-
-error:
        talloc_free(ares);
-       return ret;
+       return LDB_SUCCESS;
 }
 
 static int ps_search(struct ldb_module *module, struct ldb_request *req)
 {
        struct private_data *private_data;
-       struct ldb_paged_control *control;
        struct ps_context *ac;
-       struct ldb_handle *h;
 
        private_data = talloc_get_type(module->private_data, struct private_data);
 
@@ -248,216 +224,151 @@ static int ps_search(struct ldb_module *module, struct ldb_request *req)
                return ldb_next_request(module, req);
        }
 
-       if (!req->callback || !req->context) {
-               ldb_set_errstring(module->ldb,
-                                 "Async interface called with NULL callback function or NULL context");
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
-       h = init_handle(req, module, req->context, req->callback);
-       if (!h) {
+       ac = talloc_zero(req, struct ps_context);
+       if (ac == NULL) {
+               ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct ps_context);
-
-       ac->new_req = talloc(ac, struct ldb_request);
-       if (!ac->new_req) return LDB_ERR_OPERATIONS_ERROR;
-
-       ac->new_req->controls = talloc_array(ac->new_req, struct ldb_control *, 2);
-       if (!ac->new_req->controls) return LDB_ERR_OPERATIONS_ERROR;
-
-       ac->new_req->controls[0] = talloc(ac->new_req->controls, struct ldb_control);
-       if (!ac->new_req->controls[0]) return LDB_ERR_OPERATIONS_ERROR;
-
-       control = talloc(ac->new_req->controls[0], struct ldb_paged_control);
-       if (!control) return LDB_ERR_OPERATIONS_ERROR;
-
-       control->size = PS_DEFAULT_PAGE_SIZE;
-       control->cookie = NULL;
-       control->cookie_len = 0;
-
-       ac->new_req->controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
-       ac->new_req->controls[0]->critical = 1;
-       ac->new_req->controls[0]->data = control;
-
-       ac->new_req->controls[1] = NULL;
 
-       ac->new_req->operation = req->operation;
-       ac->new_req->op.search.base = req->op.search.base;
-       ac->new_req->op.search.scope = req->op.search.scope;
-       ac->new_req->op.search.tree = req->op.search.tree;
-       ac->new_req->op.search.attrs = req->op.search.attrs;
-       ac->new_req->context = ac;
-       ac->new_req->callback = ps_callback;
-       ldb_set_timeout_from_prev_req(module->ldb, req, ac->new_req);
-
-       req->handle = h;
+       ac->module = module;
+       ac->req = req;
+       ac->pending = false;
+       ac->saved_referrals = NULL;
+       ac->num_referrals = 0;
 
-       return ldb_next_request(module, ac->new_req);
+       return ps_next_request(ac);
 }
 
-static int ps_continuation(struct ldb_handle *handle)
-{
-       struct ps_context *ac;
+static int ps_next_request(struct ps_context *ac) {
 
-       if (!handle || !handle->private_data) {
+       struct ldb_paged_control *control;
+       struct ldb_control **controls;
+       struct ldb_request *new_req;
+       int ret;
+
+       controls = talloc_array(ac, struct ldb_control *, 2);
+       if (!controls) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ac = talloc_get_type(handle->private_data, struct ps_context);
-
-       /* reset the requests handle */
-       ac->new_req->handle = NULL;
-
-       return ldb_next_request(handle->module, ac->new_req);
-}
-
-static int ps_wait_once(struct ldb_handle *handle)
-{
-       struct ps_context *ac;
-       int ret;
-    
-       if (!handle || !handle->private_data) {
+       controls[0] = talloc(controls, struct ldb_control);
+       if (!controls[0]) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       if (handle->state == LDB_ASYNC_DONE) {
-               return handle->status;
+       control = talloc(controls[0], struct ldb_paged_control);
+       if (!control) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       handle->state = LDB_ASYNC_PENDING;
-       handle->status = LDB_SUCCESS;
-
-       ac = talloc_get_type(handle->private_data, struct ps_context);
-
-       ret = ldb_wait(ac->new_req->handle, LDB_WAIT_NONE);
+       control->size = PS_DEFAULT_PAGE_SIZE;
+       control->cookie = NULL;
+       control->cookie_len = 0;
 
+       controls[0]->oid = LDB_CONTROL_PAGED_RESULTS_OID;
+       controls[0]->critical = 1;
+       controls[0]->data = control;
+       controls[1] = NULL;
+
+       ret = ldb_build_search_req_ex(&new_req, ac->module->ldb, ac,
+                                       ac->req->op.search.base,
+                                       ac->req->op.search.scope,
+                                       ac->req->op.search.tree,
+                                       ac->req->op.search.attrs,
+                                       controls,
+                                       ac,
+                                       ps_callback,
+                                       ac->req);
        if (ret != LDB_SUCCESS) {
-               handle->status = ret;
-               goto done;
-       }
-
-       if (ac->new_req->handle->status != LDB_SUCCESS) {
-               handle->status = ac->new_req->handle->status;
-               goto done;
-       }
-
-       if (ac->new_req->handle->state != LDB_ASYNC_DONE) {
-               return LDB_SUCCESS;
-       } 
-
-       /* see if we need to send another request for the next batch */
-       if (ac->pending) {
-               ret = ps_continuation(handle);
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-
-               /* continue the search with the next request */
-               return LDB_SUCCESS;
+               return ret;
        }
+       talloc_steal(new_req, controls);
 
-       ret = LDB_SUCCESS;
-
-done:
-       handle->state = LDB_ASYNC_DONE;
-       return ret;
+       return ldb_next_request(ac->module, new_req);
 }
 
-static int ps_wait(struct ldb_handle *handle, enum ldb_wait_type type)
+static int check_supported_paged(struct ldb_request *req,
+                                struct ldb_reply *ares)
 {
-       int ret;
-
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
+       struct private_data *data;
 
-       if (type == LDB_WAIT_ALL) {
-               while (handle->state != LDB_ASYNC_DONE) {
-                       ret = ps_wait_once(handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-               }
+       data = talloc_get_type(req->context, struct private_data);
 
-               return handle->status;
+       if (!ares) {
+               return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
        }
-       return ps_wait_once(handle);
-}
 
-static int check_supported_paged(struct ldb_context *ldb, void *context, 
-                                struct ldb_reply *ares) 
-{
-       struct private_data *data;
-       data = talloc_get_type(context,
-                              struct private_data);
-       if (ares->type == LDB_REPLY_ENTRY) {
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
                if (ldb_msg_check_string_attribute(ares->message,
                                                   "supportedControl",
                                                   LDB_CONTROL_PAGED_RESULTS_OID)) {
                        data->paged_supported = true;
                }
+               break;
+
+       case LDB_REPLY_REFERRAL:
+               /* ignore */
+               break;
+
+       case LDB_REPLY_DONE:
+               return ldb_request_done(req, LDB_SUCCESS);
        }
+
+       talloc_free(ares);
        return LDB_SUCCESS;
 }
 
-
 static int ps_init(struct ldb_module *module)
 {
        static const char *attrs[] = { "supportedControl", NULL };
        struct private_data *data;
+       struct ldb_dn *base;
        int ret;
        struct ldb_request *req;
 
        data = talloc(module, struct private_data);
        if (data == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               return LDB_ERR_OTHER;
+               ldb_oom(module->ldb);
+               return LDB_ERR_OPERATIONS_ERROR;
        }
        module->private_data = data;
        data->paged_supported = false;
 
-       req = talloc(module, struct ldb_request);
-       if (req == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
+       base = ldb_dn_new(module, module->ldb, "");
+       if (base == NULL) {
+               ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
-
-       req->operation = LDB_SEARCH;
-       req->op.search.base = ldb_dn_new(req, module->ldb, "");
-       req->op.search.scope = LDB_SCOPE_BASE;
-
-       req->op.search.tree = ldb_parse_tree(req, "objectClass=*");
-       if (req->op.search.tree == NULL) {
-               ldb_set_errstring(module->ldb, "Unable to parse search expression");
-               talloc_free(req);
-               return LDB_ERR_OPERATIONS_ERROR;
+       ret = ldb_build_search_req(&req, module->ldb, module,
+                                  base, LDB_SCOPE_BASE,
+                                  "(objectClass=*)",
+                                  attrs, NULL,
+                                  data, check_supported_paged,
+                                  NULL);
+       if (ret != LDB_SUCCESS) {
+               return ret;
        }
 
-       req->op.search.attrs = attrs;
-       req->controls = NULL;
-       req->context = data;
-       req->callback = check_supported_paged;
-       ldb_set_timeout(module->ldb, req, 0); /* use default timeout */
-
        ret = ldb_next_request(module, req);
-       
        if (ret == LDB_SUCCESS) {
                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
        }
-       
-       talloc_free(req);
        if (ret != LDB_SUCCESS) {
                return ret;
        }
 
+       talloc_free(base);
+       talloc_free(req);
+
        return ldb_next_init(module);
 }
 
 _PUBLIC_ const struct ldb_module_ops ldb_paged_searches_module_ops = {
        .name           = "paged_searches",
        .search         = ps_search,
-       .wait           = ps_wait,
        .init_context   = ps_init
 };
index 65c044c0f4127c2ef0cf230854904adbc69660e2..62b8ce5112c1f6ef13a404b481f0fccff8bcef5a 100644 (file)
@@ -2,7 +2,7 @@
    ldb database library
 
    Copyright (C) Andrew Bartlet 2005
-   Copyright (C) Simo Sorce     2006
+   Copyright (C) Simo Sorce     2006-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
 
 #include "ldb_includes.h"
 
+struct rename_context {
+
+       struct ldb_module *module;
+       struct ldb_request *req;
+
+       struct ldb_reply *ares;
+};
+
 static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_message *msg, const char *name)
 {
        int i;
@@ -51,11 +59,38 @@ static struct ldb_message_element *rdn_name_find_attribute(const struct ldb_mess
        return NULL;
 }
 
+static int rdn_name_add_callback(struct ldb_request *req,
+                                struct ldb_reply *ares)
+{
+       struct rename_context *ac;
+
+       ac = talloc_get_type(req->context, struct rename_context);
+
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       if (ares->type != LDB_REPLY_DONE) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+
+       return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, LDB_SUCCESS);
+}
+
 static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
 {
        struct ldb_request *down_req;
+       struct rename_context *ac;
        struct ldb_message *msg;
        struct ldb_message_element *attribute;
+       const struct ldb_schema_attribute *a;
        const char *rdn_name;
        struct ldb_val rdn_val;
        int i, ret;
@@ -67,21 +102,22 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
                return ldb_next_request(module, req);
        }
 
-       down_req = talloc(req, struct ldb_request);
-       if (down_req == NULL) {
+       ac = talloc_zero(req, struct rename_context);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       *down_req = *req;
+       ac->module = module;
+       ac->req = req;
 
-       down_req->op.add.message = msg = ldb_msg_copy_shallow(down_req, req->op.add.message);
+       msg = ldb_msg_copy_shallow(req, req->op.add.message);
        if (msg == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
        rdn_name = ldb_dn_get_rdn_name(msg->dn);
        if (rdn_name == NULL) {
-               talloc_free(down_req);
+               talloc_free(ac);
                return LDB_ERR_OPERATIONS_ERROR;
        }
        
@@ -93,7 +129,7 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
        }
 
        if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
-               talloc_free(down_req);
+               talloc_free(ac);
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
@@ -101,14 +137,16 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
 
        if (!attribute) {
                if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
-                       talloc_free(down_req);
+                       talloc_free(ac);
                        return LDB_ERR_OPERATIONS_ERROR;
                }
        } else {
-               const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(module->ldb, rdn_name);
+               a = ldb_schema_attribute_by_name(module->ldb, rdn_name);
 
                for (i = 0; i < attribute->num_values; i++) {
-                       if (a->syntax->comparison_fn(module->ldb, msg, &rdn_val, &attribute->values[i]) == 0) {
+                       ret = a->syntax->comparison_fn(module->ldb, msg,
+                                       &rdn_val, &attribute->values[i]);
+                       if (ret == 0) {
                                /* overwrite so it matches in case */
                                attribute->values[i] = rdn_val;
                                break;
@@ -118,218 +156,166 @@ static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
                        ldb_debug_set(module->ldb, LDB_DEBUG_FATAL, 
                                      "RDN mismatch on %s: %s (%s)", 
                                      ldb_dn_get_linearized(msg->dn), rdn_name, rdn_val.data);
-                       talloc_free(down_req);
+                       talloc_free(ac);
                        /* Match AD's error here */
                        return LDB_ERR_INVALID_DN_SYNTAX;
                }
        }
 
-       /* go on with the call chain */
-       ret = ldb_next_request(module, down_req);
-
-       /* do not free down_req as the call results may be linked to it,
-        * it will be freed when the upper level request get freed */
-       if (ret == LDB_SUCCESS) {
-               req->handle = down_req->handle;
+       ret = ldb_build_add_req(&down_req, module->ldb, req,
+                               msg,
+                               req->controls,
+                               ac, rdn_name_add_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return ret;
        }
 
-       return ret;
-}
-
-struct rename_context {
+       talloc_steal(down_req, msg);
 
-       enum {RENAME_RENAME, RENAME_MODIFY} step;
-       struct ldb_request *orig_req;
-       struct ldb_request *down_req;
-       struct ldb_request *mod_req;
-};
+       /* go on with the call chain */
+       return ldb_next_request(module, down_req);
+}
 
-static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
+static int rdn_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
-       struct ldb_handle *h;
        struct rename_context *ac;
 
-       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
+       ac = talloc_get_type(req->context, struct rename_context);
 
-       /* do not manipulate our control entries */
-       if (ldb_dn_is_special(req->op.rename.newdn)) {
-               return ldb_next_request(module, req);
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
-
-       h = talloc_zero(req, struct ldb_handle);
-       if (h == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
        }
 
-       h->module = module;
-
-       ac = talloc_zero(h, struct rename_context);
-       if (ac == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       /* the only supported reply right now is a LDB_REPLY_DONE */
+       if (ares->type != LDB_REPLY_DONE) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
        }
 
-       h->private_data = (void *)ac;
-
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
-
-       ac->orig_req = req;
-       ac->down_req = talloc(req, struct ldb_request);
-       if (ac->down_req == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       *(ac->down_req) = *req;
-
-       ac->step = RENAME_RENAME;
-
-       req->handle = h;
-
-       /* rename first, modify "name" if rename is ok */
-       return ldb_next_request(module, ac->down_req);
+       /* send saved controls eventually */
+       return ldb_module_done(ac->req, ac->ares->controls,
+                               ac->ares->response, LDB_SUCCESS);
 }
 
-static int rdn_name_rename_do_mod(struct ldb_handle *h) {
-
+static int rdn_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
        struct rename_context *ac;
+       struct ldb_request *mod_req;
        const char *rdn_name;
        struct ldb_val rdn_val;
        struct ldb_message *msg;
+       int ret;
 
-       ac = talloc_get_type(h->private_data, struct rename_context);
+       ac = talloc_get_type(req->context, struct rename_context);
 
-       ac->mod_req = talloc_zero(ac, struct ldb_request);
+       if (!ares) {
+               goto error;
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
 
-       ac->mod_req->operation = LDB_MODIFY;
-       ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req);
-       if (msg == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
+       /* the only supported reply right now is a LDB_REPLY_DONE */
+       if (ares->type != LDB_REPLY_DONE) {
+               goto error;
        }
 
-       msg->dn = ldb_dn_copy(msg, ac->orig_req->op.rename.newdn);
+       /* save reply for caller */
+       ac->ares = talloc_steal(ac, ares);
+
+       msg = ldb_msg_new(ac);
+       if (msg == NULL) {
+               goto error;
+       }
+       msg->dn = ldb_dn_copy(msg, ac->req->op.rename.newdn);
        if (msg->dn == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
-
-       rdn_name = ldb_dn_get_rdn_name(ac->orig_req->op.rename.newdn);
+       rdn_name = ldb_dn_get_rdn_name(ac->req->op.rename.newdn);
        if (rdn_name == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
        
-       rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->orig_req->op.rename.newdn));
+       rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(ac->req->op.rename.newdn));
        
        if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
        if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
        if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
        if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
-               return LDB_ERR_OPERATIONS_ERROR;
+               goto error;
        }
 
-       ldb_set_timeout_from_prev_req(h->module->ldb, ac->orig_req, ac->mod_req);
-
-       ac->step = RENAME_MODIFY;
+       ret = ldb_build_mod_req(&mod_req, ac->module->ldb,
+                               ac, msg, NULL,
+                               ac, rdn_modify_callback,
+                               req);
+       if (ret != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, NULL, NULL, ret);
+       }
+       talloc_steal(mod_req, msg);
 
        /* do the mod call */
-       return ldb_request(h->module->ldb, ac->mod_req);
+       return ldb_request(ac->module->ldb, mod_req);
+
+error:
+       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
 }
 
-static int rdn_name_wait_once(struct ldb_handle *handle)
+static int rdn_name_rename(struct ldb_module *module, struct ldb_request *req)
 {
        struct rename_context *ac;
+       struct ldb_request *down_req;
        int ret;
-    
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (handle->state == LDB_ASYNC_DONE) {
-               return handle->status;
-       }
 
-       handle->state = LDB_ASYNC_PENDING;
-       handle->status = LDB_SUCCESS;
-
-       ac = talloc_get_type(handle->private_data, struct rename_context);
-
-       switch(ac->step) {
-       case RENAME_RENAME:
-               ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-               if (ac->down_req->handle->status != LDB_SUCCESS) {
-                       handle->status = ac->down_req->handle->status;
-                       goto done;
-               }
-
-               if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
-                       return LDB_SUCCESS;
-               }
-
-               /* rename operation done */
-               return rdn_name_rename_do_mod(handle);
-
-       case RENAME_MODIFY:
-               ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
-               if (ret != LDB_SUCCESS) {
-                       handle->status = ret;
-                       goto done;
-               }
-               if (ac->mod_req->handle->status != LDB_SUCCESS) {
-                       handle->status = ac->mod_req->handle->status;
-                       goto done;
-               }
-
-               if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
-                       return LDB_SUCCESS;
-               }
-
-               break;
+       ldb_debug(module->ldb, LDB_DEBUG_TRACE, "rdn_name_rename\n");
 
-       default:
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               goto done;
+       /* do not manipulate our control entries */
+       if (ldb_dn_is_special(req->op.rename.newdn)) {
+               return ldb_next_request(module, req);
        }
 
-       ret = LDB_SUCCESS;
-
-done:
-       handle->state = LDB_ASYNC_DONE;
-       return ret;
-}
-
-static int rdn_name_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
-       int ret;
-       if (!handle || !handle->private_data) {
+       ac = talloc_zero(req, struct rename_context);
+       if (ac == NULL) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       if (type == LDB_WAIT_ALL) {
-               while (handle->state != LDB_ASYNC_DONE) {
-                       ret = rdn_name_wait_once(handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-               }
+       ac->module = module;
+       ac->req = req;
 
-               return handle->status;
+       ret = ldb_build_rename_req(&down_req,
+                                  module->ldb,
+                                  ac,
+                                  req->op.rename.olddn,
+                                  req->op.rename.newdn,
+                                  req->controls,
+                                  ac,
+                                  rdn_rename_callback,
+                                  req);
+
+       if (ret != LDB_SUCCESS) {
+               return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       return rdn_name_wait_once(handle);
+       /* rename first, modify "name" if rename is ok */
+       return ldb_next_request(module, down_req);
 }
 
 const struct ldb_module_ops ldb_rdn_name_module_ops = {
        .name              = "rdn_name",
        .add               = rdn_name_add,
        .rename            = rdn_name_rename,
-       .wait              = rdn_name_wait
 };
index 746befa559208bb368a0a4bf875d5eb46b617da8..64d60f370cf7111099bfcf3f95b1dfbc64c86e77 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    ldb database library
 
-   Copyright (C) Simo Sorce  2005
+   Copyright (C) Simo Sorce  2005-2008
 
      ** NOTE! The following LGPL license applies to the ldb
      ** library. This does NOT imply that all of Samba is released
@@ -43,8 +43,6 @@ struct opaque {
 
 struct sort_context {
        struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_reply *);
 
        char *attributeName;
        char *orderingRule;
@@ -53,7 +51,6 @@ struct sort_context {
        struct ldb_request *req;
        struct ldb_message **msgs;
        char **referrals;
-       struct ldb_control **controls;
        int num_msgs;
        int num_refs;
 
@@ -61,40 +58,6 @@ struct sort_context {
        int sort_result;
 };
 
-static struct ldb_handle *init_handle(void *mem_ctx, struct ldb_module *module,
-                                           void *context,
-                                           int (*callback)(struct ldb_context *, void *, struct ldb_reply *))
-{
-       struct sort_context *ac;
-       struct ldb_handle *h;
-
-       h = talloc_zero(mem_ctx, struct ldb_handle);
-       if (h == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               return NULL;
-       }
-
-       h->module = module;
-
-       ac = talloc_zero(h, struct sort_context);
-       if (ac == NULL) {
-               ldb_set_errstring(module->ldb, "Out of Memory");
-               talloc_free(h);
-               return NULL;
-       }
-
-       h->private_data = (void *)ac;
-
-       h->state = LDB_ASYNC_INIT;
-       h->status = LDB_SUCCESS;
-
-       ac->module = module;
-       ac->up_context = context;
-       ac->up_callback = callback;
-
-       return h;
-}
-
 static int build_response(void *mem_ctx, struct ldb_control ***ctrls, int result, const char *desc)
 {
        struct ldb_control **controls;
@@ -142,7 +105,7 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo
        struct sort_context *ac = talloc_get_type(opaque, struct sort_context);
        struct ldb_message_element *el1, *el2;
 
-       if (ac->sort_result != 0) {
+       if (!ac || ac->sort_result != 0) {
                /* an error occurred previously,
                 * let's exit the sorting by returning always 0 */
                return 0;
@@ -154,7 +117,7 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo
        if (!el1 || !el2) {
                /* the attribute was not found return and
                 * set an error */
-               ac->sort_result = 53;
+               ac->sort_result = LDB_ERR_UNWILLING_TO_PERFORM;
                return 0;
        }
 
@@ -164,51 +127,111 @@ static int sort_compare(struct ldb_message **msg1, struct ldb_message **msg2, vo
        return ac->a->syntax->comparison_fn(ac->module->ldb, ac, &el1->values[0], &el2->values[0]);
 }
 
-static int server_sort_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
+static int server_sort_results(struct sort_context *ac)
 {
-       struct sort_context *ac = NULL;
-       
-       if (!context || !ares) {
-               ldb_set_errstring(ldb, "NULL Context or Result in callback");
-               goto error;
-       }       
+       struct ldb_reply *ares;
+       int i, ret;
+
+       ac->a = ldb_schema_attribute_by_name(ac->module->ldb, ac->attributeName);
+       ac->sort_result = 0;
+
+       ldb_qsort(ac->msgs, ac->num_msgs,
+                 sizeof(struct ldb_message *),
+                 ac, (ldb_qsort_cmp_fn_t)sort_compare);
+
+       if (ac->sort_result != LDB_SUCCESS) {
+               return ac->sort_result;
+       }
+
+       for (i = 0; i < ac->num_msgs; i++) {
+               ares = talloc_zero(ac, struct ldb_reply);
+               if (!ares) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               ares->type = LDB_REPLY_ENTRY;
+               ares->message = talloc_move(ares, &ac->msgs[i]);
+
+               ret = ldb_module_send_entry(ac->req, ares->message);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       for (i = 0; i < ac->num_refs; i++) {
+               ares = talloc_zero(ac, struct ldb_reply);
+               if (!ares) {
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+
+               ares->type = LDB_REPLY_REFERRAL;
+               ares->referral = talloc_move(ares, &ac->referrals[i]);
+
+               ret = ldb_module_send_referral(ac->req, ares->referral);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       return LDB_SUCCESS;
+}
+
+static int server_sort_search_callback(struct ldb_request *req, struct ldb_reply *ares)
+{
+       struct sort_context *ac;
+       int ret;
 
-               ac = talloc_get_type(context, struct sort_context);
+       ac = talloc_get_type(req->context, struct sort_context);
 
-       if (ares->type == LDB_REPLY_ENTRY) {
+       if (!ares) {
+               return ldb_module_done(ac->req, NULL, NULL,
+                                       LDB_ERR_OPERATIONS_ERROR);
+       }
+       if (ares->error != LDB_SUCCESS) {
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ares->error);
+       }
+
+       switch (ares->type) {
+       case LDB_REPLY_ENTRY:
                ac->msgs = talloc_realloc(ac, ac->msgs, struct ldb_message *, ac->num_msgs + 2);
                if (! ac->msgs) {
-                       goto error;
+                       talloc_free(ares);
+                       ldb_oom(ac->module->ldb);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
                }
 
-               ac->msgs[ac->num_msgs + 1] = NULL;
-
-               ac->msgs[ac->num_msgs] = talloc_move(ac->msgs, &ares->message);
+               ac->msgs[ac->num_msgs] = talloc_steal(ac->msgs, ares->message);
                ac->num_msgs++;
-       }
+               ac->msgs[ac->num_msgs] = NULL;
 
-       if (ares->type == LDB_REPLY_REFERRAL) {
+               break;
+
+       case LDB_REPLY_REFERRAL:
                ac->referrals = talloc_realloc(ac, ac->referrals, char *, ac->num_refs + 2);
                if (! ac->referrals) {
-                       goto error;
+                       talloc_free(ares);
+                       ldb_oom(ac->module->ldb);
+                       return ldb_module_done(ac->req, NULL, NULL,
+                                               LDB_ERR_OPERATIONS_ERROR);
                }
 
-               ac->referrals[ac->num_refs + 1] = NULL;
-               ac->referrals[ac->num_refs] = talloc_move(ac->referrals, &ares->referral);
-
+               ac->referrals[ac->num_refs] = talloc_steal(ac->referrals, ares->referral);
                ac->num_refs++;
-       }
+               ac->referrals[ac->num_refs] = NULL;
 
-       if (ares->type == LDB_REPLY_DONE) {
-               ac->controls = talloc_move(ac, &ares->controls);
+               break;
+
+       case LDB_REPLY_DONE:
+
+               ret = server_sort_results(ac);
+               return ldb_module_done(ac->req, ares->controls,
+                                       ares->response, ret);
        }
 
        talloc_free(ares);
        return LDB_SUCCESS;
-
-error:
-       talloc_free(ares);
-       return LDB_ERR_OPERATIONS_ERROR;
 }
 
 static int server_sort_search(struct ldb_module *module, struct ldb_request *req)
@@ -216,8 +239,9 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req
        struct ldb_control *control;
        struct ldb_server_sort_control **sort_ctrls;
        struct ldb_control **saved_controls;
+       struct ldb_control **controls;
+       struct ldb_request *down_req;
        struct sort_context *ac;
-       struct ldb_handle *h;
        int ret;
 
        /* check if there's a paged request control */
@@ -227,19 +251,14 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req
                return ldb_next_request(module, req);
        }
 
-       req->handle = NULL;
-
-       if (!req->callback || !req->context) {
-               ldb_set_errstring(module->ldb,
-                                 "Async interface called with NULL callback function or NULL context");
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
-       h = init_handle(req, module, req->context, req->callback);
-       if (!h) {
+       ac = talloc_zero(req, struct sort_context);
+       if (ac == NULL) {
+               ldb_oom(module->ldb);
                return LDB_ERR_OPERATIONS_ERROR;
        }
-       ac = talloc_get_type(h->private_data, struct sort_context);
+
+       ac->module = module;
+       ac->req = req;
 
        sort_ctrls = talloc_get_type(control->data, struct ldb_server_sort_control *);
        if (!sort_ctrls) {
@@ -251,26 +270,20 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req
                
        if (sort_ctrls[1] != NULL) {
                if (control->critical) {
-                       struct ldb_reply *ares;
-
-                       ares = talloc_zero(req, struct ldb_reply);
-                       if (!ares)
-                               return LDB_ERR_OPERATIONS_ERROR;
 
-                       /* 53 = unwilling to perform */
-                       ares->type = LDB_REPLY_DONE;
-                       if ((ret = build_response(ares, &ares->controls, 53, "sort control is not complete yet")) != LDB_SUCCESS) {
-                               return ret;
+                       /* callback immediately */
+                       ret = build_response(req, &controls,
+                                            LDB_ERR_UNWILLING_TO_PERFORM,
+                                            "sort control is not complete yet");
+                       if (ret != LDB_SUCCESS) {
+                               return ldb_module_done(req, NULL, NULL,
+                                                   LDB_ERR_OPERATIONS_ERROR);
                        }
 
-                       h->status = LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
-                       h->state = LDB_ASYNC_DONE;
-                       ret = ac->up_callback(module->ldb, ac->up_context, ares);
-
-                       return ret;
+                       return ldb_module_done(req, controls, NULL, ret);
                } else {
                        /* just pass the call down and don't do any sorting */
-                       ldb_next_request(module, req);
+                       return ldb_next_request(module, req);
                }
        }
 
@@ -278,181 +291,45 @@ static int server_sort_search(struct ldb_module *module, struct ldb_request *req
        ac->orderingRule = sort_ctrls[0]->orderingRule;
        ac->reverse = sort_ctrls[0]->reverse;
 
-       ac->req = talloc(req, struct ldb_request);
-       if (!ac->req)
+       ret = ldb_build_search_req_ex(&down_req, module->ldb, ac,
+                                       req->op.search.base,
+                                       req->op.search.scope,
+                                       req->op.search.tree,
+                                       req->op.search.attrs,
+                                       req->controls,
+                                       ac,
+                                       server_sort_search_callback,
+                                       req);
+       if (ret != LDB_SUCCESS) {
                return LDB_ERR_OPERATIONS_ERROR;
-
-       ac->req->operation = req->operation;
-       ac->req->op.search.base = req->op.search.base;
-       ac->req->op.search.scope = req->op.search.scope;
-       ac->req->op.search.tree = req->op.search.tree;
-       ac->req->op.search.attrs = req->op.search.attrs;
-       ac->req->controls = req->controls;
+       }
 
        /* save it locally and remove it from the list */
        /* we do not need to replace them later as we
         * are keeping the original req intact */
-       if (!save_controls(control, ac->req, &saved_controls)) {
+       if (!save_controls(control, down_req, &saved_controls)) {
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       ac->req->context = ac;
-       ac->req->callback = server_sort_search_callback;
-       ldb_set_timeout_from_prev_req(module->ldb, req, ac->req);
-
-       req->handle = h;
-
-       return ldb_next_request(module, ac->req);
-}
-
-static int server_sort_results(struct ldb_handle *handle)
-{
-       struct sort_context *ac;
-       struct ldb_reply *ares;
-       int i, ret;
-
-       ac = talloc_get_type(handle->private_data, struct sort_context);
-
-       ac->a = ldb_schema_attribute_by_name(ac->module->ldb, ac->attributeName);
-       ac->sort_result = 0;
-
-       ldb_qsort(ac->msgs, ac->num_msgs,
-                 sizeof(struct ldb_message *),
-                 ac, (ldb_qsort_cmp_fn_t)sort_compare);
-
-       for (i = 0; i < ac->num_msgs; i++) {
-               ares = talloc_zero(ac, struct ldb_reply);
-               if (!ares) {
-                       handle->status = LDB_ERR_OPERATIONS_ERROR;
-                       return handle->status;
-               }
-
-               ares->type = LDB_REPLY_ENTRY;
-               ares->message = talloc_move(ares, &ac->msgs[i]);
-               
-               handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
-               if (handle->status != LDB_SUCCESS) {
-                       return handle->status;
-               }
-       }
-
-       for (i = 0; i < ac->num_refs; i++) {
-               ares = talloc_zero(ac, struct ldb_reply);
-               if (!ares) {
-                       handle->status = LDB_ERR_OPERATIONS_ERROR;
-                       return handle->status;
-               }
-
-               ares->type = LDB_REPLY_REFERRAL;
-               ares->referral = talloc_move(ares, &ac->referrals[i]);
-               
-               handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
-               if (handle->status != LDB_SUCCESS) {
-                       return handle->status;
-               }
-       }
-
-       ares = talloc_zero(ac, struct ldb_reply);
-       if (!ares) {
-               handle->status = LDB_ERR_OPERATIONS_ERROR;
-               return handle->status;
-       }
-
-       ares->type = LDB_REPLY_DONE;
-       ares->controls = talloc_move(ares, &ac->controls);
-               
-       handle->status = ac->up_callback(ac->module->ldb, ac->up_context, ares);
-       if (handle->status != LDB_SUCCESS) {
-               return handle->status;
-       }
-
-       if ((ret = build_response(ac, &ac->controls, ac->sort_result, "sort control is not complete yet")) != LDB_SUCCESS) {
-               return ret;
-       }
-
-       return LDB_SUCCESS;
-}
-
-static int server_sort_wait_once(struct ldb_handle *handle)
-{
-       struct sort_context *ac;
-       int ret;
-    
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       ac = talloc_get_type(handle->private_data, struct sort_context);
-
-       ret = ldb_wait(ac->req->handle, LDB_WAIT_NONE);
-
-       if (ret != LDB_SUCCESS) {
-               handle->status = ret;
-               return ret;
-       }
-               
-       handle->state = ac->req->handle->state;
-       handle->status = ac->req->handle->status;
-
-       if (handle->status != LDB_SUCCESS) {
-               return handle->status;
-       }
-
-       if (handle->state == LDB_ASYNC_DONE) {
-               ret = server_sort_results(handle);
-       }
-
-       return ret;
-}
-
-static int server_sort_wait(struct ldb_handle *handle, enum ldb_wait_type type)
-{
-       int ret;
-       if (!handle || !handle->private_data) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       if (type == LDB_WAIT_ALL) {
-               while (handle->state != LDB_ASYNC_DONE) {
-                       ret = server_sort_wait_once(handle);
-                       if (ret != LDB_SUCCESS) {
-                               return ret;
-                       }
-               }
-
-               return handle->status;
-       }
-
-       return server_sort_wait_once(handle);
+       return ldb_next_request(module, down_req);
 }
 
 static int server_sort_init(struct ldb_module *module)
 {
-       struct ldb_request *req;
        int ret;
 
-       req = talloc(module, struct ldb_request);
-       if (req == NULL) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-
-       req->operation = LDB_REQ_REGISTER_CONTROL;
-       req->op.reg_control.oid = LDB_CONTROL_SERVER_SORT_OID;
-       req->controls = NULL;
-
-       ret = ldb_request(module->ldb, req);
+       ret = ldb_mod_register_control(module, LDB_CONTROL_SERVER_SORT_OID);
        if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_WARNING, "server_sort: Unable to register control with rootdse!\n");
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING,
+                       "server_sort:"
+                       "Unable to register control with rootdse!\n");
        }
 
-       talloc_free(req);
        return ldb_next_init(module);
 }
 
 const struct ldb_module_ops ldb_server_sort_module_ops = {
        .name              = "server_sort",
        .search            = server_sort_search,
-       .wait              = server_sort_wait,
        .init_context      = server_sort_init
 };