r25959: Add a new special DN to LDB: @OPTIONS
authorAndrew Bartlett <abartlet@samba.org>
Thu, 15 Nov 2007 00:53:44 +0000 (01:53 +0100)
committerStefan Metzmacher <metze@samba.org>
Fri, 21 Dec 2007 04:45:18 +0000 (05:45 +0100)
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
(This used to be commit deaac92f439ef001bfe052df170d6e34e8ba5845)

source4/lib/ldb/ldb_tdb/ldb_cache.c
source4/lib/ldb/ldb_tdb/ldb_search.c
source4/lib/ldb/ldb_tdb/ldb_tdb.h

index de489e3d8b3325eb51fd669ba4a37892f7ae41ca..77922a97c78f25bfe69460cdd46d54411eb32d46 100644 (file)
@@ -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;i<msg->num_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(&ltdb->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);
index 8151b458d4d769cf199bb8bb078844a6080618ca..1fa20740a51c2d4430ee8954f8173c888936aa0a 100644 (file)
@@ -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);
 
index 51e72c1c0f49ab42361e19dcaa19b7e6bb5e1fff..4beced30eb77b42ad9f76d505223b9301d88a5bf 100644 (file)
@@ -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"