r7709: - convert ldb to use popt, so that it can interact with the samba
[abartlet/samba.git/.git] / source4 / lib / ldb / ldb_tdb / ldb_tdb.c
index b47d79de528879fe3304b39da691445e695a78ec..596ede8a4e152a4bcf568d76deeecea28392469d 100644 (file)
 
 
 /*
-  casefold a dn. We need to uppercase the attribute names, and the 
-  attribute values of case insensitive attributes. We also need to remove
-  extraneous spaces between elements
+  callback function used in call to ldb_dn_fold() for determining whether an
+  attribute type requires case folding.
 */
-static char *ltdb_dn_fold(struct ldb_module *module, const char *dn)
+static int ltdb_case_fold_attr_required(void * user_data, char *attr)
 {
-       const char *dn_orig = dn;
-       struct ldb_context *ldb = module->ldb;
-       TALLOC_CTX *tmp_ctx = talloc_new(ldb);
-       char *ret;
-       size_t len;
-
-       ret = talloc_strdup(tmp_ctx, "");
-       if (ret == NULL) goto failed;
-
-       while ((len = strcspn(dn, ",")) > 0) {
-               char *p = strchr(dn, '=');
-               char *attr, *value;
-               int flags;
-
-               if (p == NULL || (p-dn) > len) goto failed;
-
-               attr = talloc_strndup(tmp_ctx, dn, p-dn);
-               if (attr == NULL) goto failed;
-
-               /* trim spaces from the attribute name */
-               while (' ' == *attr) attr++;
-               while (' ' == attr[strlen(attr)-1]) {
-                       attr[strlen(attr)-1] = 0;
-               }
-               if (*attr == 0) goto failed;
-
-               value = talloc_strndup(tmp_ctx, p+1, len-(p+1-dn));
-               if (value == NULL) goto failed;
+       struct ldb_module *module = talloc_get_type(user_data, struct ldb_module);
 
-               /* trim spaces from the value */
-               while (' ' == *value) value++;
-               while (' ' == value[strlen(value)-1]) {
-                       value[strlen(value)-1] = 0;
-               }
-               if (*value == 0) goto failed;
-
-               flags = ltdb_attribute_flags(module, attr);
-
-               attr = ldb_casefold(ldb, attr);
-               if (attr == NULL) goto failed;
-               talloc_steal(tmp_ctx, attr);
-
-               if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
-                       value = ldb_casefold(ldb, value);
-                       if (value == NULL) goto failed;
-                       talloc_steal(tmp_ctx, value);
-               }               
-
-               if (dn[len] == ',') {
-                       ret = talloc_asprintf_append(ret, "%s=%s,", attr, value);
-               } else {
-                       ret = talloc_asprintf_append(ret, "%s=%s", attr, value);
-               }
-               if (ret == NULL) goto failed;
-
-               dn += len;
-               if (*dn == ',') dn++;
-       }
-
-       talloc_steal(ldb, ret);
-       talloc_free(tmp_ctx);
-       return ret;
-
-failed:
-       talloc_free(tmp_ctx);
-       return ldb_casefold(ldb, dn_orig);
+       return ltdb_attribute_flags(module, attr) & LTDB_FLAG_CASE_INSENSITIVE;
 }
 
 /*
@@ -172,7 +108,8 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const char *dn)
                }
                talloc_free(attr_name);
        } else {
-               dn_folded = ltdb_dn_fold(module, dn);
+                dn_folded = ldb_dn_fold(module->ldb, dn,
+                                        module, ltdb_case_fold_attr_required);
        }
 
        if (!dn_folded) {
@@ -281,6 +218,33 @@ int ltdb_unlock_read(struct ldb_module *module)
        return 0;
 }
 
+/*
+  check special dn's have valid attributes
+  currently only @ATTRIBUTES is checked
+*/
+int ltdb_check_special_dn(struct ldb_module *module, const struct ldb_message *msg)
+{
+       struct ltdb_private *ltdb = module->private_data;
+       int i, j;
+
+       if (strcmp(msg->dn, LTDB_ATTRIBUTES) != 0) {
+               return 0;
+       }
+
+       /* we have @ATTRIBUTES, let's check attributes are fine */
+       /* should we check that we deny multivalued attributes ? */
+       for (i = 0; i < msg->num_elements; i++) {
+               for (j = 0; j < msg->elements[i].num_values; j++) {
+                       if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) {
+                               ltdb->last_err_string = "Invalid attribute value in an @ATTRIBUTES entry";
+                               return -1;
+                       }
+               }
+       }
+
+       return 0;
+}
+
 
 /*
   we've made a modification to a dn - possibly reindex and 
@@ -351,6 +315,11 @@ static int ltdb_add(struct ldb_module *module, const struct ldb_message *msg)
 
        ltdb->last_err_string = NULL;
 
+       ret = ltdb_check_special_dn(module, msg);
+       if (ret != 0) {
+               return ret;
+       }
+       
        if (ltdb_lock(module, LDBLOCK) != 0) {
                return -1;
        }
@@ -359,7 +328,7 @@ static int ltdb_add(struct ldb_module *module, const struct ldb_message *msg)
                ltdb_unlock(module, LDBLOCK);
                return -1;
        }
-       
+
        ret = ltdb_store(module, msg, TDB_INSERT);
 
        if (ret == 0) {
@@ -736,6 +705,11 @@ static int ltdb_modify(struct ldb_module *module, const struct ldb_message *msg)
 
        ltdb->last_err_string = NULL;
 
+       ret = ltdb_check_special_dn(module, msg);
+       if (ret != 0) {
+               return ret;
+       }
+       
        if (ltdb_lock(module, LDBLOCK) != 0) {
                return -1;
        }
@@ -772,6 +746,11 @@ static int ltdb_rename(struct ldb_module *module, const char *olddn, const char
                return -1;
        }
 
+       if (ltdb_cache_load(module) != 0) {
+               ltdb_unlock(module, LDBLOCK);
+               return -1;
+       }
+
        msg = talloc(module, struct ldb_message);
        if (msg == NULL) {
                goto failed;
@@ -829,15 +808,16 @@ static const char *ltdb_errstring(struct ldb_module *module)
 
 
 static const struct ldb_module_ops ltdb_ops = {
-       "tdb",
-       ltdb_search,
-       ltdb_add,
-       ltdb_modify,
-       ltdb_delete,
-       ltdb_rename,
-       ltdb_lock,
-       ltdb_unlock,
-       ltdb_errstring
+       .name          = "tdb",
+       .search        = ltdb_search,
+       .search_bytree = ltdb_search_bytree,
+       .add_record    = ltdb_add,
+       .modify_record = ltdb_modify,
+       .delete_record = ltdb_delete,
+       .rename_record = ltdb_rename,
+       .named_lock    = ltdb_lock,
+       .named_unlock  = ltdb_unlock,
+       .errstring     = ltdb_errstring
 };
 
 
@@ -854,28 +834,19 @@ static int ltdb_destructor(void *p)
 /*
   connect to the database
 */
