From: Timo Sirainen Date: Thu, 18 Sep 2025 19:35:48 +0000 (+0300) Subject: acl: Add acl_dict_index setting to rebuild ACL dict without iterating the whole dict X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bae7fe4694d61c9fdb226ea45b05f4dcabde130f;p=thirdparty%2Fdovecot%2Fcore.git acl: Add acl_dict_index setting to rebuild ACL dict without iterating the whole dict --- diff --git a/src/plugins/acl/acl-backend-vfile-acllist.c b/src/plugins/acl/acl-backend-vfile-acllist.c index 75efdece33..10d90b3fe7 100644 --- a/src/plugins/acl/acl-backend-vfile-acllist.c +++ b/src/plugins/acl/acl-backend-vfile-acllist.c @@ -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)); diff --git a/src/plugins/acl/acl-lookup-dict.c b/src/plugins/acl/acl-lookup-dict.c index fd09542389..6f16852f98 100644 --- a/src/plugins/acl/acl-lookup-dict.c +++ b/src/plugins/acl/acl-lookup-dict.c @@ -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; } diff --git a/src/plugins/acl/acl-lookup-dict.h b/src/plugins/acl/acl-lookup-dict.h index 3ed2da4c61..bad46a0515 100644 --- a/src/plugins/acl/acl-lookup-dict.h +++ b/src/plugins/acl/acl-lookup-dict.h @@ -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, diff --git a/src/plugins/acl/acl-settings.c b/src/plugins/acl/acl-settings.c index a26500881d..37fa2ad183 100644 --- a/src/plugins/acl/acl-settings.c +++ b/src/plugins/acl/acl-settings.c @@ -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, diff --git a/src/plugins/acl/acl-settings.h b/src/plugins/acl/acl-settings.h index eca4564f2d..663d59dadc 100644 --- a/src/plugins/acl/acl-settings.h +++ b/src/plugins/acl/acl-settings.h @@ -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; diff --git a/src/plugins/acl/doveadm-acl.c b/src/plugins/acl/doveadm-acl.c index 1c7ff5f4d0..81b4676da3 100644 --- a/src/plugins/acl/doveadm-acl.c +++ b/src/plugins/acl/doveadm-acl.c @@ -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;