diff options
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/ldb/common/ldb.c | 21 | ||||
-rw-r--r-- | source4/lib/ldb/common/ldb_modules.c | 10 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb.h | 46 | ||||
-rw-r--r-- | source4/lib/ldb/include/ldb_private.h | 3 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_ildap/ldb_ildap.c | 912 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_index.c | 1 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_search.c | 1 | ||||
-rw-r--r-- | source4/lib/ldb/tools/cmdline.c | 4 | ||||
-rw-r--r-- | source4/lib/ldb/tools/ldbsearch.c | 12 |
10 files changed, 770 insertions, 241 deletions
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c index 0857c07ad4..68722cde96 100644 --- a/source4/lib/ldb/common/ldb.c +++ b/source4/lib/ldb/common/ldb.c @@ -106,7 +106,15 @@ int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, co return LDB_SUCCESS; } -static void ldb_reset_err_string(struct ldb_context *ldb) +void ldb_set_errstring(struct ldb_module *module, char *err_string) +{ + if (module->ldb->err_string) { + talloc_free(module->ldb->err_string); + } + module->ldb->err_string = talloc_steal(module->ldb, err_string); +} + +void ldb_reset_err_string(struct ldb_context *ldb) { if (ldb->err_string) { talloc_free(ldb->err_string); @@ -211,6 +219,14 @@ int ldb_transaction_cancel(struct ldb_context *ldb) return status; } +int ldb_async_wait(struct ldb_context *ldb, struct ldb_async_handle *handle, enum ldb_async_wait_type type) +{ + if (ldb->async_wait != NULL) + return ldb->async_wait(handle, type); + + return LDB_ERR_OPERATIONS_ERROR; +} + /* check for an error return from an op if an op fails, but has not setup an error string, then setup one now @@ -279,6 +295,9 @@ int ldb_request(struct ldb_context *ldb, struct ldb_request *request) if (request->operation == LDB_REQ_SEARCH) { request->op.search.res = talloc_steal(ldb, r->op.search.res); } + if (request->operation == LDB_ASYNC_SEARCH) { + request->async.handle = r->async.handle; + } talloc_free(r); if (started_transaction) { diff --git a/source4/lib/ldb/common/ldb_modules.c b/source4/lib/ldb/common/ldb_modules.c index ddbdddedcc..922506ea4d 100644 --- a/source4/lib/ldb/common/ldb_modules.c +++ b/source4/lib/ldb/common/ldb_modules.c @@ -263,13 +263,3 @@ int ldb_next_del_trans(struct ldb_module *module) FIND_OP(module, del_transaction); return module->ops->del_transaction(module); } - -void ldb_set_errstring(struct ldb_module *module, char *err_string) -{ - if (module->ldb->err_string) { - talloc_free(module->ldb->err_string); - } - - module->ldb->err_string = talloc_steal(module->ldb, err_string); -} - diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h index a6cec7f774..4a40e34363 100644 --- a/source4/lib/ldb/include/ldb.h +++ b/source4/lib/ldb/include/ldb.h @@ -560,15 +560,51 @@ enum ldb_request_type { LDB_REQ_MODIFY, LDB_REQ_DELETE, LDB_REQ_RENAME, + LDB_ASYNC_SEARCH, + LDB_ASYNC_ADD, + LDB_ASYNC_MODIFY, + LDB_ASYNC_DELETE, + LDB_ASYNC_RENAME, + LDB_REQ_REGISTER }; +enum ldb_reply_type { + LDB_REPLY_ENTRY, + LDB_REPLY_REFERRAL, + LDB_REPLY_DONE +}; + +enum ldb_async_wait_type { + LDB_WAIT_ALL, + LDB_WAIT_NONE +}; + +enum ldb_async_state { + LDB_ASYNC_PENDING, + LDB_ASYNC_DONE +}; + struct ldb_result { unsigned int count; struct ldb_message **msgs; + char **refs; struct ldb_control **controls; }; +struct ldb_async_result { + enum ldb_reply_type type; + struct ldb_message *message; + char *referral; + struct ldb_control **controls; +}; + +struct ldb_async_handle { + int status; + enum ldb_async_state state; + void *private_data; +}; + struct ldb_search { const struct ldb_dn *base; enum ldb_scope scope; @@ -613,10 +649,20 @@ struct ldb_request { struct ldb_control **controls; struct ldb_credentials *creds; + + struct { + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); + + time_t timeout; + struct ldb_async_handle *handle; + } async; }; int ldb_request(struct ldb_context *ldb, struct ldb_request *request); +int ldb_async_wait(struct ldb_context *ldb, struct ldb_async_handle *handle, enum ldb_async_wait_type type); + /** Initialise an ldb context diff --git a/source4/lib/ldb/include/ldb_private.h b/source4/lib/ldb/include/ldb_private.h index 90632744ed..db34b58858 100644 --- a/source4/lib/ldb/include/ldb_private.h +++ b/source4/lib/ldb/include/ldb_private.h @@ -105,6 +105,8 @@ struct ldb_context { char *err_string; int transaction_active; + + int (*async_wait)(struct ldb_async_handle *, enum ldb_async_wait_type); }; /* the modules init function */ @@ -132,6 +134,7 @@ int ldb_next_del_trans(struct ldb_module *module); int ldb_next_second_stage_init(struct ldb_module *module); void ldb_set_errstring(struct ldb_module *module, char *err_string); +void ldb_reset_err_string(struct ldb_context *ldb); /* The following definitions come from lib/ldb/common/ldb_debug.c */ void ldb_debug(struct ldb_context *ldb, enum ldb_debug_level level, const char *fmt, ...) PRINTF_ATTRIBUTE(3, 4); 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: diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 3e24093118..48d849746f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -964,6 +964,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d (*res)->msgs = talloc_steal(*res, msgs.msgs); (*res)->count = msgs.count; + (*res)->refs = NULL; (*res)->controls = NULL; talloc_free(local_ctx); diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index 5c601f9ea8..b1b82d0360 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -709,6 +709,7 @@ int ltdb_search_indexed(struct ldb_module *module, } (*res)->count = 0; (*res)->msgs = NULL; + (*res)->refs = NULL; (*res)->controls = NULL; if (scope == LDB_SCOPE_BASE) { diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c index e43125d588..d468f02e77 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_search.c +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -441,6 +441,7 @@ static int ltdb_search_full(struct ldb_module *module, } result->controls = NULL; + result->refs = NULL; result->msgs = talloc_steal(result, sinfo->msgs); result->count = sinfo->count; *res = result; diff --git a/source4/lib/ldb/tools/cmdline.c b/source4/lib/ldb/tools/cmdline.c index 24005c450c..a67c41e67f 100644 --- a/source4/lib/ldb/tools/cmdline.c +++ b/source4/lib/ldb/tools/cmdline.c @@ -596,10 +596,6 @@ int handle_controls_reply(struct ldb_control **reply, struct ldb_control **reque cookie = ldb_base64_encode(req_control, rep_control->cookie, rep_control->cookie_len); printf("# DIRSYNC cookie returned was:\n# %s\n", cookie); - sleep(120); - - ret = 1; - continue; } diff --git a/source4/lib/ldb/tools/ldbsearch.c b/source4/lib/ldb/tools/ldbsearch.c index b4120c0dce..c380862c5d 100644 --- a/source4/lib/ldb/tools/ldbsearch.c +++ b/source4/lib/ldb/tools/ldbsearch.c @@ -64,9 +64,10 @@ static int do_search(struct ldb_context *ldb, const char *expression, const char * const *attrs) { - int ret, i; + int ret, i, n; int loop = 0; int total = 0; + int refs = 0; struct ldb_request req; struct ldb_result *result = NULL; @@ -94,7 +95,6 @@ static int do_search(struct ldb_context *ldb, } result = req.op.search.res; - printf("# returned %d records\n", result->count); if (options->sorted) { ldb_qsort(result->msgs, result->count, sizeof(struct ldb_message *), @@ -120,6 +120,12 @@ static int do_search(struct ldb_context *ldb, ldb_ldif_write_file(ldb, stdout, &ldif); } + if (result->refs) { + for(n = 0;result->refs[n]; n++, refs++) { + printf("# referral %d\nref: %s\n\n", refs + 1, result->refs[n]); + } + } + if (result->controls) { if (handle_controls_reply(result->controls, req.controls) == 1) loop = 1; @@ -137,6 +143,8 @@ static int do_search(struct ldb_context *ldb, } while(loop); + printf("# returned %d records\n# %d entries\n# %d referrals\n", total + refs, total, refs); + return 0; } |