]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
acl: Fix checking create (k) permission in global acl-file
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 6 Oct 2017 13:55:28 +0000 (16:55 +0300)
committerTimo Sirainen <tss@dovecot.fi>
Fri, 6 Oct 2017 20:46:32 +0000 (23:46 +0300)
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
src/plugins/acl/acl-global-file.c
src/plugins/acl/acl-global-file.h

index 46ab558f001ead042211667517aac2cb48d68258..37099991852927a822f4a7b44447ff570a5547f6 100644 (file)
@@ -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;
index e956a8cdd830050500e0ad0f2ede6809c95d219f..7cf49a0323c4c1239eddac7b9e824cc22e3b5934 100644 (file)
@@ -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)
 {
index 9c5137e4173f226fa195bafd60950fe4561a28b8..d393dec6a35c6c7ab9600ae57b00be26636c6ffd 100644 (file)
@@ -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. */