summaryrefslogtreecommitdiff
path: root/source4/lib/ldb/ldb_ildap
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2006-02-22 01:31:35 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:51:59 -0500
commit00fe70e5b917769418f68eaa255d3a06a9a08ce7 (patch)
tree7fe1d0d71e1771a3365a5dfda3ec4058b1bb2de1 /source4/lib/ldb/ldb_ildap
parentf490434c0f1f8e63de478c6d65f264277257968a (diff)
downloadsamba-00fe70e5b917769418f68eaa255d3a06a9a08ce7.tar.gz
samba-00fe70e5b917769418f68eaa255d3a06a9a08ce7.tar.bz2
samba-00fe70e5b917769418f68eaa255d3a06a9a08ce7.zip
r13609: Get in the initial work on making ldb async
Currently only ldb_ildap is async, the plan is to first make all backend support the async calls, and then remove the sync functions from backends and keep the only in the API. Modules will need to be transformed along the way. Simo (This used to be commit 1e2c13b2d52de7c534493dd79a2c0596a3e8c1f5)
Diffstat (limited to 'source4/lib/ldb/ldb_ildap')
-rw-r--r--source4/lib/ldb/ldb_ildap/ldb_ildap.c912
1 files changed, 688 insertions, 224 deletions
diff --git a/source4/lib/ldb/ldb_ildap/ldb_ildap.c b/source4/lib/ldb/ldb_ildap/ldb_ildap.c
index a6a5822c9e..33d3954a73 100644
--- a/source4/lib/ldb/ldb_ildap/ldb_ildap.c
+++ b/source4/lib/ldb/ldb_ildap/ldb_ildap.c
@@ -2,6 +2,7 @@
ldb database library - ildap backend
Copyright (C) Andrew Tridgell 2005
+ Copyright (C) Simo Sorce 2006
** NOTE! The following LGPL license applies to the ldb
** library. This does NOT imply that all of Samba is released
@@ -32,6 +33,7 @@
#include "includes.h"
#include "ldb/include/includes.h"
+#include "lib/events/events.h"
#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
#include "lib/cmdline/popt_common.h"
@@ -43,6 +45,66 @@ struct ildb_private {
struct ldb_context *ldb;
};
+struct ildb_async_context {
+ struct ldb_module *module;
+ struct ldap_request *req;
+ void *context;
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *);
+};
+
+/*
+ convert a ldb_message structure to a list of ldap_mod structures
+ ready for ildap_add() or ildap_modify()
+*/
+static struct ldap_mod **ildb_msg_to_mods(void *mem_ctx, int *num_mods,
+ const struct ldb_message *msg, int use_flags)
+{
+ struct ldap_mod **mods;
+ unsigned int i;
+ int n = 0;
+
+ /* allocate maximum number of elements needed */
+ mods = talloc_array(mem_ctx, struct ldap_mod *, msg->num_elements+1);
+ if (!mods) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mods[0] = NULL;
+
+ for (i = 0; i < msg->num_elements; i++) {
+ const struct ldb_message_element *el = &msg->elements[i];
+
+ mods[n] = talloc(mods, struct ldap_mod);
+ if (!mods[n]) {
+ goto failed;
+ }
+ mods[n + 1] = NULL;
+ mods[n]->type = 0;
+ mods[n]->attrib = *el;
+ if (use_flags) {
+ switch (el->flags & LDB_FLAG_MOD_MASK) {
+ case LDB_FLAG_MOD_ADD:
+ mods[n]->type = LDAP_MODIFY_ADD;
+ break;
+ case LDB_FLAG_MOD_DELETE:
+ mods[n]->type = LDAP_MODIFY_DELETE;
+ break;
+ case LDB_FLAG_MOD_REPLACE:
+ mods[n]->type = LDAP_MODIFY_REPLACE;
+ break;
+ }
+ }
+ n++;
+ }
+
+ *num_mods = n;
+ return mods;
+
+failed:
+ talloc_free(mods);
+ return NULL;
+}
+
/*
map an ildap NTSTATUS to a ldb error code
@@ -60,330 +122,661 @@ static int ildb_map_error(struct ildb_private *ildb, NTSTATUS status)
return LDB_ERR_OPERATIONS_ERROR;
}
-/*
- rename a record
-*/
-static int ildb_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
+static void ildb_request_timeout(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data)
{
- TALLOC_CTX *local_ctx;
- struct ildb_private *ildb = module->private_data;
- int ret = 0;
- char *old_dn;
- char *newrdn, *parentdn;
- NTSTATUS status;
+ struct ldb_async_handle *handle = talloc_get_type(private_data, struct ldb_async_handle);
+ struct ildb_async_context *ac = talloc_get_type(handle->private_data, struct ildb_async_context);
- /* ignore ltdb specials */
- if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) {
- return LDB_SUCCESS;
+ if (ac->req->state == LDAP_REQUEST_PENDING) {
+ DLIST_REMOVE(ac->req->conn->pending, ac->req);
}
- local_ctx = talloc_named(ildb, 0, "ildb_rename local context");
- if (local_ctx == NULL) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto failed;
- }
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
- old_dn = ldb_dn_linearize(local_ctx, olddn);
- if (old_dn == NULL) {
- ret = LDB_ERR_INVALID_DN_SYNTAX;
- goto failed;
- }
+ return;
+}
- newrdn = talloc_asprintf(local_ctx, "%s=%s",
- newdn->components[0].name,
- ldb_dn_escape_value(ildb, newdn->components[0].value));
- if (newrdn == NULL) {
- ret = LDB_ERR_OPERATIONS_ERROR;
- goto failed;
- }
+static void ildb_async_callback(struct ldap_request *req)
+{
+ struct ldb_async_handle *handle = talloc_get_type(req->async.private_data, struct ldb_async_handle);
+ struct ildb_async_context *ac = talloc_get_type(handle->private_data, struct ildb_async_context);
+ struct ildb_private *ildb = ac->module->private_data;
+ NTSTATUS status;
+ int i;
- parentdn = ldb_dn_linearize(local_ctx, ldb_dn_get_parent(ildb, newdn));
- if (parentdn == NULL) {
- ret = LDB_ERR_INVALID_DN_SYNTAX;
- goto failed;
+ handle->status = LDB_SUCCESS;
+
+ if (!NT_STATUS_IS_OK(req->status)) {
+ handle->status = ildb_map_error(ildb, req->status);
+ return;
}
- status = ildap_rename(ildb->ldap, old_dn, newrdn, parentdn, True);
- ret = ildb_map_error(ildb, status);
+ if (req->num_replies < 1) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+
+ switch (req->type) {
-failed:
- talloc_free(local_ctx);
- return ret;
+ case LDAP_TAG_ModifyRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_AddRequest:
+ if (req->replies[0]->type != LDAP_TAG_AddResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_DelRequest:
+ if (req->replies[0]->type != LDAP_TAG_DelResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_ModifyDNRequest:
+ if (req->replies[0]->type != LDAP_TAG_ModifyDNResponse) {
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+ status = ldap_check_response(req->conn, &req->replies[0]->r.GeneralResult);
+ handle->status = ildb_map_error(ildb, status);
+ handle->state = LDB_ASYNC_DONE;
+ break;
+
+ case LDAP_TAG_SearchRequest:
+ /* loop over all messages */
+ for (i = 0; i < req->num_replies; i++) {
+ struct ldap_SearchResEntry *search;
+ struct ldb_async_result *ares = NULL;
+ struct ldap_message *msg;
+ int ret;
+
+ ares = talloc_zero(ac, struct ldb_async_result);
+ if (!ares) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+
+ msg = req->replies[i];
+ switch (msg->type) {
+
+ case LDAP_TAG_SearchResultDone:
+
+ status = ldap_check_response(req->conn, &msg->r.GeneralResult);
+ if (!NT_STATUS_IS_OK(status)) {
+ ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Error: %s\n" ,ldap_errstr(req->conn, status));
+ handle->status = ildb_map_error(ildb, status);
+ return;
+ }
+
+ if (msg->controls) {
+ ares->controls = talloc_steal(ares, msg->controls);
+ }
+ if (msg->r.SearchResultDone.resultcode) {
+ if (msg->r.SearchResultDone.errormessage) {
+ ldb_set_errstring(ac->module, talloc_strdup(ac->module, msg->r.SearchResultDone.errormessage));
+ }
+ }
+
+ handle->status = msg->r.SearchResultDone.resultcode;
+ handle->state = LDB_ASYNC_DONE;
+ ares->type = LDB_REPLY_DONE;
+ break;
+
+ case LDAP_TAG_SearchResultEntry:
+
+
+ ares->message = ldb_msg_new(ares);
+ if (!ares->message) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;;
+ return;
+ }
+
+ search = &(msg->r.SearchResultEntry);
+
+ ares->message->dn = ldb_dn_explode_or_special(ares->message, search->dn);
+ if (ares->message->dn == NULL) {
+ handle->status = LDB_ERR_OPERATIONS_ERROR;
+ return;
+ }
+ ares->message->num_elements = search->num_attributes;
+ ares->message->elements = talloc_steal(ares->message, search->attributes);
+
+ handle->status = LDB_SUCCESS;
+ handle->state = LDB_ASYNC_PENDING;
+ ares->type = LDB_REPLY_ENTRY;
+ break;
+
+ case LDAP_TAG_SearchResultReference:
+
+ ares->referral = talloc_strdup(ares, msg->r.SearchResultReference.referral);
+
+ handle->status = LDB_SUCCESS;
+ handle->state = LDB_ASYNC_PENDING;
+ ares->type = LDB_REPLY_REFERRAL;
+ break;
+
+ default:
+ /* TAG not handled, fail ! */
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
+
+ ret = ac->callback(ac->module->ldb, ac->context, ares);
+ if (ret) {
+ handle->status = ret;
+ }
+ }
+
+ talloc_free(req->replies);
+ req->replies = NULL;
+ req->num_replies = 0;
+
+ break;
+
+ default:
+ handle->status = LDB_ERR_PROTOCOL_ERROR;
+ return;
+ }
}
-/*
- delete a record
-*/
-static int ildb_delete(struct ldb_module *module, const struct ldb_dn *dn)
+static int ildb_request_send(struct ldb_module *module, struct ldap_message *msg,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
{
struct ildb_private *ildb = module->private_data;
- char *del_dn;
- int ret = 0;
- NTSTATUS status;
+ struct ildb_async_context *ildb_ac;
+ struct ldb_async_handle *h;
+ struct ldap_request *req;
- /* ignore ltdb specials */
- if (ldb_dn_is_special(dn)) {
- return LDB_SUCCESS;
+ h = talloc_zero(ildb->ldap, struct ldb_async_handle);
+ if (h == NULL) {
+ ldb_set_errstring(module, talloc_asprintf(module, "Out of Memory"));
+ return LDB_ERR_OPERATIONS_ERROR;
}
-
- del_dn = ldb_dn_linearize(ildb, dn);
- if (del_dn == NULL) {
- return LDB_ERR_INVALID_DN_SYNTAX;
+
+ ildb_ac = talloc(h, struct ildb_async_context);
+ if (ildb_ac == NULL) {
+ ldb_set_errstring(module, talloc_asprintf(module, "Out of Memory"));
+ talloc_free(h);
+ return LDB_ERR_OPERATIONS_ERROR;
}
- status = ildap_delete(ildb->ldap, del_dn);
- ret = ildb_map_error(ildb, status);
+ h->private_data = (void *)ildb_ac;
- talloc_free(del_dn);
+ req = ldap_request_send(ildb->ldap, msg);
+ if (req == NULL) {
+ ldb_set_errstring(module, talloc_asprintf(module, "async send request failed"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- return ret;
-}
+ ildb_ac->req = talloc_steal(ildb_ac, req);
+ ildb_ac->module = module;
+ ildb_ac->context = context;
+ ildb_ac->callback = callback;
+ req->async.fn = ildb_async_callback;
+ req->async.private_data = (void *)h;
-static void ildb_rootdse(struct ldb_module *module);
+ talloc_free(req->time_event);
+ req->time_event = NULL;
+ if (timeout) {
+ req->time_event = event_add_timed(req->conn->event.event_ctx, h,
+ timeval_current_ofs(timeout, 0),
+ ildb_request_timeout, ildb_ac);
+ }
+
+ *handle = h;
+
+ return LDB_SUCCESS;
+
+}
/*
- search for matching records using a ldb_parse_tree
-*/
-static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
+ search for matching records using an asynchronous function
+ */
+static int ildb_search_async(struct ldb_module *module, const struct ldb_dn *base,
enum ldb_scope scope, struct ldb_parse_tree *tree,
const char * const *attrs,
struct ldb_control **control_req,
- struct ldb_result **res)
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
{
struct ildb_private *ildb = module->private_data;
- int count, i;
- struct ldap_message **ldapres, *msg;
- struct ldap_Control **controls = NULL;
- char *search_base;
- NTSTATUS status;
+ struct ldap_message *msg;
+ int n;
- if (scope == LDB_SCOPE_DEFAULT) {
- scope = LDB_SCOPE_SUBTREE;
+ *handle = NULL;
+
+ if (!callback || !context) {
+ ldb_set_errstring(module, talloc_asprintf(module, "Async interface called with NULL callback function or NULL context"));
+ return LDB_ERR_OPERATIONS_ERROR;
}
+ if (tree == NULL) {
+ ldb_set_errstring(module, talloc_asprintf(module, "Invalid expression parse tree"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg = new_ldap_message(ildb);
+ if (msg == NULL) {
+ ldb_set_errstring(module, talloc_asprintf(module, "Out of Memory"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ msg->type = LDAP_TAG_SearchRequest;
+
if (base == NULL) {
- if (ildb->rootDSE == NULL) {
- ildb_rootdse(module);
- }
if (ildb->rootDSE != NULL) {
- search_base = talloc_strdup(ildb,
- ldb_msg_find_string(ildb->rootDSE,
- "defaultNamingContext", ""));
+ msg->r.SearchRequest.basedn =
+ talloc_strdup(msg, ldb_msg_find_string(ildb->rootDSE, "defaultNamingContext", ""));
} else {
- search_base = talloc_strdup(ildb, "");
+ msg->r.SearchRequest.basedn = talloc_strdup(msg, "");
}
} else {
- search_base = ldb_dn_linearize(ildb, base);
+ msg->r.SearchRequest.basedn = ldb_dn_linearize(msg, base);
}
- if (search_base == NULL) {
+ if (msg->r.SearchRequest.basedn == NULL) {
ldb_set_errstring(module, talloc_asprintf(module, "Unable to determine baseDN"));
- return LDB_ERR_OTHER;
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
}
- if (tree == NULL) {
- ldb_set_errstring(module, talloc_asprintf(module, "Invalid expression parse tree"));
- return LDB_ERR_OTHER;
+
+ if (scope == LDB_SCOPE_DEFAULT) {
+ msg->r.SearchRequest.scope = LDB_SCOPE_SUBTREE;
+ } else {
+ msg->r.SearchRequest.scope = scope;
}
+
+ msg->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ msg->r.SearchRequest.timelimit = 0;
+ msg->r.SearchRequest.sizelimit = 0;
+ msg->r.SearchRequest.attributesonly = 0;
+ msg->r.SearchRequest.tree = tree;
+
+ for (n = 0; attrs && attrs[n]; n++) /* noop */ ;
+ msg->r.SearchRequest.num_attributes = n;
+ msg->r.SearchRequest.attributes = discard_const(attrs);
+ msg->controls = control_req;
- (*res) = talloc(ildb, struct ldb_result);
- if (! *res) {
- return LDB_ERR_OTHER;
+ return ildb_request_send(module, msg, context, callback, timeout, handle);
+}
+
+struct ildb_sync_context {
+ struct ldb_result *res;
+ int status;
+ int done;
+};
+
+static int ildb_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+{
+ struct ldb_result *res;
+ int n;
+
+ if (!context) {
+ ldb_set_errstring(ldb->modules, talloc_asprintf(ldb, "NULL Context in callback"));
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ res = *((struct ldb_result **)context);
+
+ if (!res || !ares) {
+ goto error;
}
- (*res)->count = 0;
- (*res)->msgs = NULL;
- (*res)->controls = NULL;
- status = ildap_search_bytree(ildb->ldap, search_base, scope, tree, attrs, 0,
- (struct ldap_Control **)control_req,
- &controls,
- &ldapres);
- talloc_free(search_base);
- if (!NT_STATUS_IS_OK(status)) {
- ildb_map_error(ildb, status);
- return LDB_ERR_OTHER;
+ if (ares->type == LDB_REPLY_ENTRY) {
+ res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2);
+ if (! res->msgs) {
+ goto error;
+ }
+
+ res->msgs[res->count + 1] = NULL;
+
+ res->msgs[res->count] = talloc_steal(res->msgs, ares->message);
+ if (! res->msgs[res->count]) {
+ goto error;
+ }
+
+ res->count++;
}
- count = ildap_count_entries(ildb->ldap, ldapres);
- if (count == -1) {
- talloc_free(ldapres);
- return LDB_ERR_OTHER;
+ if (ares->type == LDB_REPLY_REFERRAL) {
+ if (res->refs) {
+ for (n = 0; res->refs[n]; n++) /*noop*/ ;
+ } else {
+ n = 0;
+ }
+
+ res->refs = talloc_realloc(res, res->refs, char *, n + 2);
+ if (! res->refs) {
+ goto error;
+ }
+
+ res->refs[n] = talloc_steal(res->refs, ares->referral);
+ res->refs[n + 1] = NULL;
}
- if (count == 0) {
- talloc_free(ldapres);
- return LDB_SUCCESS;
+ if (ares->type == LDB_REPLY_DONE) {
+ if (ares->controls) {
+ res->controls = talloc_steal(res, ares->controls);
+ if (! res->controls) {
+ goto error;
+ }
+ }
}
- (*res)->msgs = talloc_array(*res, struct ldb_message *, count + 1);
- if (! (*res)->msgs) {
- talloc_free(ldapres);
- return LDB_ERR_OTHER;
+ talloc_free(ares);
+ return LDB_SUCCESS;
+
+error:
+ talloc_free(ares);
+ talloc_free(res);
+ *((struct ldb_result **)context) = NULL;
+ return LDB_ERR_OPERATIONS_ERROR;
+}
+
+/*
+ search for matching records using a synchronous function
+ */
+static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
+ enum ldb_scope scope, struct ldb_parse_tree *tree,
+ const char * const *attrs,
+ struct ldb_control **control_req,
+ struct ldb_result **res)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_async_handle *handle;
+ int ret;
+
+ *res = talloc_zero(ildb, struct ldb_result);
+ if (! *res) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- (*res)->msgs[0] = NULL;
+ ret = ildb_search_async(module, base, scope, tree, attrs, control_req,
+ res, &ildb_search_sync_callback, ildb->ldap->timeout, &handle);
- /* loop over all messages */
- for (i=0;i<count;i++) {
- struct ldap_SearchResEntry *search;
+ if (ret != LDB_SUCCESS)
+ return ret;
- msg = ldapres[i];
- search = &msg->r.SearchResultEntry;
+ return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
+}
- (*res)->msgs[i] = talloc((*res)->msgs, struct ldb_message);
- if (!(*res)->msgs[i]) {
- goto failed;
- }
- (*res)->msgs[i+1] = NULL;
+/*
+ add a record
+*/
+static int ildb_add_async(struct ldb_module *module, const struct ldb_message *ldb_msg,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldap_message *msg;
+ struct ldap_mod **mods;
+ int i,n;
- (*res)->msgs[i]->dn = ldb_dn_explode_or_special((*res)->msgs[i], search->dn);
- if ((*res)->msgs[i]->dn == NULL) {
- goto failed;
- }
- (*res)->msgs[i]->num_elements = search->num_attributes;
- (*res)->msgs[i]->elements = talloc_steal((*res)->msgs[i], search->attributes);
- (*res)->msgs[i]->private_data = NULL;
+ *handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(ldb_msg->dn)) {
+ return LDB_SUCCESS;
}
- talloc_free(ldapres);
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- (*res)->count = count;
+ msg->type = LDAP_TAG_AddRequest;
- if (controls) {
- (*res)->controls = (struct ldb_control **)talloc_steal(*res, controls);
+ msg->r.AddRequest.dn = ldb_dn_linearize(msg, ldb_msg->dn);
+ if (msg->r.AddRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
- return LDB_SUCCESS;
+ mods = ildb_msg_to_mods(msg, &n, ldb_msg, 0);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
-failed:
- if (*res) talloc_free(*res);
- return LDB_ERR_OTHER;
+ msg->r.AddRequest.num_attributes = n;
+ msg->r.AddRequest.attributes = talloc_array(msg, struct ldb_message_element, n);
+ if (msg->r.AddRequest.attributes == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.AddRequest.attributes[i] = mods[i]->attrib;
+ }
+
+ return ildb_request_send(module, msg, context, callback, timeout, handle);
}
+static int ildb_add(struct ldb_module *module, const struct ldb_message *msg)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_async_handle *handle;
+ int ret;
+
+ ret = ildb_add_async(module, msg,
+ NULL, NULL, ildb->ldap->timeout, &handle);
+
+ if (ret != LDB_SUCCESS)
+ return ret;
+
+ return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
+}
/*
- convert a ldb_message structure to a list of ldap_mod structures
- ready for ildap_add() or ildap_modify()
+ modify a record
*/
-static struct ldap_mod **ildb_msg_to_mods(struct ldb_context *ldb,
- const struct ldb_message *msg, int use_flags)
+static int ildb_modify_async(struct ldb_module *module, const struct ldb_message *ldb_msg,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
{
+ struct ildb_private *ildb = module->private_data;
+ struct ldap_message *msg;
struct ldap_mod **mods;
- unsigned int i;
- int num_mods = 0;
+ int i,n;
- /* allocate maximum number of elements needed */
- mods = talloc_array(ldb, struct ldap_mod *, msg->num_elements+1);
- if (!mods) {
- errno = ENOMEM;
- return NULL;
+ *handle = NULL;
+
+ /* ignore ltdb specials */
+ if (ldb_dn_is_special(ldb_msg->dn)) {
+ return LDB_SUCCESS;
}
- mods[0] = NULL;
- for (i=0;i<msg->num_elements;i++) {
- const struct ldb_message_element *el = &msg->elements[i];
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- mods[num_mods] = talloc(ldb, struct ldap_mod);
- if (!mods[num_mods]) {
- goto failed;
- }
- mods[num_mods+1] = NULL;
- mods[num_mods]->type = 0;
- mods[num_mods]->attrib = *el;
- if (use_flags) {
- switch (el->flags & LDB_FLAG_MOD_MASK) {
- case LDB_FLAG_MOD_ADD:
- mods[num_mods]->type = LDAP_MODIFY_ADD;
- break;
- case LDB_FLAG_MOD_DELETE:
- mods[num_mods]->type = LDAP_MODIFY_DELETE;
- break;
- case LDB_FLAG_MOD_REPLACE:
- mods[num_mods]->type = LDAP_MODIFY_REPLACE;
- break;
- }
- }
- num_mods++;
+ msg->type = LDAP_TAG_ModifyRequest;
+
+ msg->r.ModifyRequest.dn = ldb_dn_linearize(msg, ldb_msg->dn);
+ if (msg->r.ModifyRequest.dn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
}
- return mods;
+ mods = ildb_msg_to_mods(msg, &n, ldb_msg, 1);
+ if (mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
-failed:
- talloc_free(mods);
- return NULL;
+ msg->r.ModifyRequest.num_mods = n;
+ msg->r.ModifyRequest.mods = talloc_array(msg, struct ldap_mod, n);
+ if (msg->r.ModifyRequest.mods == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ for (i = 0; i < n; i++) {
+ msg->r.ModifyRequest.mods[i] = *mods[i];
+ }
+
+ return ildb_request_send(module, msg, context, callback, timeout, handle);
}
+static int ildb_modify(struct ldb_module *module, const struct ldb_message *msg)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_async_handle *handle;
+ int ret;
+
+ ret = ildb_modify_async(module, msg,
+ NULL, NULL, ildb->ldap->timeout, &handle);
+
+ if (ret != LDB_SUCCESS)
+ return ret;
+
+ return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
+}
/*
- add a record
+ delete a record
*/
-static int ildb_add(struct ldb_module *module, const struct ldb_message *msg)
+static int ildb_delete_async(struct ldb_module *module, const struct ldb_dn *dn,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
{
- struct ldb_context *ldb = module->ldb;
struct ildb_private *ildb = module->private_data;
- struct ldap_mod **mods;
- char *dn;
- int ret = 0;
- NTSTATUS status;
+ struct ldap_message *msg;
+
+ *handle = NULL;
/* ignore ltdb specials */
- if (ldb_dn_is_special(msg->dn)) {
+ if (ldb_dn_is_special(dn)) {
return LDB_SUCCESS;
}
- mods = ildb_msg_to_mods(ldb, msg, 0);
- if (mods == NULL) {
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- dn = ldb_dn_linearize(mods, msg->dn);
- if (dn == NULL) {
- talloc_free(mods);
+ msg->type = LDAP_TAG_DelRequest;
+
+ msg->r.DelRequest.dn = ldb_dn_linearize(msg, dn);
+ if (msg->r.DelRequest.dn == NULL) {
+ talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
- status = ildap_add(ildb->ldap, dn, mods);
- ret = ildb_map_error(ildb, status);
+ return ildb_request_send(module, msg, context, callback, timeout, handle);
+}
- talloc_free(mods);
+static int ildb_delete(struct ldb_module *module, const struct ldb_dn *dn)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_async_handle *handle;
+ int ret;
- return ret;
-}
+ ret = ildb_delete_async(module, dn,
+ NULL, NULL, ildb->ldap->timeout, &handle);
+ if (ret != LDB_SUCCESS)
+ return ret;
+
+ return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
+}
/*
- modify a record
+ rename a record
*/
-static int ildb_modify(struct ldb_module *module, const struct ldb_message *msg)
+static int ildb_rename_async(struct ldb_module *module,
+ const struct ldb_dn *olddn, const struct ldb_dn *newdn,
+ void *context,
+ int (*callback)(struct ldb_context *, void *, struct ldb_async_result *),
+ int timeout,
+ struct ldb_async_handle **handle)
{
- struct ldb_context *ldb = module->ldb;
struct ildb_private *ildb = module->private_data;
- struct ldap_mod **mods;
- char *dn;
- int ret = 0;
- NTSTATUS status;
+ struct ldap_message *msg;
+
+ *handle = NULL;
/* ignore ltdb specials */
- if (ldb_dn_is_special(msg->dn)) {
+ if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) {
return LDB_SUCCESS;
}
- mods = ildb_msg_to_mods(ldb, msg, 1);
- if (mods == NULL) {
+ msg = new_ldap_message(ildb->ldap);
+ if (msg == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- dn = ldb_dn_linearize(mods, msg->dn);
- if (dn == NULL) {
- talloc_free(mods);
+ msg->type = LDAP_TAG_ModifyDNRequest;
+ msg->r.ModifyDNRequest.dn = ldb_dn_linearize(msg, olddn);
+ if (msg->r.ModifyDNRequest.dn == NULL) {
+ talloc_free(msg);
return LDB_ERR_INVALID_DN_SYNTAX;
}
- status = ildap_modify(ildb->ldap, dn, mods);
- ret = ildb_map_error(ildb, status);
+ msg->r.ModifyDNRequest.newrdn =
+ talloc_asprintf(msg, "%s=%s",
+ newdn->components[0].name,
+ ldb_dn_escape_value(msg, newdn->components[0].value));
+ if (msg->r.ModifyDNRequest.newrdn == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
- talloc_free(mods);
+ msg->r.ModifyDNRequest.newsuperior =
+ ldb_dn_linearize(msg,
+ ldb_dn_get_parent(msg, newdn));
+ if (msg->r.ModifyDNRequest.newsuperior == NULL) {
+ talloc_free(msg);
+ return LDB_ERR_INVALID_DN_SYNTAX;
+ }
+
+ msg->r.ModifyDNRequest.deleteolddn = True;
+
+ return ildb_request_send(module, msg, context, callback, timeout, handle);
+}
+
+static int ildb_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn)
+{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_async_handle *handle;
+ int ret;
+
+ ret = ildb_rename_async(module, olddn, newdn,
+ NULL, NULL, ildb->ldap->timeout, &handle);
- return ret;
+ if (ret != LDB_SUCCESS)
+ return ret;
+
+ return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL);
}
static int ildb_start_trans(struct ldb_module *module)
@@ -434,14 +827,75 @@ static int ildb_request(struct ldb_module *module, struct ldb_request *req)
req->op.rename.olddn,
req->op.rename.newdn);
+ case LDB_ASYNC_SEARCH:
+ return ildb_search_async(module,
+ req->op.search.base,
+ req->op.search.scope,
+ req->op.search.tree,
+ req->op.search.attrs,
+ req->controls,
+ req->async.context,
+ req->async.callback,
+ req->async.timeout,
+ &req->async.handle);
+
+ case LDB_ASYNC_ADD:
+ return ildb_add_async(module,
+ req->op.add.message,
+ req->async.context,
+ req->async.callback,
+ req->async.timeout,
+ &req->async.handle);
+
+ case LDB_ASYNC_MODIFY:
+ return ildb_modify_async(module,
+ req->op.mod.message,
+ req->async.context,
+ req->async.callback,
+ req->async.timeout,
+ &req->async.handle);
+
+ case LDB_ASYNC_DELETE:
+ return ildb_delete_async(module,
+ req->op.del.dn,
+ req->async.context,
+ req->async.callback,
+ req->async.timeout,
+ &req->async.handle);
+
+ case LDB_ASYNC_RENAME:
+ return ildb_rename_async(module,
+ req->op.rename.olddn,
+ req->op.rename.newdn,
+ req->async.context,
+ req->async.callback,
+ req->async.timeout,
+ &req->async.handle);
+
default:
return -1;
}
}
+/*
+ fetch the rootDSE for later use
+*/
static int ildb_init_2(struct ldb_module *module)
{
+ struct ildb_private *ildb = module->private_data;
+ struct ldb_result *res = NULL;
+ struct ldb_dn *empty_dn = ldb_dn_new(ildb);
+ int ret;
+ ret = ildb_search_bytree(module, empty_dn, LDB_SCOPE_BASE,
+ ldb_parse_tree(empty_dn, "dn=dc=rootDSE"),
+ NULL, NULL, &res);
+ if (ret == LDB_SUCCESS && res->count == 1) {
+ ildb->rootDSE = talloc_steal(ildb, res->msgs[0]);
+ }
+ if (ret == LDB_SUCCESS) talloc_free(res);
+ talloc_free(empty_dn);
+
return LDB_SUCCESS;
}
@@ -455,25 +909,33 @@ static const struct ldb_module_ops ildb_ops = {
};
-/*
- fetch the rootDSE
-*/
-static void ildb_rootdse(struct ldb_module *module)
+static int ildb_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
{
- struct ildb_private *ildb = module->private_data;
- struct ldb_result *res = NULL;
- struct ldb_dn *empty_dn = ldb_dn_new(ildb);
- int ret;
- ret = ildb_search_bytree(module, empty_dn, LDB_SCOPE_BASE,
- ldb_parse_tree(empty_dn, "dn=dc=rootDSE"),
- NULL, NULL, &res);
- if (ret == LDB_SUCCESS && res->count == 1) {
- ildb->rootDSE = talloc_steal(ildb, res->msgs[0]);
+ struct ildb_async_context *ac = talloc_get_type(handle->private_data, struct ildb_async_context);
+
+ if (!ac) {
+ return LDB_ERR_OPERATIONS_ERROR;
}
- if (ret == LDB_SUCCESS) talloc_free(res);
- talloc_free(empty_dn);
-}
+ switch(type) {
+ case LDB_WAIT_NONE:
+ if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
+ return LDB_ERR_OTHER;
+ }
+ break;
+ case LDB_WAIT_ALL:
+ while (handle->status == LDB_SUCCESS && handle->state != LDB_ASYNC_DONE) {
+ if (event_loop_once(ac->req->conn->event.event_ctx) != 0) {
+ return LDB_ERR_OTHER;
+ }
+ }
+ break;
+ default:
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ return handle->status;
+}
/*
connect to the database
@@ -546,6 +1008,8 @@ int ildb_connect(struct ldb_context *ldb, const char *url,
}
}
+ ldb->async_wait = &ildb_async_wait;
+
return 0;
failed: