]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
acl: Add acl_dict_index setting to rebuild ACL dict without iterating the whole dict
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 18 Sep 2025 19:35:48 +0000 (22:35 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 18 Sep 2025 21:07:49 +0000 (00:07 +0300)
src/plugins/acl/acl-backend-vfile-acllist.c
src/plugins/acl/acl-lookup-dict.c
src/plugins/acl/acl-lookup-dict.h
src/plugins/acl/acl-settings.c
src/plugins/acl/acl-settings.h
src/plugins/acl/doveadm-acl.c

index 75efdece3343e7c02c34460f484c2f94b5bf99dd..10d90b3fe752047aa9766fe5cd5826e6d44e0c4c 100644 (file)
@@ -309,8 +309,8 @@ acl_backend_vfile_acllist_try_rebuild(struct acl_backend_vfile *backend)
                i_assert(auser != NULL);
                backend->acllist_mtime = st.st_mtime;
                backend->acllist_last_check = ioloop_time;
-               /* FIXME: dict rebuild is expensive, try to avoid it */
-               (void)acl_lookup_dict_rebuild(auser->acl_lookup_dict);
+               (void)acl_lookup_dict_rebuild(auser->acl_lookup_dict,
+                       backend->backend.set->acl_dict_index);
        } else {
                acllist_clear(backend, 0);
                i_unlink_if_exists(str_c(path));
index fd09542389ca1d6ec9076f414f0f1a999a4207f7..6f16852f98ed4ac460df7660d570c5632ff5aec9 100644 (file)
@@ -14,6 +14,7 @@
 
 
 #define DICT_SHARED_BOXES_PATH "shared-boxes/"
+#define DICT_SHARED_USER_BOXES_PATH_REV "shared-user-boxes-rev/"
 
 extern struct event_category event_category_acl;
 
@@ -147,7 +148,7 @@ static int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
 static int
 acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
                               const ARRAY_TYPE(const_string) *new_ids_arr,
-                              bool no_removes)
+                              bool no_removes, bool acl_dict_index)
 {
        struct event *event = dict->event;
        const char *username = dict->user->username;
@@ -168,15 +169,42 @@ acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
           that aren't visible to us, so we don't want to remove anything
           that could break them. */
        t_array_init(&old_ids_arr, 128);
-       prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
-       prefix_len = strlen(prefix);
-       iter = dict_iterate_init(dict->dict, set, prefix, DICT_ITERATE_FLAG_RECURSE);
-       while (dict_iterate(iter, &key, &value)) {
-               /* prefix/$type/$dest/$source */
-               key += prefix_len;
-               p = strrchr(key, '/');
-               if (p != NULL && strcmp(p + 1, username) == 0) {
-                       key = t_strdup_until(key, p);
+       if (!acl_dict_index) {
+               prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
+               prefix_len = strlen(prefix);
+               iter = dict_iterate_init(dict->dict, set, prefix, DICT_ITERATE_FLAG_RECURSE);
+               while (dict_iterate(iter, &key, &value)) {
+                       /* prefix/$type/$dest/$source */
+                       key += prefix_len;
+                       p = strrchr(key, '/');
+                       if (p != NULL && strcmp(p + 1, username) == 0) {
+                               key = t_strdup_until(key, p);
+                               array_push_back(&old_ids_arr, &key);
+                       }
+               }
+       } else {
+               key = t_strdup_printf(DICT_PATH_SHARED
+                                     DICT_SHARED_BOXES_PATH"anyone/%s",
+                                     username);
+               ret = dict_lookup(dict->dict, set, pool_datastack_create(),
+                                 key, &value, &error);
+               if (ret < 0) {
+                       e_error(event, "dict_lookup(%s) failed: %s - can't update dict",
+                               key, error);
+                       return -1;
+               }
+               if (ret > 0) {
+                       key = t_strdup_printf("anyone/%s", username);
+                       array_push_back(&old_ids_arr, &key);
+               }
+               prefix = t_strdup_printf(DICT_PATH_SHARED
+                                        DICT_SHARED_USER_BOXES_PATH_REV"%s/",
+                                        username);
+               prefix_len = strlen(prefix);
+               iter = dict_iterate_init(dict->dict, set, prefix, DICT_ITERATE_FLAG_RECURSE);
+               while (dict_iterate(iter, &key, &value)) {
+                       /* prefix/$dest */
+                       key = t_strdup_printf("user/%s", key + prefix_len);
                        array_push_back(&old_ids_arr, &key);
                }
        }
@@ -190,7 +218,8 @@ acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
 
        /* sync the identifiers */
        path = t_str_new(256);
-       str_append(path, prefix);
+       str_append(path, DICT_PATH_SHARED DICT_SHARED_BOXES_PATH);
+       prefix_len = str_len(path);
 
        old_ids = array_get(&old_ids_arr, &old_count);
        new_ids = array_get(new_ids_arr, &new_count);
@@ -226,7 +255,7 @@ acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
        return 0;
 }
 
-int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
+int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict, bool acl_dict_index)
 {
        struct mail_namespace *ns;
        ARRAY_TYPE(const_string) ids_arr;
@@ -259,7 +288,8 @@ int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
 
        /* if lookup failed at some point we can still add new ids,
           but we can't remove any existing ones */
-       if (acl_lookup_dict_rebuild_update(dict, &ids_arr, ret < 0) < 0)
+       if (acl_lookup_dict_rebuild_update(dict, &ids_arr, ret < 0,
+                                          acl_dict_index) < 0)
                ret = -1;
        return ret;
 }
index 3ed2da4c610dd722ce8edf29c8d48e286cb5a642..bad46a05156ed59b9cffe0210b20a485e2fbf424 100644 (file)
@@ -9,7 +9,7 @@ void acl_lookup_dict_deinit(struct acl_lookup_dict **dict);
 
 bool acl_lookup_dict_is_enabled(struct acl_lookup_dict *dict);
 
-int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict);
+int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict, bool acl_dict_index);
 
 struct acl_lookup_dict_iter *
 acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict,
index a26500881d460d2611e8a77d679d56b9c16f3a4d..37fa2ad183c7bc2ef7502cf7acd5c13631672d8e 100644 (file)
@@ -53,6 +53,7 @@ static const struct setting_define acl_setting_defines[] = {
        DEF(BOOL, acl_globals_only),
        DEF(BOOL, acl_defaults_from_inbox),
        DEF(BOOL, acl_ignore),
+       DEF(BOOL, acl_dict_index),
        { .type = SET_FILTER_NAME, .key = "acl_sharing_map",
                .required_setting = "dict", },
        { .type = SET_FILTER_ARRAY,
@@ -73,6 +74,11 @@ static const struct acl_settings acl_default_settings = {
        .acl_globals_only = FALSE,
        .acl_defaults_from_inbox = FALSE,
        .acl_ignore = FALSE,
+#ifdef DOVECOT_PRO_EDITION
+       .acl_dict_index = TRUE,
+#else
+       .acl_dict_index = FALSE,
+#endif
 };
 
 static bool acl_settings_check(void *_set ATTR_UNUSED, pool_t pool ATTR_UNUSED,
index eca4564f2dd1583ef961098a31f19e2f1d23f5b0..663d59dadc54dc94ab1a60a2546ae3435bea57d0 100644 (file)
@@ -24,6 +24,7 @@ struct acl_settings {
        bool acl_globals_only;
        bool acl_defaults_from_inbox;
        bool acl_ignore;
+       bool acl_dict_index;
 };
 
 extern const struct setting_parser_info acl_rights_setting_parser_info;
index 1c7ff5f4d08fdffe6bcf513b140dc37e8e00ce54..81b4676da313d988bc4f399ed071c208ff300bf1 100644 (file)
@@ -345,7 +345,7 @@ cmd_acl_recalc_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user)
                doveadm_mail_failed_error(ctx, MAIL_ERROR_NOTFOUND);
                return -1;
        }
-       if (acl_lookup_dict_rebuild(auser->acl_lookup_dict) < 0) {
+       if (acl_lookup_dict_rebuild(auser->acl_lookup_dict, FALSE) < 0) {
                e_error(user->event, "Failed to recalculate ACL dicts");
                doveadm_mail_failed_error(ctx, MAIL_ERROR_TEMP);
                return -1;
@@ -501,7 +501,7 @@ static bool cmd_acl_debug_mailbox(struct mailbox *box, bool *retry_r)
        if (name == NULL) {
                e_error(box->event, "User %s not found from ACL shared dict, rebuilding",
                        ns->owner->username);
-               if (acl_lookup_dict_rebuild(auser->acl_lookup_dict) < 0)
+               if (acl_lookup_dict_rebuild(auser->acl_lookup_dict, FALSE) < 0)
                        i_fatal("ACL lookup dict rebuild failed");
                all_ok = FALSE;
                *retry_r = TRUE;