]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict-file: Make sure home_dir doesn't change during operations
authorSiavash Tavakoli <siavash.tavakoli@open-xchange.com>
Fri, 4 Jun 2021 22:00:21 +0000 (23:00 +0100)
committerSiavash Tavakoli <siavash.tavakoli@open-xchange.com>
Thu, 1 Jul 2021 22:30:56 +0000 (23:30 +0100)
file_dict is initialized for a specific user. Keep record of the user's
home_dir and check for all dict operations that the user did not change.

src/lib-dict/dict-file.c

index b101871be7bdf7ad5c0c90d0761b0464f0fb8c84..8a3942fec30d9336ef266622a0748db600c5816c 100644 (file)
@@ -27,6 +27,8 @@ struct file_dict {
        enum file_lock_method lock_method;
 
        char *path;
+       char *home_dir;
+       bool dict_path_checked;
        HASH_TABLE(char *, char *) hash;
        int fd;
 
@@ -52,6 +54,28 @@ static struct dotlock_settings file_dict_dotlock_settings = {
        .use_io_notify = TRUE
 };
 
+static int
+file_dict_ensure_path_home_dir(struct file_dict *dict, const char *home_dir,
+                              const char **error_r)
+{
+       if (null_strcmp(dict->home_dir, home_dir) == 0)
+               return 0;
+
+       if (dict->dict_path_checked) {
+               *error_r = t_strdup_printf("home_dir changed from %s to %s "
+                               "(requested dict was: %s)", dict->home_dir,
+                               home_dir, dict->path);
+               return -1;
+       }
+
+       char *_p = dict->path;
+       dict->path = i_strdup(home_expand_tilde(dict->path, home_dir));
+       dict->home_dir = i_strdup(home_dir);
+       i_free(_p);
+       dict->dict_path_checked = TRUE;
+       return 0;
+}
+
 static int
 file_dict_init(struct dict *driver, const char *uri,
               const struct dict_settings *set ATTR_UNUSED,
@@ -79,6 +103,11 @@ file_dict_init(struct dict *driver, const char *uri,
                        return -1;
                }
        }
+
+       /* keep the path for now, later in dict operations check if home_dir
+          should be prepended. */
+       dict->path = i_strdup(path);
+
        dict->dict = *driver;
        dict->hash_pool = pool_alloconly_create("file dict", 1024);
        hash_table_create(&dict->hash, dict->hash_pool, 0, str_hash, strcmp);
@@ -95,6 +124,7 @@ static void file_dict_deinit(struct dict *_dict)
        hash_table_destroy(&dict->hash);
        pool_unref(&dict->hash_pool);
        i_free(dict->path);
+       i_free(dict->home_dir);
        i_free(dict);
 }
 
@@ -192,12 +222,15 @@ static int file_dict_refresh(struct file_dict *dict, const char **error_r)
 }
 
 static int file_dict_lookup(struct dict *_dict,
-                           const struct dict_op_settings *set ATTR_UNUSED,
+                           const struct dict_op_settings *set,
                            pool_t pool, const char *key,
                            const char **value_r, const char **error_r)
 {
        struct file_dict *dict = (struct file_dict *)_dict;
 
+       if (file_dict_ensure_path_home_dir(dict, set->home_dir, error_r) < 0)
+               return -1;
+
        if (file_dict_refresh(dict, error_r) < 0)
                return -1;
 
@@ -224,7 +257,8 @@ file_dict_iterate_init(struct dict *_dict,
        ctx->path_len = strlen(path);
        ctx->flags = flags;
 
-       if (file_dict_refresh(dict, &error) < 0)
+       if (file_dict_ensure_path_home_dir(dict, set->home_dir, &error) < 0 ||
+           file_dict_refresh(dict, &error) < 0)
                ctx->error = p_strdup(pool, error);
 
        ctx->iter = hash_table_iterate_init(dict->hash);
@@ -520,6 +554,9 @@ file_dict_write_changes(struct dict_transaction_memory_context *ctx,
 
        *atomic_inc_not_found_r = FALSE;
 
+       if (file_dict_ensure_path_home_dir(dict, ctx->ctx.set.home_dir, error_r) < 0)
+               return -1;
+
        switch (dict->lock_method) {
        case FILE_LOCK_METHOD_FCNTL:
        case FILE_LOCK_METHOD_FLOCK: