dovecot-2.2: acl: Moved acl_rights array from vfile-specific cod...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Jan 18 00:33:56 EET 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/018c66251db6
changeset: 17115:018c66251db6
user: Timo Sirainen <tss at iki.fi>
date: Fri Jan 17 17:33:47 2014 -0500
description:
acl: Moved acl_rights array from vfile-specific code to generic struct acl_object.
diffstat:
src/plugins/acl/acl-api-private.h | 12 +
src/plugins/acl/acl-api.c | 170 +++++++++++++++++++++
src/plugins/acl/acl-backend-vfile-update.c | 17 +-
src/plugins/acl/acl-backend-vfile.c | 225 ++--------------------------
src/plugins/acl/acl-backend-vfile.h | 3 -
5 files changed, 214 insertions(+), 213 deletions(-)
diffs (truncated from 616 to 300 lines):
diff -r 498fcb82fcb6 -r 018c66251db6 src/plugins/acl/acl-api-private.h
--- a/src/plugins/acl/acl-api-private.h Fri Jan 17 16:23:49 2014 -0500
+++ b/src/plugins/acl/acl-api-private.h Fri Jan 17 17:33:47 2014 -0500
@@ -67,6 +67,9 @@
struct acl_object {
struct acl_backend *backend;
char *name;
+
+ pool_t rights_pool;
+ ARRAY(struct acl_rights) rights;
};
struct acl_object_list_iter {
@@ -78,6 +81,12 @@
extern const char *const all_mailbox_rights[];
+struct acl_object_list_iter *
+acl_default_object_list_init(struct acl_object *aclobj);
+int acl_default_object_list_next(struct acl_object_list_iter *iter,
+ struct acl_rights *rights_r);
+void acl_default_object_list_deinit(struct acl_object_list_iter *iter);
+
const char *const *
acl_backend_mask_get_names(struct acl_backend *backend,
const struct acl_mask *mask, pool_t pool);
@@ -95,6 +104,7 @@
int acl_rights_parse_line(const char *line, pool_t pool,
struct acl_rights *rights_r, const char **error_r);
int acl_rights_cmp(const struct acl_rights *r1, const struct acl_rights *r2);
+void acl_rights_sort(struct acl_object *aclobj);
const char *const *
acl_right_names_parse(pool_t pool, const char *acl, const char **error_r);
@@ -105,5 +115,7 @@
const char *const **rightsp,
const char *const *modify_rights,
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);
#endif
diff -r 498fcb82fcb6 -r 018c66251db6 src/plugins/acl/acl-api.c
--- a/src/plugins/acl/acl-api.c Fri Jan 17 16:23:49 2014 -0500
+++ b/src/plugins/acl/acl-api.c Fri Jan 17 17:33:47 2014 -0500
@@ -185,6 +185,43 @@
iter->aclobj->backend->v.object_list_deinit(iter);
}
+struct acl_object_list_iter *
+acl_default_object_list_init(struct acl_object *aclobj)
+{
+ struct acl_object_list_iter *iter;
+
+ iter = i_new(struct acl_object_list_iter, 1);
+ iter->aclobj = aclobj;
+
+ if (!array_is_created(&aclobj->rights)) {
+ /* we may have the object cached, but we don't have all the
+ rights read into memory */
+ acl_cache_flush(aclobj->backend->cache, aclobj->name);
+ }
+
+ if (aclobj->backend->v.object_refresh_cache(aclobj) < 0)
+ iter->failed = TRUE;
+ return iter;
+}
+
+int acl_default_object_list_next(struct acl_object_list_iter *iter,
+ struct acl_rights *rights_r)
+{
+ const struct acl_rights *rights;
+
+ if (iter->idx == array_count(&iter->aclobj->rights))
+ return 0;
+
+ rights = array_idx(&iter->aclobj->rights, iter->idx++);
+ *rights_r = *rights;
+ return 1;
+}
+
+void acl_default_object_list_deinit(struct acl_object_list_iter *iter)
+{
+ i_free(iter);
+}
+
struct acl_mailbox_list_context *
acl_backend_nonowner_lookups_iter_init(struct acl_backend *backend)
{
@@ -399,6 +436,35 @@
return null_strcmp(r1->identifier, r2->identifier);
}
+void acl_rights_sort(struct acl_object *aclobj)
+{
+ struct acl_rights *rights;
+ unsigned int i, dest, count;
+
+ if (!array_is_created(&aclobj->rights))
+ return;
+
+ array_sort(&aclobj->rights, acl_rights_cmp);
+
+ /* merge identical identifiers */
+ rights = array_get_modifiable(&aclobj->rights, &count);
+ for (dest = 0, i = 1; i < count; i++) {
+ if (acl_rights_cmp(&rights[i], &rights[dest]) == 0) {
+ /* add i's rights to dest and delete i */
+ acl_right_names_merge(aclobj->rights_pool,
+ &rights[dest].rights,
+ rights[i].rights, FALSE);
+ acl_right_names_merge(aclobj->rights_pool,
+ &rights[dest].neg_rights,
+ rights[i].neg_rights, FALSE);
+ } else {
+ if (++dest != i)
+ rights[dest] = rights[i];
+ }
+ }
+ if (++dest != count)
+ array_delete(&aclobj->rights, dest, count - dest);
+}
bool acl_rights_has_nonowner_lookup_changes(const struct acl_rights *rights)
{
@@ -633,3 +699,107 @@
}
return old_rights[i] != NULL || new_rights[i] != NULL;
}
+
+static void apply_owner_default_rights(struct acl_object *aclobj)
+{
+ struct acl_rights_update ru;
+ const char *null = NULL;
+
+ memset(&ru, 0, sizeof(ru));
+ ru.modify_mode = ACL_MODIFY_MODE_REPLACE;
+ ru.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
+ ru.rights.id_type = ACL_ID_OWNER;
+ ru.rights.rights = aclobj->backend->default_rights;
+ ru.rights.neg_rights = &null;
+ acl_cache_update(aclobj->backend->cache, aclobj->name, &ru);
+}
+
+void acl_object_rebuild_cache(struct acl_object *aclobj)
+{
+ struct acl_rights_update ru;
+ enum acl_modify_mode add_mode;
+ const struct acl_rights *rights, *prev_match = NULL;
+ unsigned int i, count;
+ bool first_global = TRUE;
+
+ acl_cache_flush(aclobj->backend->cache, aclobj->name);
+
+ if (!array_is_created(&aclobj->rights))
+ return;
+
+ /* 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);
+ 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 */
+ ru.modify_mode = rights[i].rights == NULL ?
+ ACL_MODIFY_MODE_REMOVE : add_mode;
+ ru.neg_modify_mode = rights[i].neg_rights == NULL ?
+ ACL_MODIFY_MODE_REMOVE : add_mode;
+ ru.rights = rights[i];
+ if (rights[i].global && first_global) {
+ /* first global: reset negative ACLs so local ACLs
+ can't mess things up via them */
+ first_global = FALSE;
+ ru.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
+ }
+ acl_cache_update(aclobj->backend->cache, aclobj->name, &ru);
+ }
+}
+
+void acl_object_remove_all_access(struct acl_object *aclobj)
+{
+ static const char *null = NULL;
+ struct acl_rights rights;
+
+ memset(&rights, 0, sizeof(rights));
+ rights.id_type = ACL_ID_ANYONE;
+ rights.rights = &null;
+ array_append(&aclobj->rights, &rights, 1);
+
+ rights.id_type = ACL_ID_OWNER;
+ rights.rights = &null;
+ array_append(&aclobj->rights, &rights, 1);
+}
diff -r 498fcb82fcb6 -r 018c66251db6 src/plugins/acl/acl-backend-vfile-update.c
--- a/src/plugins/acl/acl-backend-vfile-update.c Fri Jan 17 16:23:49 2014 -0500
+++ b/src/plugins/acl/acl-backend-vfile-update.c Fri Jan 17 17:33:47 2014 -0500
@@ -56,7 +56,7 @@
}
static bool
-vfile_object_modify_right(struct acl_object_vfile *aclobj, unsigned int idx,
+vfile_object_modify_right(struct acl_object *aclobj, unsigned int idx,
const struct acl_rights_update *update)
{
struct acl_rights *right;
@@ -78,7 +78,7 @@
}
static bool
-vfile_object_add_right(struct acl_object_vfile *aclobj, unsigned int idx,
+vfile_object_add_right(struct acl_object *aclobj, unsigned int idx,
const struct acl_rights_update *update)
{
struct acl_rights right;
@@ -129,7 +129,7 @@
}
static int
-acl_backend_vfile_update_write(struct acl_object_vfile *aclobj,
+acl_backend_vfile_update_write(struct acl_object *aclobj,
int fd, const char *path)
{
struct ostream *output;
@@ -193,7 +193,8 @@
int acl_backend_vfile_object_update(struct acl_object *_aclobj,
const struct acl_rights_update *update)
{
- struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
+ struct acl_object_vfile *aclobj =
+ (struct acl_object_vfile *)_aclobj;
struct acl_backend_vfile *backend =
(struct acl_backend_vfile *)_aclobj->backend;
struct acl_backend_vfile_validity *validity;
@@ -212,11 +213,11 @@
if (fd == -1)
return -1;
- if (!array_bsearch_insert_pos(&aclobj->rights, &update->rights,
+ if (!array_bsearch_insert_pos(&_aclobj->rights, &update->rights,
acl_rights_cmp, &i))
- changed = vfile_object_add_right(aclobj, i, update);
+ changed = vfile_object_add_right(_aclobj, i, update);
else
- changed = vfile_object_modify_right(aclobj, i, update);
+ changed = vfile_object_modify_right(_aclobj, i, update);
if (!changed) {
file_dotlock_delete(&dotlock);
return 0;
@@ -228,7 +229,7 @@
/* ACLs were really changed, write the new ones */
path = file_dotlock_get_lock_path(dotlock);
- if (acl_backend_vfile_update_write(aclobj, fd, path) < 0) {
+ if (acl_backend_vfile_update_write(_aclobj, fd, path) < 0) {
file_dotlock_delete(&dotlock);
acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
return -1;
diff -r 498fcb82fcb6 -r 018c66251db6 src/plugins/acl/acl-backend-vfile.c
--- a/src/plugins/acl/acl-backend-vfile.c Fri Jan 17 16:23:49 2014 -0500
+++ b/src/plugins/acl/acl-backend-vfile.c Fri Jan 17 17:33:47 2014 -0500
More information about the dovecot-cvs
mailing list