-struct ldb_context *ltdb_connect(const char *url, 
-                                unsigned int flags, 
-                                const char *options[])
+int ltdb_connect(struct ldb_context *ldb, const char *url, 
+                unsigned int flags, const char *options[])
 {
        const char *path;
        int tdb_flags, open_flags;
        struct ltdb_private *ltdb;
        TDB_CONTEXT *tdb;
-       struct ldb_context *ldb;
-
-       ldb = talloc_zero(NULL, struct ldb_context);
-       if (!ldb) {
-               errno = ENOMEM;
-               return NULL;
-       }
 
        /* parse the url */
        if (strchr(url, ':')) {
                if (strncmp(url, "tdb://", 6) != 0) {
-                       errno = EINVAL;
-                       talloc_free(ldb);
-                       return NULL;
+                       ldb_debug(ldb, LDB_DEBUG_ERROR, "Invalid tdb URL '%s'", url);
+                       return -1;
                }
                path = url+6;
        } else {
@@ -893,16 +864,15 @@ struct ldb_context *ltdb_connect(const char *url,
        /* note that we use quite a large default hash size */
        tdb = tdb_open(path, 10000, tdb_flags, open_flags, 0666);
        if (!tdb) {
-               talloc_free(ldb);
-               return NULL;
+               ldb_debug(ldb, LDB_DEBUG_ERROR, "Unable to open tdb '%s'", path);
+               return -1;
        }
 
        ltdb = talloc_zero(ldb, struct ltdb_private);
        if (!ltdb) {
                tdb_close(tdb);
-               talloc_free(ldb);
-               errno = ENOMEM;
-               return NULL;
+               ldb_oom(ldb);
+               return -1;
        }
 
        ltdb->tdb = tdb;
@@ -912,14 +882,14 @@ struct ldb_context *ltdb_connect(const char *url,
 
        ldb->modules = talloc(ldb, struct ldb_module);
        if (!ldb->modules) {
-               talloc_free(ldb);
-               errno = ENOMEM;
-               return NULL;
+               ldb_oom(ldb);
+               talloc_free(ltdb);
+               return -1;
        }
        ldb->modules->ldb = ldb;
        ldb->modules->prev = ldb->modules->next = NULL;
        ldb->modules->private_data = ltdb;
        ldb->modules->ops = &ltdb_ops;
 
-       return ldb;
+       return 0;
 }