From deaac92f439ef001bfe052df170d6e34e8ba5845 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 15 Nov 2007 01:53:44 +0100 Subject: [PATCH] r25959: Add a new special DN to LDB: @OPTIONS Use the checkBaseOnSearch attribute to control if we should check the base DN on search requests. Also ensure we honour any errors in searching, not just errors in the supplied 'done' callback. Andrew Bartlett --- source/lib/ldb/ldb_tdb/ldb_cache.c | 35 ++++++-- source/lib/ldb/ldb_tdb/ldb_search.c | 122 +++++++++++++++++++++++++--- source/lib/ldb/ldb_tdb/ldb_tdb.h | 4 + 3 files changed, 144 insertions(+), 17 deletions(-) diff --git a/source/lib/ldb/ldb_tdb/ldb_cache.c b/source/lib/ldb/ldb_tdb/ldb_cache.c index de489e3d8b3..77922a97c78 100644 --- a/source/lib/ldb/ldb_tdb/ldb_cache.c +++ b/source/lib/ldb/ldb_tdb/ldb_cache.c @@ -113,11 +113,13 @@ static int ltdb_attributes_load(struct ldb_module *module) if (dn == NULL) goto failed; r = ltdb_search_dn1(module, dn, msg); + talloc_free(dn); if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { - talloc_free(dn); goto failed; } - talloc_free(dn); + if (r == LDB_ERR_NO_SUCH_OBJECT) { + return 0; + } /* mapping these flags onto ldap 'syntaxes' isn't strictly correct, but its close enough for now */ for (i=0;inum_elements;i++) { @@ -247,10 +249,10 @@ int ltdb_cache_reload(struct ldb_module *module) int ltdb_cache_load(struct ldb_module *module) { struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; - struct ldb_dn *baseinfo_dn = NULL; + struct ldb_dn *baseinfo_dn = NULL, *options_dn = NULL; struct ldb_dn *indexlist_dn = NULL; uint64_t seq; - struct ldb_message *baseinfo = NULL; + struct ldb_message *baseinfo = NULL, *options = NULL; int r; /* a very fast check to avoid extra database reads */ @@ -282,7 +284,7 @@ int ltdb_cache_load(struct ldb_module *module) } /* possibly initialise the baseinfo */ - if (!baseinfo->dn) { + if (r == LDB_ERR_NO_SUCH_OBJECT) { if (ltdb_baseinfo_init(module) != LDB_SUCCESS) { goto failed; } @@ -301,6 +303,25 @@ int ltdb_cache_load(struct ldb_module *module) } ltdb->sequence_number = seq; + /* Read an interpret database options */ + options = talloc(ltdb->cache, struct ldb_message); + if (options == NULL) goto failed; + + options_dn = ldb_dn_new(module, module->ldb, LTDB_OPTIONS); + if (options_dn == NULL) goto failed; + + r= ltdb_search_dn1(module, options_dn, options); + if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) { + goto failed; + } + + /* possibly initialise the baseinfo */ + if (r == LDB_SUCCESS) { + ltdb->check_base = ldb_msg_find_attr_as_bool(options, LTDB_CHECK_BASE, false); + } else { + ltdb->check_base = false; + } + talloc_free(ltdb->cache->last_attribute.name); memset(<db->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute)); @@ -328,12 +349,16 @@ int ltdb_cache_load(struct ldb_module *module) } done: + talloc_free(options); + talloc_free(options_dn); talloc_free(baseinfo); talloc_free(baseinfo_dn); talloc_free(indexlist_dn); return 0; failed: + talloc_free(options); + talloc_free(options_dn); talloc_free(baseinfo); talloc_free(baseinfo_dn); talloc_free(indexlist_dn); diff --git a/source/lib/ldb/ldb_tdb/ldb_search.c b/source/lib/ldb/ldb_tdb/ldb_search.c index 8151b458d4d..1fa20740a51 100644 --- a/source/lib/ldb/ldb_tdb/ldb_search.c +++ b/source/lib/ldb/ldb_tdb/ldb_search.c @@ -200,6 +200,35 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module, return ret; } +/* + search the database for a single simple dn. + return LDB_ERR_NO_SUCH_OBJECT on record-not-found + and LDB_SUCCESS on success +*/ +int ltdb_search_base(struct ldb_module *module, struct ldb_dn *dn) +{ + struct ltdb_private *ltdb = (struct ltdb_private *)module->private_data; + TDB_DATA tdb_key, tdb_data; + + if (ldb_dn_is_null(dn)) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + /* form the key */ + tdb_key = ltdb_key(module, dn); + if (!tdb_key.dptr) { + return LDB_ERR_OPERATIONS_ERROR; + } + + tdb_data = tdb_fetch(ltdb->tdb, tdb_key); + talloc_free(tdb_key.dptr); + if (!tdb_data.dptr) { + return LDB_ERR_NO_SUCH_OBJECT; + } + + free(tdb_data.dptr); + return LDB_SUCCESS; +} /* search the database for a single simple dn, returning all attributes @@ -227,7 +256,7 @@ int ltdb_search_dn1(struct ldb_module *module, struct ldb_dn *dn, struct ldb_mes if (!tdb_data.dptr) { return LDB_ERR_NO_SUCH_OBJECT; } - + msg->num_elements = 0; msg->elements = NULL; @@ -473,10 +502,6 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) struct ldb_reply *ares; int ret; - if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) && - (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) - return LDB_ERR_OPERATIONS_ERROR; - if (ltdb_lock_read(module) != 0) { return LDB_ERR_OPERATIONS_ERROR; } @@ -496,6 +521,65 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) ltdb_unlock_read(module); return LDB_ERR_OPERATIONS_ERROR; } + + if ((req->op.search.base == NULL) || (ldb_dn_is_null(req->op.search.base) == true)) { + + /* Check what we should do with a NULL dn */ + switch (req->op.search.scope) { + case LDB_SCOPE_BASE: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a base search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + case LDB_SCOPE_ONELEVEL: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a one-level search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + case LDB_SCOPE_SUBTREE: + default: + /* We accept subtree searches from a NULL base DN, ie over the whole DB */ + ret = LDB_SUCCESS; + } + } else if (ldb_dn_is_valid(req->op.search.base) == false) { + + /* We don't want invalid base DNs here */ + ldb_asprintf_errstring(module->ldb, + "Invalid Base DN: %s", + ldb_dn_get_linearized(req->op.search.base)); + ret = LDB_ERR_INVALID_DN_SYNTAX; + + } else if (ldb_dn_is_null(req->op.search.base) == true) { + + /* Check what we should do with a NULL dn */ + switch (req->op.search.scope) { + case LDB_SCOPE_BASE: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a base search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + case LDB_SCOPE_ONELEVEL: + ldb_asprintf_errstring(module->ldb, + "NULL Base DN invalid for a one-level search"); + ret = LDB_ERR_INVALID_DN_SYNTAX; + case LDB_SCOPE_SUBTREE: + default: + /* We accept subtree searches from a NULL base DN, ie over the whole DB */ + ret = LDB_SUCCESS; + } + + } else if (ltdb->check_base) { + /* This database has been marked as 'checkBaseOnSearch', so do a spot check of the base dn */ + ret = ltdb_search_base(module, req->op.search.base); + + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + ldb_asprintf_errstring(module->ldb, + "No such Base DN: %s", + ldb_dn_get_linearized(req->op.search.base)); + } + + } else { + /* If we are not checking the base DN life is easy */ + ret = LDB_SUCCESS; + } + ltdb_ac = talloc_get_type(req->handle->private_data, struct ltdb_context); ltdb_ac->tree = req->op.search.tree; @@ -503,12 +587,23 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) ltdb_ac->base = req->op.search.base; ltdb_ac->attrs = req->op.search.attrs; - ret = ltdb_search_indexed(req->handle); - if (ret == LDB_ERR_OPERATIONS_ERROR) { - ret = ltdb_search_full(req->handle); + + if (ret == LDB_SUCCESS) { + ret = ltdb_search_indexed(req->handle); + if (ret == LDB_ERR_NO_SUCH_OBJECT) { + /* Not in the index, therefore OK! */ + ret = LDB_SUCCESS; + + } else if (ret == LDB_ERR_OPERATIONS_ERROR) { + /* Not indexed, so we need to do a full scan */ + ret = ltdb_search_full(req->handle); + if (ret != LDB_SUCCESS) { + ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n"); + } + } } + if (ret != LDB_SUCCESS) { - ldb_set_errstring(module->ldb, "Indexed and full searches both failed!\n"); req->handle->state = LDB_ASYNC_DONE; req->handle->status = ret; } @@ -522,10 +617,13 @@ int ltdb_search(struct ldb_module *module, struct ldb_request *req) } req->handle->state = LDB_ASYNC_DONE; - ares->type = LDB_REPLY_DONE; - ret = req->callback(module->ldb, req->context, ares); - req->handle->status = ret; + if (ret == LDB_SUCCESS) { + ares->type = LDB_REPLY_DONE; + + ret = req->callback(module->ldb, req->context, ares); + req->handle->status = ret; + } ltdb_unlock_read(module); diff --git a/source/lib/ldb/ldb_tdb/ldb_tdb.h b/source/lib/ldb/ldb_tdb/ldb_tdb.h index 51e72c1c0f4..4beced30eb7 100644 --- a/source/lib/ldb/ldb_tdb/ldb_tdb.h +++ b/source/lib/ldb/ldb_tdb/ldb_tdb.h @@ -31,6 +31,8 @@ struct ltdb_private { } *cache; int in_transaction; + + bool check_base; }; /* @@ -58,10 +60,12 @@ struct ltdb_context { #define LTDB_IDXATTR "@IDXATTR" #define LTDB_IDXONE "@IDXONE" #define LTDB_BASEINFO "@BASEINFO" +#define LTDB_OPTIONS "@OPTIONS" #define LTDB_ATTRIBUTES "@ATTRIBUTES" /* special attribute types */ #define LTDB_SEQUENCE_NUMBER "sequenceNumber" +#define LTDB_CHECK_BASE "checkBaseOnSearch" #define LTDB_MOD_TIMESTAMP "whenChanged" #define LTDB_OBJECTCLASS "objectClass"