r21496: A number of ldb control and LDAP changes, surrounding the
[kamenim/samba.git] / source4 / lib / ldb / modules / asq.c
index 75ef4a487eae2e08761ba2bf00bdaa191cff36bf..0c31727909e3a3cae0985238ff6348a4132cf448 100644 (file)
 #include "includes.h"
 #include "ldb/include/includes.h"
 
-#define ASQ_CTRL_SUCCESS                       0
-#define ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX      21
-#define ASQ_CTRL_UNWILLING_TO_PERFORM          53
-#define ASQ_CTRL_AFFECTS_MULTIPLE_DSA          71
+struct asq_context {
 
-struct asq_async_context {
-
-       enum {ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
+       enum {ASQ_INIT, ASQ_SEARCH_BASE, ASQ_SEARCH_MULTI} step;
 
        struct ldb_module *module;
-       void *up_context;
-       int (*up_callback)(struct ldb_context *, void *, struct ldb_async_result *);
+       struct ldb_request *orig_req;
+
+       struct ldb_asq_control *asq_ctrl;
 
        const char * const *req_attrs;
        char *req_attribute;
-       int asq_ret;
+       enum {
+               ASQ_CTRL_SUCCESS                        = 0,
+               ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX       = 21,
+               ASQ_CTRL_UNWILLING_TO_PERFORM           = 53,
+               ASQ_CTRL_AFFECTS_MULTIPLE_DSA           = 71
+       } asq_ret;
 
        struct ldb_request *base_req;
-       struct ldb_async_result *base_res;
+       struct ldb_reply *base_res;
 
        struct ldb_request **reqs;
        int num_reqs;
@@ -63,24 +64,22 @@ struct asq_async_context {
        struct ldb_control **controls;
 };
 
-static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *module,
-                                           void *context,
-                                           int (*callback)(struct ldb_context *, void *, struct ldb_async_result *))
+static struct ldb_handle *init_handle(struct ldb_request *req, struct ldb_module *module)
 {
-       struct asq_async_context *ac;
-       struct ldb_async_handle *h;
+       struct asq_context *ac;
+       struct ldb_handle *h;
 
-       h = talloc_zero(mem_ctx, struct ldb_async_handle);
+       h = talloc_zero(req, struct ldb_handle);
        if (h == NULL) {
-               ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
+               ldb_set_errstring(module->ldb, "Out of Memory");
                return NULL;
        }
 
        h->module = module;
 
-       ac = talloc_zero(h, struct asq_async_context);
+       ac = talloc_zero(h, struct asq_context);
        if (ac == NULL) {
-               ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
+               ldb_set_errstring(module->ldb, "Out of Memory");
                talloc_free(h);
                return NULL;
        }
@@ -90,26 +89,29 @@ static struct ldb_async_handle *init_handle(void *mem_ctx, struct ldb_module *mo
        h->state = LDB_ASYNC_INIT;
        h->status = LDB_SUCCESS;
 
+       ac->step = ASQ_INIT;
        ac->module = module;
-       ac->up_context = context;
-       ac->up_callback = callback;
+       ac->orig_req = req;
 
        return h;
 }
 
-static int asq_terminate(struct ldb_async_handle *handle)
+static int asq_terminate(struct ldb_handle *handle)
 {
-       struct asq_async_context *ac;
-       struct ldb_async_result *ares;
+       struct asq_context *ac;
+       struct ldb_reply *ares;
        struct ldb_asq_control *asq;
        int i;
 
-       ac = talloc_get_type(handle->private_data, struct asq_async_context);
+       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_async_result);
+       ares = talloc_zero(ac, struct ldb_reply);
        if (ares == NULL)
                return LDB_ERR_OPERATIONS_ERROR;
 
@@ -117,7 +119,7 @@ static int asq_terminate(struct ldb_async_handle *handle)
 
        if (ac->controls) {
                for (i = 0; ac->controls[i]; i++);
-               ares->controls = talloc_steal(ares, ac->controls);
+               ares->controls = talloc_move(ares, &ac->controls);
        } else {
                i = 0;
        }
@@ -144,25 +146,28 @@ static int asq_terminate(struct ldb_async_handle *handle)
 
        ares->controls[i + 1] = NULL;
 
-       ac->up_callback(ac->module->ldb, ac->up_context, ares);
+       ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares);
 
        return LDB_SUCCESS;
 }
 
-static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+static int asq_base_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
 {
-       struct asq_async_context *ac;
+       struct asq_context *ac;
 
        if (!context || !ares) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+               ldb_set_errstring(ldb, "NULL Context or Result in callback");
                goto error;
        }
 
-       ac = talloc_get_type(context, struct asq_async_context);
+       ac = talloc_get_type(context, struct asq_context);
+       if (ac == NULL) {
+               goto error;
+       }
 
        /* we are interested only in the single reply (base search) we receive here */
        if (ares->type == LDB_REPLY_ENTRY) {
-               ac->base_res = talloc_steal(ac, ares);
+               ac->base_res = talloc_move(ac, &ares);
        } else {
                talloc_free(ares);
        }
@@ -173,23 +178,26 @@ error:
        return LDB_ERR_OPERATIONS_ERROR;
 }
 
