dovecot-2.2: acl plugin: Added an alternative global ACL file th...

dovecot at dovecot.org dovecot at dovecot.org
Mon Jan 27 16:36:11 EET 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/9376bf098692
changeset: 17118:9376bf098692
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jan 27 16:35:46 2014 +0200
description:
acl plugin: Added an alternative global ACL file that can contain mailbox patterns.
Instead of pointing the global ACL path to a directory use a file instead.
The file format is "<mailbox pattern> <normal ACL line>". Most importantly
this can be used to specify default ACLs for namespaces.

The mailbox pattern uses "*" and "?" wildcards currently. I'm not sure if I
should still change them to IMAP "*" and "%" wildcards. That would make the
behavior more complex ("%" depends on hierarchy separator), slightly slower
and quota code is already also using the */? wildcards..

diffstat:

 src/plugins/acl/Makefile.am         |    2 +
 src/plugins/acl/acl-api-private.h   |    6 +-
 src/plugins/acl/acl-api.c           |   28 +++++
 src/plugins/acl/acl-api.h           |    1 +
 src/plugins/acl/acl-backend-vfile.c |  114 +++++++++++++++------
 src/plugins/acl/acl-backend-vfile.h |    4 +-
 src/plugins/acl/acl-global-file.c   |  191 ++++++++++++++++++++++++++++++++++++
 src/plugins/acl/acl-global-file.h   |   20 +++
 8 files changed, 330 insertions(+), 36 deletions(-)

diffs (truncated from 572 to 300 lines):

diff -r 1a54118f4690 -r 9376bf098692 src/plugins/acl/Makefile.am
--- a/src/plugins/acl/Makefile.am	Mon Jan 27 14:25:03 2014 +0200
+++ b/src/plugins/acl/Makefile.am	Mon Jan 27 16:35:46 2014 +0200
@@ -24,6 +24,7 @@
 	acl-backend-vfile-acllist.c \
 	acl-backend-vfile-update.c \
 	acl-cache.c \
+	acl-global-file.c \
 	acl-lookup-dict.c \
 	acl-mailbox.c \
 	acl-mailbox-list.c \
@@ -36,6 +37,7 @@
 	acl-api-private.h \
 	acl-backend-vfile.h \
 	acl-cache.h \
+	acl-global-file.h \
 	acl-lookup-dict.h \
 	acl-plugin.h \
 	acl-shared-storage.h \
diff -r 1a54118f4690 -r 9376bf098692 src/plugins/acl/acl-api-private.h
--- a/src/plugins/acl/acl-api-private.h	Mon Jan 27 14:25:03 2014 +0200
+++ b/src/plugins/acl/acl-api-private.h	Mon Jan 27 16:35:46 2014 +0200
@@ -49,6 +49,7 @@
 
 	struct mailbox_list *list;
 	struct acl_cache *cache;
+	struct acl_global_file *global_file;
 
 	struct acl_object *default_aclobj;
 	struct acl_mask *default_aclmask;
@@ -69,7 +70,7 @@
 	char *name;
 
 	pool_t rights_pool;
-	ARRAY(struct acl_rights) rights;
+	ARRAY_TYPE(acl_rights) rights;
 };
 
 struct acl_object_list_iter {
@@ -103,6 +104,8 @@
 const char *acl_rights_export(const struct acl_rights *rights);
 int acl_rights_parse_line(const char *line, pool_t pool,
 			  struct acl_rights *rights_r, const char **error_r);
+void acl_rights_dup(const struct acl_rights *src,
+		    pool_t pool, struct acl_rights *dest_r);
 int acl_rights_cmp(const struct acl_rights *r1, const struct acl_rights *r2);
 void acl_rights_sort(struct acl_object *aclobj);
 
@@ -117,5 +120,6 @@
 			    enum acl_modify_mode modify_mode);
 void acl_object_rebuild_cache(struct acl_object *aclobj);
 void acl_object_remove_all_access(struct acl_object *aclobj);
+void acl_object_add_global_acls(struct acl_object *aclobj);
 
 #endif
diff -r 1a54118f4690 -r 9376bf098692 src/plugins/acl/acl-api.c
--- a/src/plugins/acl/acl-api.c	Mon Jan 27 14:25:03 2014 +0200
+++ b/src/plugins/acl/acl-api.c	Mon Jan 27 16:35:46 2014 +0200
@@ -7,6 +7,7 @@
 #include "hash.h"
 #include "mail-user.h"
 #include "mailbox-list.h"
+#include "acl-global-file.h"
 #include "acl-cache.h"
 #include "acl-api-private.h"
 
@@ -420,6 +421,19 @@
 	return 0;
 }
 
