changeset 22582:954ccfeef2f4

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.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 06 Oct 2017 16:55:28 +0300
parents 55a7f5a381cd
children 21c8f6efa1e3
files src/plugins/acl/acl-backend-vfile.c src/plugins/acl/acl-global-file.c src/plugins/acl/acl-global-file.h
diffstat 3 files changed, 34 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/acl/acl-backend-vfile.c	Fri Oct 06 16:54:20 2017 +0300
+++ b/src/plugins/acl/acl-backend-vfile.c	Fri Oct 06 16:55:28 2017 +0300
@@ -532,6 +532,23 @@
 	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;
@@ -545,7 +562,8 @@
 	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);
@@ -568,9 +586,15 @@
 	}
 
 	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;
--- a/src/plugins/acl/acl-global-file.c	Fri Oct 06 16:54:20 2017 +0300
+++ b/src/plugins/acl/acl-global-file.c	Fri Oct 06 16:55:28 2017 +0300
@@ -203,6 +203,11 @@
 	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)
 {
--- a/src/plugins/acl/acl-global-file.h	Fri Oct 06 16:54:20 2017 +0300
+++ b/src/plugins/acl/acl-global-file.h	Fri Oct 06 16:55:28 2017 +0300
@@ -10,6 +10,8 @@
 
 /* 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. */