dovecot-1.2: acl: Fixed the logic of merging multiple ACLs.
dovecot at dovecot.org
dovecot at dovecot.org
Fri Oct 1 17:46:41 EEST 2010
details: http://hg.dovecot.org/dovecot-1.2/rev/fd607e10e75d
changeset: 9617:fd607e10e75d
user: Timo Sirainen <tss at iki.fi>
date: Fri Oct 01 15:37:19 2010 +0100
description:
acl: Fixed the logic of merging multiple ACLs.
diffstat:
src/plugins/acl/acl-api.h | 3 +
src/plugins/acl/acl-backend-vfile.c | 62 ++++++++++++++++++++++---------
src/plugins/acl/acl-backend.c | 21 ++++++++++
src/plugins/acl/acl-cache.c | 36 +-----------------
4 files changed, 70 insertions(+), 52 deletions(-)
diffs (198 lines):
diff -r 9e824012da57 -r fd607e10e75d src/plugins/acl/acl-api.h
--- a/src/plugins/acl/acl-api.h Mon Jan 25 20:40:25 2010 +0200
+++ b/src/plugins/acl/acl-api.h Fri Oct 01 15:37:19 2010 +0100
@@ -110,6 +110,9 @@
/* Returns index for the right name. If it doesn't exist, it's created. */
unsigned int acl_backend_lookup_right(struct acl_backend *backend,
const char *right);
+/* Returns TRUE if acl_rights matches backend user. */
+bool acl_backend_rights_match_me(struct acl_backend *backend,
+ const struct acl_rights *rights);
/* List mailboxes that have lookup right to some non-owners. */
struct acl_mailbox_list_context *
diff -r 9e824012da57 -r fd607e10e75d src/plugins/acl/acl-backend-vfile.c
--- a/src/plugins/acl/acl-backend-vfile.c Mon Jan 25 20:40:25 2010 +0200
+++ b/src/plugins/acl/acl-backend-vfile.c Fri Oct 01 15:37:19 2010 +0100
@@ -742,7 +742,7 @@
array_delete(&aclobj->rights, dest, count - dest);
}
-static void apply_owner_rights(struct acl_object *_aclobj)
+static void apply_owner_default_rights(struct acl_object *_aclobj)
{
struct acl_rights_update ru;
const char *null = NULL;
@@ -762,9 +762,9 @@
struct acl_object *_aclobj = &aclobj->aclobj;
struct acl_rights_update ru;
enum acl_modify_mode add_mode;
- const struct acl_rights *rights;
+ const struct acl_rights *rights, *prev_match = NULL;
unsigned int i, count;
- bool owner_applied, first_global = TRUE;
+ bool first_global = TRUE;
acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
@@ -772,26 +772,54 @@
return;
ns = mailbox_list_get_namespace(_aclobj->backend->list);
- owner_applied = ns->type != NAMESPACE_PRIVATE;
+ /* Rights are sorted by their 1) locals first, globals next,
+ 2) acl_id_type. We'll apply only the rights matching ourself.
+
+ Every time acl_id_type or local/global changes, the new ACLs will
+ replace all of the existing ACLs. Basically this means that if
+ user belongs to multiple matching groups or group-overrides, their
+ ACLs are merged. In all other situations the ACLs are replaced
+ (because there aren't duplicate rights entries and a user can't
+ match multiple usernames). */
memset(&ru, 0, sizeof(ru));
rights = array_get(&aclobj->rights, &count);
- for (i = 0; i < count; i++) {
- if (!owner_applied &&
- (rights[i].id_type >= ACL_ID_OWNER || rights[i].global)) {
- owner_applied = TRUE;
- if (rights[i].id_type != ACL_ID_OWNER) {
- /* owner rights weren't explicitly specified.
- replace all the current rights */
- apply_owner_rights(_aclobj);
- }
+ if (!acl_backend_user_is_owner(_aclobj->backend))
+ i = 0;
+ else {
+ /* we're the owner. skip over all rights entries until we
+ reach ACL_ID_OWNER or higher, or alternatively when we
+ reach a global ACL (even ACL_ID_ANYONE overrides owner's
+ rights if it's global) */
+ for (i = 0; i < count; i++) {
+ if (rights[i].id_type >= ACL_ID_OWNER ||
+ rights[i].global)
+ break;
}
+ apply_owner_default_rights(_aclobj);
+ /* now continue applying the rest of the rights,
+ if there are any */
+ }
+ for (; i < count; i++) {
+ if (!acl_backend_rights_match_me(_aclobj->backend, &rights[i]))
+ continue;
+
+ if (prev_match == NULL ||
+ prev_match->id_type != rights[i].id_type ||
+ prev_match->global != rights[i].global) {
+ /* replace old ACLs */
+ add_mode = ACL_MODIFY_MODE_REPLACE;
+ } else {
+ /* merging to existing ACLs */
+ i_assert(rights[i].id_type == ACL_ID_GROUP ||
+ rights[i].id_type == ACL_ID_GROUP_OVERRIDE);
+ add_mode = ACL_MODIFY_MODE_ADD;
+ }
+ prev_match = &rights[i];
+
/* If [neg_]rights is NULL it needs to be ignored.
The easiest way to do that is to just mark it with
REMOVE mode */
- add_mode = i > 0 && rights[i-1].id_type == rights[i].id_type &&
- rights[i-1].global == rights[i].global ?
- ACL_MODIFY_MODE_ADD : ACL_MODIFY_MODE_REPLACE;
ru.modify_mode = rights[i].rights == NULL ?
ACL_MODIFY_MODE_REMOVE : add_mode;
ru.neg_modify_mode = rights[i].neg_rights == NULL ?
@@ -805,8 +833,6 @@
}
acl_cache_update(_aclobj->backend->cache, _aclobj->name, &ru);
}
- if (!owner_applied && count > 0)
- apply_owner_rights(_aclobj);
}
static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj)
diff -r 9e824012da57 -r fd607e10e75d src/plugins/acl/acl-backend.c
--- a/src/plugins/acl/acl-backend.c Mon Jan 25 20:40:25 2010 +0200
+++ b/src/plugins/acl/acl-backend.c Fri Oct 01 15:37:19 2010 +0100
@@ -128,6 +128,27 @@
sizeof(const char *), bsearch_strcmp) != NULL;
}
+bool acl_backend_rights_match_me(struct acl_backend *backend,
+ const struct acl_rights *rights)
+{
+ switch (rights->id_type) {
+ case ACL_ID_ANYONE:
+ return TRUE;
+ case ACL_ID_AUTHENTICATED:
+ return acl_backend_user_is_authenticated(backend);
+ case ACL_ID_GROUP:
+ case ACL_ID_GROUP_OVERRIDE:
+ return acl_backend_user_is_in_group(backend, rights->identifier);
+ case ACL_ID_USER:
+ return acl_backend_user_name_equals(backend, rights->identifier);
+ case ACL_ID_OWNER:
+ return acl_backend_user_is_owner(backend);
+ case ACL_ID_TYPE_COUNT:
+ break;
+ }
+ i_unreached();
+}
+
unsigned int acl_backend_lookup_right(struct acl_backend *backend,
const char *right)
{
diff -r 9e824012da57 -r fd607e10e75d src/plugins/acl/acl-cache.c
--- a/src/plugins/acl/acl-cache.c Mon Jan 25 20:40:25 2010 +0200
+++ b/src/plugins/acl/acl-cache.c Fri Oct 01 15:37:19 2010 +0100
@@ -284,9 +284,8 @@
return obj_cache;
}
-static void
-acl_cache_update_rights(struct acl_cache *cache, const char *objname,
- const struct acl_rights_update *update)
+void acl_cache_update(struct acl_cache *cache, const char *objname,
+ const struct acl_rights_update *update)
{
struct acl_object_cache *obj_cache;
bool created;
@@ -310,37 +309,6 @@
&obj_cache->my_neg_rights);
}
-void acl_cache_update(struct acl_cache *cache, const char *objname,
- const struct acl_rights_update *update)
-{
- switch (update->rights.id_type) {
- case ACL_ID_ANYONE:
- acl_cache_update_rights(cache, objname, update);
- break;
- case ACL_ID_AUTHENTICATED:
- if (acl_backend_user_is_authenticated(cache->backend))
- acl_cache_update_rights(cache, objname, update);
- break;
- case ACL_ID_GROUP:
- case ACL_ID_GROUP_OVERRIDE:
- if (acl_backend_user_is_in_group(cache->backend,
- update->rights.identifier))
- acl_cache_update_rights(cache, objname, update);
- break;
- case ACL_ID_USER:
- if (acl_backend_user_name_equals(cache->backend,
- update->rights.identifier))
- acl_cache_update_rights(cache, objname, update);
- break;
- case ACL_ID_OWNER:
- if (acl_backend_user_is_owner(cache->backend))
- acl_cache_update_rights(cache, objname, update);
- break;
- case ACL_ID_TYPE_COUNT:
- i_unreached();
- }
-}
-
void acl_cache_set_validity(struct acl_cache *cache, const char *objname,
const void *validity)
{
More information about the dovecot-cvs
mailing list