+void acl_rights_dup(const struct acl_rights *src,
+		    pool_t pool, struct acl_rights *dest_r)
+{
+	memset(dest_r, 0, sizeof(*dest_r));
+	dest_r->id_type = src->id_type;
+	dest_r->identifier = p_strdup(pool, src->identifier);
+	dest_r->rights = src->rights == NULL ? NULL :
+		p_strarray_dup(pool, src->rights);
+	dest_r->neg_rights = src->neg_rights == NULL ? NULL :
+		p_strarray_dup(pool, src->neg_rights);
+	dest_r->global = src->global;
+}
+
 int acl_rights_cmp(const struct acl_rights *r1, const struct acl_rights *r2)
 {
 	int ret;
@@ -803,3 +817,17 @@
 	rights.rights = &null;
 	array_append(&aclobj->rights, &rights, 1);
 }
+
+void acl_object_add_global_acls(struct acl_object *aclobj)
+{
+	struct acl_backend *backend = aclobj->backend;
+	const char *vname, *error;
+
+	if (mailbox_list_is_valid_name(backend->list, aclobj->name, &error))
+		vname = mailbox_list_get_vname(backend->list, aclobj->name);
+	else
+		vname = "";
+
+	acl_global_file_get(backend->global_file, vname,
+			    aclobj->rights_pool, &aclobj->rights);
+}
diff -r 1a54118f4690 -r 9376bf098692 src/plugins/acl/acl-api.h
--- a/src/plugins/acl/acl-api.h	Mon Jan 27 14:25:03 2014 +0200
+++ b/src/plugins/acl/acl-api.h	Mon Jan 27 16:35:46 2014 +0200
@@ -79,6 +79,7 @@
 	/* These rights are global for all users */
 	unsigned int global:1;
 };
+ARRAY_DEFINE_TYPE(acl_rights, struct acl_rights);
 
 struct acl_rights_update {
 	struct acl_rights rights;
diff -r 1a54118f4690 -r 9376bf098692 src/plugins/acl/acl-backend-vfile.c
--- a/src/plugins/acl/acl-backend-vfile.c	Mon Jan 27 14:25:03 2014 +0200
+++ b/src/plugins/acl/acl-backend-vfile.c	Mon Jan 27 16:35:46 2014 +0200
@@ -6,6 +6,7 @@
 #include "istream.h"
 #include "nfs-workarounds.h"
 #include "mail-storage-private.h"
+#include "acl-global-file.h"
 #include "acl-cache.h"
 #include "acl-backend-vfile.h"
 
@@ -32,10 +33,11 @@
 {
 	struct acl_backend_vfile *backend =
 		(struct acl_backend_vfile *)_backend;
+	struct stat st;
 	const char *const *tmp;
 
 	tmp = t_strsplit(data, ":");
-	backend->global_dir = p_strdup_empty(_backend->pool, *tmp);
+	backend->global_path = p_strdup_empty(_backend->pool, *tmp);
 	backend->cache_secs = ACL_VFILE_DEFAULT_CACHE_SECS;
 
 	if (*tmp != NULL)
@@ -52,10 +54,28 @@
 			return -1;
 		}
 	}
+	if (backend->global_path != NULL) {
+		if (stat(backend->global_path, &st) < 0) {
+			if (errno != ENOENT) {
+				i_error("acl vfile: stat(%s) failed: %m",
+					backend->global_path);
+				return -1;
+			}
+		} else if (!S_ISDIR(st.st_mode)) {
+			_backend->global_file =
+				acl_global_file_init(backend->global_path, backend->cache_secs);
+		}
+	}
 	if (_backend->debug) {
-		i_debug("acl vfile: Global ACL directory: %s",
-			backend->global_dir == NULL ? "(none)" :
-			backend->global_dir);
+		if (backend->global_path == NULL)
+			i_debug("acl vfile: Global ACLs disabled");
+		else if (_backend->global_file != NULL) {
+			i_debug("acl vfile: Global ACL file: %s",
+				backend->global_path);
+		} else {
+			i_debug("acl vfile: Global ACL legacy directory: %s",
+				backend->global_path);
+		}
 	}
 
 	_backend->cache =
@@ -73,28 +93,27 @@
 		array_free(&backend->acllist);
 		pool_unref(&backend->acllist_pool);
 	}
