]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
acl: Avoid opening two dict iterators at the same time.
authorTimo Sirainen <tss@iki.fi>
Thu, 30 Sep 2010 19:28:54 +0000 (20:28 +0100)
committerTimo Sirainen <tss@iki.fi>
Thu, 30 Sep 2010 19:28:54 +0000 (20:28 +0100)
src/plugins/acl/acl-lookup-dict.c

index f396f7f0a6cff97dfe55f33c517c05a9cc861b90..4f629bf7e11129109a3d0b9bff65c8632c3094b6 100644 (file)
@@ -24,12 +24,10 @@ struct acl_lookup_dict_iter {
        pool_t pool;
        struct acl_lookup_dict *dict;
 
+       pool_t iter_value_pool;
        ARRAY_TYPE(const_string) iter_ids;
-       struct dict_iterate_context *dict_iter;
-       unsigned int iter_idx;
-
-       const char *prefix;
-       unsigned int prefix_len;
+       ARRAY_TYPE(const_string) iter_values;
+       unsigned int iter_idx, iter_value_idx;
 
        unsigned int failed:1;
 };
@@ -245,18 +243,35 @@ int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
        return ret;
 }
 
-static void acl_lookup_dict_iterate_start(struct acl_lookup_dict_iter *iter)
+static void acl_lookup_dict_iterate_read(struct acl_lookup_dict_iter *iter)
 {
-       const char *const *idp;
+       struct dict_iterate_context *dict_iter;
+       const char *const *idp, *prefix, *key, *value;
+       unsigned int prefix_len;
 
        idp = array_idx(&iter->iter_ids, iter->iter_idx);
        iter->iter_idx++;
-       iter->prefix = p_strconcat(iter->pool, DICT_PATH_SHARED
-                                  DICT_SHARED_BOXES_PATH, *idp, "/", NULL);
-       iter->prefix_len = strlen(iter->prefix);
+       iter->iter_value_idx = 0;
+
+       prefix = t_strconcat(DICT_PATH_SHARED DICT_SHARED_BOXES_PATH,
+                            *idp, "/", NULL);
+       prefix_len = strlen(prefix);
 
-       iter->dict_iter = dict_iterate_init(iter->dict->dict, iter->prefix,
-                                           DICT_ITERATE_FLAG_RECURSE);
+       /* read all of it to memory. at least currently dict-proxy can support
+          only one iteration at a time, but the acl code can end up rebuilding
+          the dict, which opens another iteration. */
+       p_clear(iter->iter_value_pool);
+       array_clear(&iter->iter_values);
+       dict_iter = dict_iterate_init(iter->dict->dict, prefix,
+                                     DICT_ITERATE_FLAG_RECURSE);
+       while (dict_iterate(dict_iter, &key, &value)) {
+               i_assert(prefix_len < strlen(key));
+
+               key = p_strdup(iter->iter_value_pool, key + prefix_len);
+               array_append(&iter->iter_values, &key, 1);
+       }
+       if (dict_iterate_deinit(&dict_iter) < 0)
+               iter->failed = TRUE;
 }
 
 struct acl_lookup_dict_iter *
@@ -268,7 +283,7 @@ acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
        unsigned int i;
        pool_t pool;
 
-       pool = pool_alloconly_create("acl lookup dict iter", 512);
+       pool = pool_alloconly_create("acl lookup dict iter", 1024);
        iter = p_new(pool, struct acl_lookup_dict_iter, 1);
        iter->pool = pool;
        iter->dict = dict;
@@ -279,6 +294,10 @@ acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
        id = p_strconcat(pool, "user/", dict->user->username, NULL);
        array_append(&iter->iter_ids, &id, 1);
 
+       i_array_init(&iter->iter_values, 64);
+       iter->iter_value_pool =
+               pool_alloconly_create("acl lookup dict iter values", 1024);
+
        /* get all groups we belong to */
        if (auser->groups != NULL) {
                for (i = 0; auser->groups[i] != NULL; i++) {
@@ -291,28 +310,23 @@ acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
        /* iterate through all identifiers that match us, start with the
           first one */
        if (dict->dict != NULL)
-               acl_lookup_dict_iterate_start(iter);
+               acl_lookup_dict_iterate_read(iter);
        return iter;
 }
 
 const char *
 acl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
 {
-       const char *key, *value;
-
-       if (iter->dict_iter == NULL)
-               return 0;
+       const char *const *keys;
+       unsigned int count;
 
-       if (dict_iterate(iter->dict_iter, &key, &value)) {
-               i_assert(iter->prefix_len < strlen(key));
-               return key + iter->prefix_len;
-       }
-       if (dict_iterate_deinit(&iter->dict_iter) < 0)
-               iter->failed = TRUE;
+       keys = array_get(&iter->iter_values, &count);
+       if (iter->iter_value_idx < count)
+               return keys[iter->iter_value_idx++];
 
        if (iter->iter_idx < array_count(&iter->iter_ids)) {
                /* get to the next iterator */
-               acl_lookup_dict_iterate_start(iter);
+               acl_lookup_dict_iterate_read(iter);
                return acl_lookup_dict_iterate_visible_next(iter);
        }
        return NULL;
@@ -324,10 +338,8 @@ int acl_lookup_dict_iterate_visible_deinit(struct acl_lookup_dict_iter **_iter)
        int ret = iter->failed ? -1 : 0;
 
        *_iter = NULL;
-       if (iter->dict_iter != NULL) {
-               if (dict_iterate_deinit(&iter->dict_iter) < 0)
-                       ret = -1;
-       }
+       array_free(&iter->iter_values);
+       pool_unref(&iter->iter_value_pool);
        pool_unref(&iter->pool);
        return ret;
 }