diff options
-rw-r--r-- | source4/lib/ldb/ldb_ildap/ldb_ildap.c | 25 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_ldap/ldb_ldap.c | 27 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_index.c | 106 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_pack.c | 15 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_search.c | 301 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.c | 316 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_tdb.h | 37 |
7 files changed, 630 insertions, 197 deletions
diff --git a/source4/lib/ldb/ldb_ildap/ldb_ildap.c b/source4/lib/ldb/ldb_ildap/ldb_ildap.c index 69053cc110..a3af7dedba 100644 --- a/source4/lib/ldb/ldb_ildap/ldb_ildap.c +++ b/source4/lib/ldb/ldb_ildap/ldb_ildap.c @@ -539,7 +539,10 @@ static int ildb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -608,7 +611,10 @@ static int ildb_add(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -677,7 +683,10 @@ static int ildb_modify(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -727,7 +736,10 @@ static int ildb_delete(struct ldb_module *module, const struct ldb_dn *dn) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -796,7 +808,10 @@ static int ildb_rename(struct ldb_module *module, const struct ldb_dn *olddn, co if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } static int ildb_start_trans(struct ldb_module *module) diff --git a/source4/lib/ldb/ldb_ldap/ldb_ldap.c b/source4/lib/ldb/ldb_ldap/ldb_ldap.c index 4f840868a1..540dfc690b 100644 --- a/source4/lib/ldb/ldb_ldap/ldb_ldap.c +++ b/source4/lib/ldb/ldb_ldap/ldb_ldap.c @@ -52,7 +52,7 @@ struct lldb_private { struct lldb_async_context { struct ldb_module *module; int msgid; - uint32_t timeout; + int timeout; void *context; int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); }; @@ -398,7 +398,10 @@ static int lldb_search_bytree(struct ldb_module *module, const struct ldb_dn *ba if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -469,7 +472,10 @@ static int lldb_add(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } @@ -541,7 +547,10 @@ static int lldb_modify(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -601,7 +610,10 @@ static int lldb_delete(struct ldb_module *module, const struct ldb_dn *dn) if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } /* @@ -681,7 +693,10 @@ static int lldb_rename(struct ldb_module *module, const struct ldb_dn *olddn, co if (ret != LDB_SUCCESS) return ret; - return ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; } static int lldb_parse_result(struct ldb_async_handle *handle, LDAPMessage *result) diff --git a/source4/lib/ldb/ldb_tdb/ldb_index.c b/source4/lib/ldb/ldb_tdb/ldb_index.c index b1b82d0360..2fc20adb30 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_index.c +++ b/source4/lib/ldb/ldb_tdb/ldb_index.c @@ -625,52 +625,75 @@ static int ltdb_index_dn(struct ldb_module *module, filter a candidate dn_list from an indexed search into a set of results extracting just the given attributes */ -static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tree, - const struct ldb_dn *base, - enum ldb_scope scope, - const struct dn_list *dn_list, - const char * const attrs[], struct ldb_result *res) +static int ltdb_index_filter(const struct dn_list *dn_list, + struct ldb_async_handle *handle) { + struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context); + struct ldb_async_result *ares = NULL; unsigned int i; for (i = 0; i < dn_list->count; i++) { - struct ldb_message *msg; struct ldb_dn *dn; int ret; - msg = talloc(module, struct ldb_message); - if (msg == NULL) { - return LDB_ERR_OTHER; + ares = talloc_zero(ac, struct ldb_async_result); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + return LDB_ERR_OPERATIONS_ERROR; } - dn = ldb_dn_explode(msg, dn_list->dn[i]); + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + + dn = ldb_dn_explode(ares->message, dn_list->dn[i]); if (dn == NULL) { - talloc_free(msg); - return LDB_ERR_OTHER; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; } - ret = ltdb_search_dn1(module, dn, msg); + ret = ltdb_search_dn1(ac->module, dn, ares->message); talloc_free(dn); if (ret == 0) { /* the record has disappeared? yes, this can happen */ - talloc_free(msg); + talloc_free(ares); continue; } if (ret == -1) { /* an internal error */ - talloc_free(msg); - return LDB_ERR_OTHER; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; } - ret = 0; - if (ldb_match_msg(module->ldb, msg, tree, base, scope) == 1) { - ret = ltdb_add_attr_results(module, res, msg, - attrs, &(res->count), &(res->msgs)); + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, ac->base, ac->scope)) { + talloc_free(ares); + continue; } - talloc_free(msg); - if (ret != 0) { - return LDB_ERR_OTHER; + + /* filter the attributes that the user wants */ + ret = ltdb_filter_attrs(ares->message, ac->attrs); + + if (ret == -1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return LDB_ERR_OPERATIONS_ERROR; + } + + ares->type = LDB_REPLY_ENTRY; + handle->state = LDB_ASYNC_PENDING; + handle->status = ac->callback(ac->module->ldb, ac->context, ares); + + if (handle->status != LDB_SUCCESS) { + handle->state = LDB_ASYNC_DONE; + return handle->status; } } @@ -682,59 +705,48 @@ static int ldb_index_filter(struct ldb_module *module, struct ldb_parse_tree *tr returns -1 if an indexed search is not possible, in which case the caller should call ltdb_search_full() */ -int ltdb_search_indexed(struct ldb_module *module, - const struct ldb_dn *base, - enum ldb_scope scope, - struct ldb_parse_tree *tree, - const char * const attrs[], struct ldb_result **res) +int ltdb_search_indexed(struct ldb_async_handle *handle) { - struct ltdb_private *ltdb = module->private_data; + struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context); + struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); struct dn_list *dn_list; int ret; if (ltdb->cache->indexlist->num_elements == 0 && - scope != LDB_SCOPE_BASE) { + ac->scope != LDB_SCOPE_BASE) { /* no index list? must do full search */ return -1; } - dn_list = talloc(module, struct dn_list); + dn_list = talloc(handle, struct dn_list); if (dn_list == NULL) { return -1; } - *res = talloc(module, struct ldb_result); - if (*res == NULL) { - return LDB_ERR_OTHER; - } - (*res)->count = 0; - (*res)->msgs = NULL; - (*res)->refs = NULL; - (*res)->controls = NULL; - - if (scope == LDB_SCOPE_BASE) { + if (ac->scope == LDB_SCOPE_BASE) { /* with BASE searches only one DN can match */ dn_list->dn = talloc_array(dn_list, char *, 1); if (dn_list->dn == NULL) { - ldb_oom(module->ldb); + ldb_oom(ac->module->ldb); return -1; } - dn_list->dn[0] = ldb_dn_linearize(dn_list, base); + dn_list->dn[0] = ldb_dn_linearize(dn_list, ac->base); if (dn_list->dn[0] == NULL) { - ldb_oom(module->ldb); + ldb_oom(ac->module->ldb); return -1; } dn_list->count = 1; ret = 1; } else { - ret = ltdb_index_dn(module, tree, ltdb->cache->indexlist, dn_list); + ret = ltdb_index_dn(ac->module, ac->tree, ltdb->cache->indexlist, dn_list); } if (ret == 1) { /* we've got a candidate list - now filter by the full tree and extract the needed attributes */ - ret = ldb_index_filter(module, tree, base, scope, dn_list, - attrs, *res); + ret = ltdb_index_filter(dn_list, handle); + handle->status = ret; + handle->state = LDB_ASYNC_DONE; } talloc_free(dn_list); diff --git a/source4/lib/ldb/ldb_tdb/ldb_pack.c b/source4/lib/ldb/ldb_tdb/ldb_pack.c index e8654f7a53..c6edf663ae 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_pack.c +++ b/source4/lib/ldb/ldb_tdb/ldb_pack.c @@ -240,7 +240,11 @@ int ltdb_unpack_data(struct ldb_module *module, goto failed; } message->elements[i].flags = 0; - message->elements[i].name = (char *)p; + message->elements[i].name = talloc_strndup(message->elements, (char *)p, len); + if (message->elements[i].name == NULL) { + errno = ENOMEM; + goto failed; + } remaining -= len + 1; p += len + 1; message->elements[i].num_values = pull_uint32(p, 0); @@ -264,7 +268,14 @@ int ltdb_unpack_data(struct ldb_module *module, } message->elements[i].values[j].length = len; - message->elements[i].values[j].data = p+4; + message->elements[i].values[j].data = talloc_size(message->elements[i].values, len+1); + if (message->elements[i].values[j].data == NULL) { + errno = ENOMEM; + goto failed; + } + memcpy(message->elements[i].values[j].data, p+4, len); + message->elements[i].values[j].data[len] = 0; + remaining -= len+4+1; p += len+4+1; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_search.c b/source4/lib/ldb/ldb_tdb/ldb_search.c index d468f02e77..46f560f817 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_search.c +++ b/source4/lib/ldb/ldb_tdb/ldb_search.c @@ -213,7 +213,7 @@ int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct l { struct ltdb_private *ltdb = module->private_data; int ret; - TDB_DATA tdb_key, tdb_data, tdb_data2; + TDB_DATA tdb_key, tdb_data; memset(msg, 0, sizeof(*msg)); @@ -229,27 +229,19 @@ int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct l return 0; } - tdb_data2.dptr = talloc_memdup(msg, tdb_data.dptr, tdb_data.dsize); - free(tdb_data.dptr); - if (!tdb_data2.dptr) { - return -1; - } - tdb_data2.dsize = tdb_data.dsize; - msg->num_elements = 0; msg->elements = NULL; - ret = ltdb_unpack_data(module, &tdb_data2, msg); + ret = ltdb_unpack_data(module, &tdb_data, msg); + free(tdb_data.dptr); if (ret == -1) { - talloc_free(tdb_data2.dptr); return -1; } if (!msg->dn) { - msg->dn = ldb_dn_copy(tdb_data2.dptr, dn); + msg->dn = ldb_dn_copy(msg, dn); } if (!msg->dn) { - talloc_free(tdb_data2.dptr); return -1; } @@ -328,28 +320,67 @@ int ltdb_add_attr_results(struct ldb_module *module, } + /* - internal search state during a full db search -*/ -struct ltdb_search_info { - struct ldb_module *module; - struct ldb_parse_tree *tree; - const struct ldb_dn *base; - enum ldb_scope scope; - const char * const *attrs; - struct ldb_message **msgs; - unsigned int failures; - unsigned int count; -}; + filter the specified list of attributes from a message + removing not requested attrs. + */ +int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs) +{ + int i, keep_all = 0; + + if (attrs) { + /* check for special attrs */ + for (i = 0; attrs[i]; i++) { + if (strcmp(attrs[i], "*") == 0) { + keep_all = 1; + break; + } + + if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) { + if (msg_add_distinguished_name(msg) != 0) { + return -1; + } + } + } + } else { + keep_all = 1; + } + + if (keep_all) { + if (msg_add_distinguished_name(msg) != 0) { + return -1; + } + return 0; + } + + for (i = 0; i < msg->num_elements; i++) { + int j, found; + + for (j = 0, found = 0; attrs[j]; j++) { + if (ldb_attr_cmp(msg->elements[i].name, attrs[j]) == 0) { + found = 1; + break; + } + } + if (!found) { + ldb_msg_remove_attr(msg, msg->elements[i].name); + i--; + } + } + + return 0; +} /* search function for a non-indexed search */ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *state) { - struct ltdb_search_info *sinfo = state; - struct ldb_message *msg; + struct ldb_async_handle *handle = talloc_get_type(state, struct ldb_async_handle); + struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context); + struct ldb_async_result *ares = NULL; int ret; if (key.dsize < 4 || @@ -357,43 +388,65 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi return 0; } - msg = talloc(sinfo, struct ldb_message); - if (msg == NULL) { + ares = talloc_zero(ac, struct ldb_async_result); + if (!ares) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + return -1; + } + + ares->message = ldb_msg_new(ares); + if (!ares->message) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); return -1; } /* unpack the record */ - ret = ltdb_unpack_data(sinfo->module, &data, msg); + ret = ltdb_unpack_data(ac->module, &data, ares->message); if (ret == -1) { - sinfo->failures++; - talloc_free(msg); - return 0; + talloc_free(ares); + return -1; } - if (!msg->dn) { - msg->dn = ldb_dn_explode(msg, (char *)key.dptr + 3); - if (msg->dn == NULL) { - talloc_free(msg); + if (!ares->message->dn) { + ares->message->dn = ldb_dn_explode(ares->message, (char *)key.dptr + 3); + if (ares->message->dn == NULL) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); return -1; } } /* see if it matches the given expression */ - if (!ldb_match_msg(sinfo->module->ldb, msg, sinfo->tree, - sinfo->base, sinfo->scope)) { - talloc_free(msg); + if (!ldb_match_msg(ac->module->ldb, ares->message, ac->tree, + ac->base, ac->scope)) { + talloc_free(ares); return 0; } - ret = ltdb_add_attr_results(sinfo->module, sinfo, msg, sinfo->attrs, &sinfo->count, &sinfo->msgs); + /* filter the attributes that the user wants */ + ret = ltdb_filter_attrs(ares->message, ac->attrs); if (ret == -1) { - sinfo->failures++; + handle->status = LDB_ERR_OPERATIONS_ERROR; + handle->state = LDB_ASYNC_DONE; + talloc_free(ares); + return -1; } - talloc_free(msg); + ares->type = LDB_REPLY_ENTRY; + handle->state = LDB_ASYNC_PENDING; + handle->status = ac->callback(ac->module->ldb, ac->context, ares); - return ret; + if (handle->status != LDB_SUCCESS) { + /* don't try to free ares here, the callback is in charge of that */ + return -1; + } + + return 0; } @@ -401,88 +454,121 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi search the database with a LDAP-like expression. this is the "full search" non-indexed variant */ -static int ltdb_search_full(struct ldb_module *module, - const struct ldb_dn *base, - enum ldb_scope scope, - struct ldb_parse_tree *tree, - const char * const attrs[], struct ldb_result **res) +static int ltdb_search_full(struct ldb_async_handle *handle) { - struct ltdb_private *ltdb = module->private_data; - struct ldb_result *result; + struct ltdb_async_context *ac = talloc_get_type(handle->private_data, struct ltdb_async_context); + struct ltdb_private *ltdb = talloc_get_type(ac->module->private_data, struct ltdb_private); int ret; - struct ltdb_search_info *sinfo; - result = talloc(ltdb, struct ldb_result); - if (result == NULL) { - return LDB_ERR_OTHER; - } + ret = tdb_traverse_read(ltdb->tdb, search_func, handle); - sinfo = talloc(ltdb, struct ltdb_search_info); - if (sinfo == NULL) { - talloc_free(result); - return LDB_ERR_OTHER; + handle->state = LDB_ASYNC_DONE; + + if (ret == -1) { + handle->status = LDB_ERR_OPERATIONS_ERROR; + return handle->status; } - sinfo->tree = tree; - sinfo->module = module; - sinfo->scope = scope; - sinfo->base = base; - sinfo->attrs = attrs; - sinfo->msgs = NULL; - sinfo->count = 0; - sinfo->failures = 0; + handle->status = LDB_SUCCESS; + return handle->status; +} + +static int ltdb_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares) +{ + struct ldb_result *res; + + if (!context) { + ldb_set_errstring(ldb, talloc_strdup(ldb, "NULL Context in callback")); + goto error; + } - ret = tdb_traverse_read(ltdb->tdb, search_func, sinfo); + res = *((struct ldb_result **)context); - if (ret == -1) { - talloc_free(result); - talloc_free(sinfo); - return -1; + if (!res || !ares) { + goto error; } - result->controls = NULL; - result->refs = NULL; - result->msgs = talloc_steal(result, sinfo->msgs); - result->count = sinfo->count; - *res = result; + 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; + } - talloc_free(sinfo); + res->count++; + } else { + ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); + goto error; + } + talloc_free(ares); return LDB_SUCCESS; -} +error: + if (ares) talloc_free(ares); + if (res) talloc_free(res); + if (context) *((struct ldb_result **)context) = NULL; + return LDB_ERR_OPERATIONS_ERROR; +} -/* - search the database with a LDAP-like expression. - choses a search method -*/ -int ltdb_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_result **res) +int ltdb_search_async(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout, + struct ldb_async_handle **handle) { + struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_async_context *ltdb_ac; int ret; if ((base == NULL || base->comp_num == 0) && - (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) return -1; + (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; if (ltdb_lock_read(module) != 0) { - return -1; + return LDB_ERR_OPERATIONS_ERROR; } if (ltdb_cache_load(module) != 0) { ltdb_unlock_read(module); - return -1; + return LDB_ERR_OPERATIONS_ERROR; } if (tree == NULL) { - return -1; + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + *handle = init_ltdb_handle(ltdb, module, context, callback, timeout); + if (*handle == NULL) { + talloc_free(*handle); + ltdb_unlock_read(module); + return LDB_ERR_OPERATIONS_ERROR; } - *res = NULL; + ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context); + + ltdb_ac->tree = tree; + ltdb_ac->scope = scope; + ltdb_ac->base = base; + ltdb_ac->attrs = attrs; - ret = ltdb_search_indexed(module, base, scope, tree, attrs, res); + ret = ltdb_search_indexed(*handle); if (ret == -1) { - ret = ltdb_search_full(module, base, scope, tree, attrs, res); + ret = ltdb_search_full(*handle); + } + if (ret != LDB_SUCCESS) { + ldb_set_errstring(module->ldb, talloc_strdup(module->ldb, "Indexed and full searches both failed!\n")); + talloc_free(*handle); + *handle = NULL; } ltdb_unlock_read(module); @@ -490,4 +576,33 @@ int ltdb_search_bytree(struct ldb_module *module, const struct ldb_dn *base, return ret; } +/* + search the database with a LDAP-like expression. + choses a search method +*/ +int ltdb_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_result **res) +{ + struct ldb_async_handle *handle; + int ret; + + *res = talloc_zero(module, struct ldb_result); + if (! *res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ltdb_search_async(module, base, scope, tree, attrs, + res, <db_search_sync_callback, + 0, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.c b/source4/lib/ldb/ldb_tdb/ldb_tdb.c index 7cf6138b12..04766c53a1 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.c +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.c @@ -3,6 +3,7 @@ Copyright (C) Andrew Tridgell 2004 Copyright (C) Stefan Metzmacher 2004 + Copyright (C) Simo Sorce 2006 ** NOTE! The following LGPL license applies to the ldb @@ -25,7 +26,7 @@ */ /* - * Name: ldb + * Name: ldb_tdb * * Component: ldb tdb backend * @@ -33,6 +34,12 @@ * * Author: Andrew Tridgell * Author: Stefan Metzmacher + * + * Modifications: + * + * - description: make the module use asyncronous calls + * date: Feb 2006 + * Author: Simo Sorce */ #include "includes.h" @@ -71,6 +78,37 @@ static int ltdb_err_map(enum TDB_ERROR tdb_code) } +struct ldb_async_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout) +{ + struct ltdb_async_context *ac; + struct ldb_async_handle *h; + + h = talloc_zero(ltdb, struct ldb_async_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + return NULL; + } + + ac = talloc_zero(h, struct ltdb_async_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + ac->module = module; + ac->context = context; + ac->callback = callback; + ac->timeout = timeout; + + return h; +} + /* form a TDB_DATA for a record key caller frees @@ -218,28 +256,65 @@ done: /* add a record to the database */ -static int ltdb_add(struct ldb_module *module, const struct ldb_message *msg) +static int ltdb_add_async(struct ldb_module *module, const struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout, + struct ldb_async_handle **handle) { - int ret; + struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_async_context *ltdb_ac; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_ltdb_handle(ltdb, module, context, callback, timeout); + if (*handle == NULL) { + return ret; + } + ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; ret = ltdb_check_special_dn(module, msg); if (ret != LDB_SUCCESS) { + talloc_free(*handle); return ret; } if (ltdb_cache_load(module) != 0) { + talloc_free(*handle); return LDB_ERR_OTHER; } ret = ltdb_store(module, msg, TDB_INSERT); - if (ret == LDB_SUCCESS) { - ltdb_modified(module, msg->dn); + if (ret != LDB_SUCCESS) { + (*handle)->status = ret; + return LDB_SUCCESS; } - return ret; + ltdb_modified(module, msg->dn); + + if (ltdb_ac->callback) + (*handle)->status = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + + return LDB_SUCCESS; } +static int ltdb_add(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_async_handle *handle; + int ret; + + ret = ltdb_add_async(module, msg, NULL, NULL, 0, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} /* delete a record from the database, not updating indexes (used for deleting @@ -269,16 +344,32 @@ int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn) /* delete a record from the database */ -static int ltdb_delete(struct ldb_module *module, const struct ldb_dn *dn) +static int ltdb_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_message *msg = NULL; - int ret = LDB_ERR_OTHER; + struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_async_context *ltdb_ac; + struct ldb_message *msg; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = NULL; if (ltdb_cache_load(module) != 0) { goto failed; } - msg = talloc(module, struct ldb_message); + *handle = init_ltdb_handle(ltdb, module, context, callback, timeout); + if (*handle == NULL) { + goto failed; + } + ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + msg = talloc(ltdb_ac, struct ldb_message); if (msg == NULL) { goto failed; } @@ -288,8 +379,8 @@ static int ltdb_delete(struct ldb_module *module, const struct ldb_dn *dn) ret = ltdb_search_dn1(module, dn, msg); if (ret != 1) { /* not finding the old record is an error */ - ret = LDB_ERR_NO_SUCH_OBJECT; - goto failed; + (*handle)->status = LDB_ERR_NO_SUCH_OBJECT; + return LDB_SUCCESS; } ret = ltdb_delete_noindex(module, dn); @@ -299,16 +390,35 @@ static int ltdb_delete(struct ldb_module *module, const struct ldb_dn *dn) /* remove any indexed attributes */ ret = ltdb_index_del(module, msg); - if (ret == LDB_SUCCESS) { - ltdb_modified(module, dn); - } else - ret = LDB_ERR_OTHER; + if (ret) { + goto failed; + } + ltdb_modified(module, dn); - talloc_free(msg); - return ret; + if (ltdb_ac->callback) + (*handle)->status = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + + return LDB_SUCCESS; failed: - talloc_free(msg); + talloc_free(*handle); + return ret; +} + +static int ltdb_delete(struct ldb_module *module, const struct ldb_dn *dn) +{ + struct ldb_async_handle *handle; + int ret; + + ret = ltdb_delete_async(module, dn, + NULL, NULL, 0, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); return ret; } @@ -624,42 +734,97 @@ failed: /* modify a record */ -static int ltdb_modify(struct ldb_module *module, const struct ldb_message *msg) +static int ltdb_modify_async(struct ldb_module *module, const struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout, + struct ldb_async_handle **handle) { - int ret; + struct ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_async_context *ltdb_ac; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = NULL; + + *handle = init_ltdb_handle(ltdb, module, context, callback, timeout); + if (*handle == NULL) { + return ret; + } + ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; ret = ltdb_check_special_dn(module, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { + talloc_free(*handle); return ret; } if (ltdb_cache_load(module) != 0) { - return -1; + talloc_free(*handle); + return LDB_ERR_OTHER; } ret = ltdb_modify_internal(module, msg); - if (ret == LDB_SUCCESS) { - ltdb_modified(module, msg->dn); + if (ret != LDB_SUCCESS) { + (*handle)->status = ret; + return LDB_SUCCESS; } + ltdb_modified(module, msg->dn); + + if (ltdb_ac->callback) + (*handle)->status = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); + + return LDB_SUCCESS; +} + +static int ltdb_modify(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_async_handle *handle; + int ret; + + ret = ltdb_modify_async(module, msg, NULL, NULL, 0, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); return ret; } /* rename a record */ -static int ltdb_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +static int ltdb_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 ltdb_private *ltdb = talloc_get_type(module->private_data, struct ltdb_private); + struct ltdb_async_context *ltdb_ac; struct ldb_message *msg; - char *error_str; - int ret = LDB_ERR_OTHER; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = NULL; if (ltdb_cache_load(module) != 0) { return ret; } - msg = talloc(module, struct ldb_message); + *handle = init_ltdb_handle(ltdb, module, context, callback, timeout); + if (*handle == NULL) { + goto failed; + } + ltdb_ac = talloc_get_type((*handle)->private_data, struct ltdb_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; + + msg = talloc(ltdb_ac, struct ldb_message); if (msg == NULL) { goto failed; } @@ -669,35 +834,53 @@ static int ltdb_rename(struct ldb_module *module, const struct ldb_dn *olddn, co ret = ltdb_search_dn1(module, olddn, msg); if (ret != 1) { /* not finding the old record is an error */ - ret = LDB_ERR_NO_SUCH_OBJECT; - goto failed; + (*handle)->status = LDB_ERR_NO_SUCH_OBJECT; + return LDB_SUCCESS; } msg->dn = ldb_dn_copy(msg, newdn); if (!msg->dn) { - ret = LDB_ERR_OTHER; + ret = LDB_ERR_OPERATIONS_ERROR; goto failed; } ret = ltdb_add(module, msg); if (ret != LDB_SUCCESS) { - goto failed; + (*handle)->status = LDB_ERR_OPERATIONS_ERROR; + return LDB_SUCCESS; } ret = ltdb_delete(module, olddn); - error_str = talloc_strdup(module, ldb_errstring(module->ldb)); if (ret != LDB_SUCCESS) { ltdb_delete(module, newdn); + (*handle)->status = ret; + return LDB_SUCCESS; } - ldb_set_errstring(module->ldb, error_str); + if (ltdb_ac->callback) + (*handle)->status = ltdb_ac->callback(module->ldb, ltdb_ac->context, NULL); - talloc_free(msg); + return LDB_SUCCESS; +failed: + talloc_free(*handle); return ret; +} -failed: - talloc_free(msg); +static int ltdb_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_async_handle *handle; + int ret; + + ret = ltdb_rename_async(module, olddn, newdn, + NULL, NULL, 0, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); return ret; } @@ -734,10 +917,19 @@ static int ltdb_del_trans(struct ldb_module *module) return LDB_SUCCESS; } +static int ltdb_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type) +{ + return handle->status; +} + static int ltdb_request(struct ldb_module *module, struct ldb_request *req) { /* check for oustanding critical controls and return an error if found */ + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_tdb backend!\n"); + } + if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } @@ -749,7 +941,7 @@ static int ltdb_request(struct ldb_module *module, struct ldb_request *req) req->op.search.base, req->op.search.scope, req->op.search.tree, - req->op.search.attrs, + req->op.search.attrs, &req->op.search.res); case LDB_REQ_ADD: @@ -766,6 +958,50 @@ static int ltdb_request(struct ldb_module *module, struct ldb_request *req) req->op.rename.olddn, req->op.rename.newdn); + case LDB_ASYNC_SEARCH: + return ltdb_search_async(module, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->async.context, + req->async.callback, + req->async.timeout, + &req->async.handle); + + case LDB_ASYNC_ADD: + return ltdb_add_async(module, + req->op.add.message, + req->async.context, + req->async.callback, + req->async.timeout, + &req->async.handle); + + case LDB_ASYNC_MODIFY: + return ltdb_modify_async(module, + req->op.mod.message, + req->async.context, + req->async.callback, + req->async.timeout, + &req->async.handle); + + case LDB_ASYNC_DELETE: + return ltdb_delete_async(module, + req->op.del.dn, + req->async.context, + req->async.callback, + req->async.timeout, + &req->async.handle); + + case LDB_ASYNC_RENAME: + return ltdb_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 LDB_ERR_OPERATIONS_ERROR; @@ -868,5 +1104,7 @@ int ltdb_connect(struct ldb_context *ldb, const char *url, ldb->modules->ops = <db_ops; ldb->sequence_number = ltdb_sequence_number; + ldb->async_wait = <db_async_wait; + return 0; } diff --git a/source4/lib/ldb/ldb_tdb/ldb_tdb.h b/source4/lib/ldb/ldb_tdb/ldb_tdb.h index 29845fa8ac..5c76463ff7 100644 --- a/source4/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source4/lib/ldb/ldb_tdb/ldb_tdb.h @@ -29,6 +29,25 @@ struct ltdb_private { } *cache; }; +/* + the async local context + holds also internal search state during a full db search +*/ +struct ltdb_async_context { + struct ldb_module *module; + + /* search stuff */ + struct ldb_parse_tree *tree; + const struct ldb_dn *base; + enum ldb_scope scope; + const char * const *attrs; + + /* async stuff */ + void *context; + int timeout; + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); +}; + /* special record types */ #define LTDB_INDEX "@INDEX" #define LTDB_INDEXLIST "@INDEXLIST" @@ -53,11 +72,7 @@ int ltdb_check_at_attributes_values(const struct ldb_val *value); struct ldb_parse_tree; -int ltdb_search_indexed(struct ldb_module *module, - const struct ldb_dn *base, - enum ldb_scope scope, - struct ldb_parse_tree *tree, - const char * const attrs[], struct ldb_result **res); +int ltdb_search_indexed(struct ldb_async_handle *handle); int ltdb_index_add(struct ldb_module *module, const struct ldb_message *msg); int ltdb_index_del(struct ldb_module *module, const struct ldb_message *msg); int ltdb_reindex(struct ldb_module *module); @@ -85,12 +100,24 @@ int ltdb_add_attr_results(struct ldb_module *module, const char * const attrs[], unsigned int *count, struct ldb_message ***res); +int ltdb_filter_attrs(struct ldb_message *msg, const char * const *attrs); +int ltdb_search_async(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout, + struct ldb_async_handle **handle); int ltdb_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_result **res); /* The following definitions come from lib/ldb/ldb_tdb/ldb_tdb.c */ +struct ldb_async_handle *init_ltdb_handle(struct ltdb_private *ltdb, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + int timeout); struct TDB_DATA ltdb_key(struct ldb_module *module, const struct ldb_dn *dn); int ltdb_store(struct ldb_module *module, const struct ldb_message *msg, int flgs); int ltdb_delete_noindex(struct ldb_module *module, const struct ldb_dn *dn); |