-static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+static int asq_reqs_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
 {
-       struct asq_async_context *ac;
+       struct asq_context *ac;
 
        if (!context || !ares) {
-               ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+               ldb_set_errstring(ldb, "NULL Context or Result in callback");
                goto error;
        }
 
-       ac = talloc_get_type(context, struct asq_async_context);
+       ac = talloc_get_type(context, struct asq_context);
+       if (ac == NULL) {
+               goto error;
+       }
 
        /* we are interested only in the single reply (base search) we receive here */
        if (ares->type == LDB_REPLY_ENTRY) {
 
                /* pass the message up to the original callback as we
                 * do not have to elaborate on it any further */
-               return ac->up_callback(ac->module->ldb, ac->up_context, ares);
+               return ac->orig_req->callback(ac->module->ldb, ac->orig_req->context, ares);
                
        } else { /* ignore any REFERRAL or DONE reply */
                talloc_free(ares);
@@ -201,94 +209,42 @@ error:
        return LDB_ERR_OPERATIONS_ERROR;
 }
 
-static int asq_search(struct ldb_module *module, struct ldb_request *req)
+static int asq_build_first_request(struct asq_context *ac)
 {
-       struct ldb_control *control;
-       struct ldb_asq_control *asq_ctrl;
-       struct asq_async_context *ac;
-       struct ldb_async_handle *h;
        char **base_attrs;
-       int ret;
-
-       /* check if there's a paged request control */
-       control = get_control_from_list(req->controls, LDB_CONTROL_ASQ_OID);
-       if (control == NULL) {
-               /* not found go on */
-               return ldb_next_request(module, req);
-       }
-
-       req->async.handle = NULL;
-
-       if (!req->async.callback || !req->async.context) {
-               ldb_set_errstring(module->ldb, talloc_asprintf(module,
-                                 "Async interface called with NULL callback function or NULL context"));
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       
-       asq_ctrl = talloc_get_type(control->data, struct ldb_asq_control);
-       if (!asq_ctrl) {
-               return LDB_ERR_PROTOCOL_ERROR;
-       }
-
-       h = init_handle(req, module, req->async.context, req->async.callback);
-       if (!h) {
-               return LDB_ERR_OPERATIONS_ERROR;
-       }
-       ac = talloc_get_type(h->private_data, struct asq_async_context);
-
-       req->async.handle = h;
 
-       /* check the search is well formed */
-       if (req->op.search.scope != LDB_SCOPE_BASE) {
-               ac->asq_ret = ASQ_CTRL_UNWILLING_TO_PERFORM;
-               return asq_terminate(h);
-       }
-
-       ac->req_attrs = req->op.search.attrs;
-       ac->req_attribute = talloc_strdup(ac, asq_ctrl->source_attribute);
-       if (ac->req_attribute == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
+       ac->base_req = talloc_zero(ac, struct ldb_request);
+       if (ac->base_req == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
-       /* get the object to retrieve the DNs to search */
-       ac->base_req = talloc_zero(req, struct ldb_request);
-       if (ac->base_req == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
-       ac->base_req->operation = req->operation;
-       ac->base_req->op.search.base = req->op.search.base;
+       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 = req->op.search.tree;
+       ac->base_req->op.search.tree = ac->orig_req->op.search.tree;
        base_attrs = talloc_array(ac->base_req, char *, 2);
-       if (base_attrs == NULL)
-               return LDB_ERR_OPERATIONS_ERROR;
-       base_attrs[0] = talloc_strdup(base_attrs, 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;
+       if (base_attrs == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
-       ac->base_req->async.context = ac;
-       ac->base_req->async.callback = asq_base_callback;
-       ldb_set_timeout_from_prev_req(module->ldb, req, ac->base_req);
+       base_attrs[0] = talloc_strdup(base_attrs, ac->asq_ctrl->source_attribute);
+       if (base_attrs[0] == NULL) return LDB_ERR_OPERATIONS_ERROR;
 
-       ac->step = ASQ_SEARCH_BASE;
+       base_attrs[1] = NULL;
+       ac->base_req->op.search.attrs = (const char * const *)base_attrs;
 
-       ret = ldb_request(module->ldb, ac->base_req);
-
-       if (ret != LDB_SUCCESS) {
-               return ret;
-       }
+       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);
 
        return LDB_SUCCESS;
 }
 
-static int asq_async_requests(struct ldb_async_handle *handle) {
-       struct asq_async_context *ac;
+static int asq_build_multiple_requests(struct asq_context *ac, struct ldb_handle *handle)
+{
        struct ldb_message_element *el;
        int i;
 
-       ac = talloc_get_type(handle->private_data, struct asq_async_context);
-
        /* 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) {
@@ -296,7 +252,6 @@ static int asq_async_requests(struct ldb_async_handle *handle) {
                return asq_terminate(handle);
        }
 
-       /* build up the requests call chain */
        ac->num_reqs = el->num_values;
        ac->cur_req = 0;
        ac->reqs = talloc_array(ac, struct ldb_request *, ac->num_reqs);
@@ -310,8 +265,8 @@ static int asq_async_requests(struct ldb_async_handle *handle) {
                if (ac->reqs[i] == NULL)
                        return LDB_ERR_OPERATIONS_ERROR;
                ac->reqs[i]->operation = LDB_SEARCH;
-               ac->reqs[i]->op.search.base = ldb_dn_explode(ac->reqs[i], (const char *)el->values[i].data);
-               if (ac->reqs[i]->op.search.base == NULL) {
+               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)) {
                        ac->asq_ret = ASQ_CTRL_INVALID_ATTRIBUTE_SYNTAX;
                        return asq_terminate(handle);
                }
@@ -319,19 +274,17 @@ static int asq_async_requests(struct ldb_async_handle *handle) {
                ac->reqs[i]->op.search.tree = ac->base_req->op.search.tree;
                ac->reqs[i]->op.search.attrs = ac->req_attrs;
 
-               ac->reqs[i]->async.context = ac;
-               ac->reqs[i]->async.callback = asq_reqs_callback;
+               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]);
        }
 
-       ac->step = ASQ_SEARCH_MULTI;
-
        return LDB_SUCCESS;
 }
 
-static int asq_async_wait_none(struct ldb_async_handle *handle)
+static int asq_search_continue(struct ldb_handle *handle)
 {
-       struct asq_async_context *ac;
+       struct asq_context *ac;
        int ret;
     
        if (!handle || !handle->private_data) {
@@ -342,78 +295,148 @@ static int asq_async_wait_none(struct ldb_async_handle *handle)
                return handle->status;
        }
 
-       handle->state = LDB_ASYNC_PENDING;
-       handle->status = LDB_SUCCESS;
+       ac = talloc_get_type(handle->private_data, struct asq_context);
+       if (ac == NULL) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
 
-       ac = talloc_get_type(handle->private_data, struct asq_async_context);
+       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);
 
-       switch (ac->step) {
        case ASQ_SEARCH_BASE:
-               ret = ldb_async_wait(ac->base_req->async.handle, LDB_WAIT_NONE);
+
+               ret = ldb_wait(ac->base_req->handle, LDB_WAIT_NONE);
                
                if (ret != LDB_SUCCESS) {
                        handle->status = ret;
                        goto done;
                }
 
-               if (ac->base_req->async.handle->status != LDB_SUCCESS) {
-                       handle->status = ac->base_req->async.handle->status;
+               if (ac->base_req->handle->status != LDB_SUCCESS) {
+                       handle->status = ac->base_req->handle->status;
                        goto done;
                }
-               if (ac->base_req->async.handle->state != LDB_ASYNC_DONE) {
-                       return LDB_SUCCESS;
-               }
-
-               ret = asq_async_requests(handle);
 
-       case ASQ_SEARCH_MULTI:
+               if (ac->base_req->handle->state == LDB_ASYNC_DONE) {
 
-               if (ac->reqs[ac->cur_req]->async.handle == NULL) {
-                       ret = ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
+                       /* 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]);
                }
 
-               ret = ldb_async_wait(ac->reqs[ac->cur_req]->async.handle, LDB_WAIT_NONE);
+               /* request still pending, return to cycle again */
+               return LDB_SUCCESS;
+
+       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]->async.handle->status != LDB_SUCCESS) {
-                       handle->status = ac->reqs[ac->cur_req]->async.handle->status;
+               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]->async.handle->state == LDB_ASYNC_DONE) {
+               if (ac->reqs[ac->cur_req]->handle->state == LDB_ASYNC_DONE) {
                        ac->cur_req++;
-               }
 
-               if (ac->cur_req < ac->num_reqs) {
-                       return LDB_SUCCESS;
+                       if (ac->cur_req < ac->num_reqs) {
+                               return ldb_request(ac->module->ldb, ac->reqs[ac->cur_req]);
+                       }
+
+                       return asq_terminate(handle);
                }
 
-               return asq_terminate(handle);
+               /* request still pending, return to cycle again */
+               return LDB_SUCCESS;
 
        default:
                ret = LDB_ERR_OPERATIONS_ERROR;
-               goto done;
+               break;
        }
 
-       ret = LDB_SUCCESS;
-
 done:
        handle->state = LDB_ASYNC_DONE;
        return ret;
 }
 
-static int asq_async_wait_all(struct ldb_async_handle *handle)
+static int asq_search(struct ldb_module *module, struct ldb_request *req)
+{
+       struct ldb_control *control;
+       struct asq_context *ac;
+       struct ldb_handle *h;
+
+       /* check if there's a paged request control */
+       control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID);
+       if (control == NULL) {
+               /* not found go on */
+               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);
+       if (!h) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       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_all(struct ldb_handle *handle)
 {
        int ret;
 
        while (handle->state != LDB_ASYNC_DONE) {
-               ret = asq_async_wait_none(handle);
+               ret = asq_search_continue(handle);
                if (ret != LDB_SUCCESS) {
                        return ret;
                }
@@ -422,12 +445,12 @@ static int asq_async_wait_all(struct ldb_async_handle *handle)
        return handle->status;
 }
 
-static int asq_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
+static int asq_wait(struct ldb_handle *handle, enum ldb_wait_type type)
 {
        if (type == LDB_WAIT_ALL) {
-               return asq_async_wait_all(handle);
+               return asq_wait_all(handle);
        } else {
-               return asq_async_wait_none(handle);
+               return asq_search_continue(handle);
        }
 }
 
@@ -442,13 +465,12 @@ static int asq_init(struct ldb_module *module)
                return LDB_ERR_OPERATIONS_ERROR;
        }
 
-       req->operation = LDB_REQ_REGISTER;
-       req->op.reg.oid = LDB_CONTROL_ASQ_OID;
+       req->operation = LDB_REQ_REGISTER_CONTROL;
+       req->op.reg_control.oid = LDB_CONTROL_ASQ_OID;
 
        ret = ldb_request(module->ldb, req);
        if (ret != LDB_SUCCESS) {
-               ldb_debug(module->ldb, LDB_DEBUG_ERROR, "asq: Unable to register control with rootdse!\n");
-               return LDB_ERR_OTHER;
+               ldb_debug(module->ldb, LDB_DEBUG_WARNING, "asq: Unable to register control with rootdse!\n");
        }
 
        return ldb_next_init(module);
@@ -458,7 +480,7 @@ static int asq_init(struct ldb_module *module)
 static const struct ldb_module_ops asq_ops = {
        .name              = "asq",
        .search            = asq_search,
-       .async_wait        = asq_async_wait,
+       .wait              = asq_wait,
        .init_context      = asq_init
 };