From af134287071b6d8a9e12c3f11a50fe9ad824d89a Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Fri, 6 Oct 2017 16:55:28 +0300 Subject: [PATCH] acl: Fix checking create (k) permission in global acl-file Just because the global ACL file hasn't changed since it was last refreshed for another ACL object, it doesn't mean that those ACLs don't need to be applied to this ACL object. This didn't usually cause problems, because the initial ACL object refresh was always done due to local-path refresh returning "needs a refresh". The only exception was when acl_object_init_from_parent() was called, because it added an empty non-NULL validity for the local-path, so the "needs a refresh" wasn't returned. This happened only when trying to CREATE or RENAME mailbox under a parent where user didn't have create permissions. This affected only when using a single global acl-file, not when using global acl directory containing per-mailbox files. --- src/plugins/acl/acl-backend-vfile.c | 30 ++++++++++++++++++++++++++--- src/plugins/acl/acl-global-file.c | 5 +++++ src/plugins/acl/acl-global-file.h | 2 ++ 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/plugins/acl/acl-backend-vfile.c b/src/plugins/acl/acl-backend-vfile.c index 46ab558f00..3709999185 100644 --- a/src/plugins/acl/acl-backend-vfile.c +++ b/src/plugins/acl/acl-backend-vfile.c @@ -531,6 +531,23 @@ int acl_backend_vfile_object_get_mtime(struct acl_object *aclobj, return 0; } +static int +acl_backend_global_file_refresh(struct acl_object *_aclobj, + struct acl_vfile_validity *validity) +{ + struct acl_backend_vfile *backend = + (struct acl_backend_vfile *)_aclobj->backend; + struct stat st; + + if (acl_global_file_refresh(_aclobj->backend->global_file) < 0) + return -1; + + acl_global_file_last_stat(_aclobj->backend->global_file, &st); + if (validity == NULL) + return 1; + return acl_vfile_validity_has_changed(backend, validity, &st) ? 1 : 0; +} + static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj) { struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj; @@ -544,7 +561,8 @@ static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj) old_validity = acl_cache_get_validity(_aclobj->backend->cache, _aclobj->name); ret = _aclobj->backend->global_file != NULL ? - acl_global_file_refresh(_aclobj->backend->global_file) : + acl_backend_global_file_refresh(_aclobj, old_validity == NULL ? NULL : + &old_validity->global_validity) : acl_backend_vfile_refresh(_aclobj, aclobj->global_path, old_validity == NULL ? NULL : &old_validity->global_validity); @@ -567,9 +585,15 @@ static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj) } i_zero(&validity); - if (_aclobj->backend->global_file != NULL) + if (_aclobj->backend->global_file != NULL) { + struct stat st; + acl_object_add_global_acls(_aclobj); - else { + acl_global_file_last_stat(_aclobj->backend->global_file, &st); + validity.global_validity.last_read_time = ioloop_time; + validity.global_validity.last_mtime = st.st_mtime; + validity.global_validity.last_size = st.st_size; + } else { if (acl_backend_vfile_read_with_retry(_aclobj, TRUE, aclobj->global_path, &validity.global_validity) < 0) return -1; diff --git a/src/plugins/acl/acl-global-file.c b/src/plugins/acl/acl-global-file.c index e956a8cdd8..7cf49a0323 100644 --- a/src/plugins/acl/acl-global-file.c +++ b/src/plugins/acl/acl-global-file.c @@ -203,6 +203,11 @@ int acl_global_file_refresh(struct acl_global_file *file) return 0; } +void acl_global_file_last_stat(struct acl_global_file *file, struct stat *st_r) +{ + *st_r = file->prev_st; +} + void acl_global_file_get(struct acl_global_file *file, const char *vname, pool_t pool, ARRAY_TYPE(acl_rights) *rights_r) { diff --git a/src/plugins/acl/acl-global-file.h b/src/plugins/acl/acl-global-file.h index 9c5137e417..d393dec6a3 100644 --- a/src/plugins/acl/acl-global-file.h +++ b/src/plugins/acl/acl-global-file.h @@ -10,6 +10,8 @@ void acl_global_file_deinit(struct acl_global_file **file); /* Read the global ACLs into memory. */ int acl_global_file_refresh(struct acl_global_file *file); +/* Return stat data for the last refresh. */ +void acl_global_file_last_stat(struct acl_global_file *file, struct stat *st_r); /* Return global ACL rights matching the mailbox name. The file must already have been refreshed at least once. */ -- 2.47.3