+	if (_backend->global_file != NULL)
+		acl_global_file_deinit(&_backend->global_file);
 	pool_unref(&backend->backend.pool);
 }
 
 static const char *
 acl_backend_vfile_get_local_dir(struct acl_backend *backend,
-				const char *name)
+				const char *name, const char *vname)
 {
 	struct mail_namespace *ns = mailbox_list_get_namespace(backend->list);
 	struct mailbox_list *list = ns->list;
 	struct mail_storage *storage;
 	enum mailbox_list_path_type type;
-	const char *dir, *inbox, *vname, *error;
+	const char *dir, *inbox;
 
 	if (*name == '\0')
 		name = NULL;
-	else if (!mailbox_list_is_valid_name(list, name, &error))
-		return NULL;
 
 	/* ACL files are very important. try to keep them among the main
 	   mail files. that's not possible though with a) if the mailbox is
 	   a file or b) if the mailbox path doesn't point to filesystem. */
-	vname = name == NULL ? "" : mailbox_list_get_vname(backend->list, name);
 	if (mailbox_list_get_storage(&list, vname, &storage) < 0)
 		return NULL;
 	i_assert(list == ns->list);
@@ -104,7 +123,7 @@
 		MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_MAILBOX;
 	if (name == NULL) {
 		if (!mailbox_list_get_root_path(list, type, &dir))
-			return FALSE;
+			return NULL;
 	} else {
 		if (mailbox_list_get_path(list, name, type, &dir) <= 0)
 			return NULL;
@@ -129,22 +148,30 @@
 	struct acl_backend_vfile *backend =
 		(struct acl_backend_vfile *)_backend;
 	struct acl_object_vfile *aclobj;
-	const char *dir, *vname;
+	const char *dir, *vname, *error;
 
 	aclobj = i_new(struct acl_object_vfile, 1);
 	aclobj->aclobj.backend = _backend;
 	aclobj->aclobj.name = i_strdup(name);
 
 	T_BEGIN {
-		if (backend->global_dir != NULL) {
-			vname = mailbox_list_get_vname(backend->backend.list, name);
-			aclobj->global_path =
-				i_strconcat(backend->global_dir, "/", vname, NULL);
+		if (*name == '\0' ||
+		    mailbox_list_is_valid_name(_backend->list, name, &error)) {
+			vname = *name == '\0' ? "" :
+				mailbox_list_get_vname(_backend->list, name);
+
+			dir = acl_backend_vfile_get_local_dir(_backend, name, vname);
+			aclobj->local_path = dir == NULL ? NULL :
+				i_strconcat(dir, "/"ACL_FILENAME, NULL);
+			if (backend->global_path != NULL &&
+			    _backend->global_file == NULL) {
+				aclobj->global_path =
+					i_strconcat(backend->global_path, "/", name, NULL);
+			}
+		} else {
+			/* Invalid mailbox name, just use the default
+			   global ACL files */
 		}
-
-		dir = acl_backend_vfile_get_local_dir(_backend, name);
-		aclobj->local_path = dir == NULL ? NULL :
-			i_strconcat(dir, "/"ACL_FILENAME, NULL);
 	} T_END;
 	return &aclobj->aclobj;
 }
@@ -193,7 +220,8 @@
 	struct acl_backend_vfile *backend =
 		(struct acl_backend_vfile *)_backend;
 	struct acl_backend_vfile_validity *old_validity, new_validity;
-	const char *path, *local_path, *global_path, *dir;
+	const char *path, *local_path, *global_path, *dir, *vname = "";
+	const char *error;
 	int ret;
 
 	old_validity = acl_cache_get_validity(_backend->cache, name);
@@ -212,16 +240,28 @@
 		ret = acl_backend_vfile_exists(backend, path,
 					       &new_validity.mailbox_validity);
 	}
+
 	if (ret == 0 &&
-	    (dir = acl_backend_vfile_get_local_dir(_backend, name)) != NULL) {
-		local_path = t_strconcat(dir, "/", name, NULL);
-		ret = acl_backend_vfile_exists(backend, local_path,
-					       &new_validity.local_validity);
+	    (*name == '\0' ||
+	     mailbox_list_is_valid_name(_backend->list, name, &error))) {
+		vname = *name == '\0' ? "" :
+			mailbox_list_get_vname(_backend->list, name);
+		dir = acl_backend_vfile_get_local_dir(_backend, name, vname);
+		if (dir != NULL) {
+			local_path = t_strconcat(dir, "/", name, NULL);
+			ret = acl_backend_vfile_exists(backend, local_path,
+						       &new_validity.local_validity);
+		}
 	}
-	if (ret == 0 && backend->global_dir != NULL) {
-		global_path = t_strconcat(backend->global_dir, "/", name, NULL);
-		ret = acl_backend_vfile_exists(backend, global_path,
-					       &new_validity.global_validity);
+
+	if (ret == 0 && backend->global_path != NULL) {
+		if (_backend->global_file != NULL)
+			ret = acl_global_file_have_any(_backend->global_file, vname) ? 1 : 0;
+		else {
+			global_path = t_strconcat(backend->global_path, "/", name, NULL);
+			ret = acl_backend_vfile_exists(backend, global_path,
+						       &new_validity.global_validity);
+		}
 	}
 	acl_cache_set_validity(_backend->cache, name, &new_validity);
 	return ret > 0;


More information about the dovecot-cvs mailing list