dovecot-1.2: Global ACLs now override all local ACLs.
dovecot at dovecot.org
dovecot at dovecot.org
Sun Nov 16 01:34:34 EET 2008
details: http://hg.dovecot.org/dovecot-1.2/rev/d486dfe02c1e
changeset: 8414:d486dfe02c1e
user: Timo Sirainen <tss at iki.fi>
date: Sun Nov 16 00:15:15 2008 +0200
description:
Global ACLs now override all local ACLs.
Also did some some internal in anticipation of ACL file update code.
diffstat:
4 files changed, 174 insertions(+), 97 deletions(-)
src/plugins/acl/acl-api.h | 3
src/plugins/acl/acl-backend-vfile.c | 199 +++++++++++++++++++++++++----------
src/plugins/acl/acl-cache.c | 66 +++--------
src/plugins/acl/acl-cache.h | 3
diffs (truncated from 447 to 300 lines):
diff -r 24c8bc8098ee -r d486dfe02c1e src/plugins/acl/acl-api.h
--- a/src/plugins/acl/acl-api.h Sat Nov 15 21:29:59 2008 +0200
+++ b/src/plugins/acl/acl-api.h Sun Nov 16 00:15:15 2008 +0200
@@ -66,6 +66,9 @@ struct acl_rights {
const char *const *rights;
/* Negative rights assigned */
const char *const *neg_rights;
+
+ /* These rights are global for all users */
+ unsigned int global:1;
};
struct acl_rights_update {
diff -r 24c8bc8098ee -r d486dfe02c1e src/plugins/acl/acl-backend-vfile.c
--- a/src/plugins/acl/acl-backend-vfile.c Sat Nov 15 21:29:59 2008 +0200
+++ b/src/plugins/acl/acl-backend-vfile.c Sun Nov 16 00:15:15 2008 +0200
@@ -266,11 +266,33 @@ static void acl_backend_vfile_object_dei
}
static const char *const *
+acl_rights_alloc(pool_t pool, ARRAY_TYPE(const_string) *rights_arr)
+{
+ const char **ret, **rights;
+ unsigned int i, dest, count;
+
+ /* sort the rights first so we can easily drop duplicates */
+ rights = array_get_modifiable(rights_arr, &count);
+ qsort(rights, count, sizeof(*rights), i_strcmp_p);
+
+ /* @UNSAFE */
+ ret = p_new(pool, const char *, count + 1);
+ if (count > 0) {
+ ret[0] = rights[0];
+ for (i = dest = 1; i < count; i++) {
+ if (strcmp(rights[i-1], rights[i]) != 0)
+ ret[dest++] = rights[i];
+ }
+ }
+ return ret;
+}
+
+static const char *const *
acl_parse_rights(pool_t pool, const char *acl, const char **error_r)
{
- ARRAY_DEFINE(rights, const char *);
- const char *const *names, **ret_rights;
- unsigned int i, count;
+ ARRAY_TYPE(const_string) rights;
+ const char *const *names;
+ unsigned int i;
/* parse IMAP ACL list */
while (*acl == ' ' || *acl == '\t')
@@ -304,21 +326,15 @@ acl_parse_rights(pool_t pool, const char
}
}
- /* @UNSAFE */
- count = array_count(&rights);
- ret_rights = p_new(pool, const char *, count + 1);
- if (count > 0) {
- memcpy(ret_rights, array_idx(&rights, 0),
- sizeof(const char *) * count);
- }
- return ret_rights;
+ return acl_rights_alloc(pool, &rights);
}
static int
-acl_object_vfile_parse_line(struct acl_object_vfile *aclobj, const char *path,
- const char *line, unsigned int linenum)
-{
- struct acl_rights_update rights;
+acl_object_vfile_parse_line(struct acl_object_vfile *aclobj, bool global,
+ const char *path, const char *line,
+ unsigned int linenum)
+{
+ struct acl_rights rights;
const char *p, *const *right_names, *error = NULL;
if (*line == '\0' || *line == '#')
@@ -334,46 +350,45 @@ acl_object_vfile_parse_line(struct acl_o
}
memset(&rights, 0, sizeof(rights));
+ rights.global = global;
right_names = acl_parse_rights(aclobj->rights_pool, p, &error);
if (*line != '-') {
- rights.modify_mode = ACL_MODIFY_MODE_REPLACE;
- rights.rights.rights = right_names;
+ rights.rights = right_names;
} else {
line++;
- rights.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
- rights.rights.neg_rights = right_names;
+ rights.neg_rights = right_names;
}
switch (*line) {
case 'u':
if (strncmp(line, "user=", 5) == 0) {
- rights.rights.id_type = ACL_ID_USER;
- rights.rights.identifier = line + 5;
+ rights.id_type = ACL_ID_USER;
+ rights.identifier = line + 5;
break;
}
case 'o':
if (strcmp(line, "owner") == 0) {
- rights.rights.id_type = ACL_ID_OWNER;
+ rights.id_type = ACL_ID_OWNER;
break;
}
case 'g':
if (strncmp(line, "group=", 6) == 0) {
- rights.rights.id_type = ACL_ID_GROUP;
- rights.rights.identifier = line + 6;
+ rights.id_type = ACL_ID_GROUP;
+ rights.identifier = line + 6;
break;
} else if (strncmp(line, "group-override=", 15) == 0) {
- rights.rights.id_type = ACL_ID_GROUP_OVERRIDE;
- rights.rights.identifier = line + 15;
+ rights.id_type = ACL_ID_GROUP_OVERRIDE;
+ rights.identifier = line + 15;
break;
}
case 'a':
if (strcmp(line, "authenticated") == 0) {
- rights.rights.id_type = ACL_ID_AUTHENTICATED;
+ rights.id_type = ACL_ID_AUTHENTICATED;
break;
} else if (strcmp(line, "anyone") == 0 ||
strcmp(line, "anonymous") == 0) {
- rights.rights.id_type = ACL_ID_ANYONE;
+ rights.id_type = ACL_ID_ANYONE;
break;
}
default:
@@ -386,12 +401,8 @@ acl_object_vfile_parse_line(struct acl_o
return -1;
}
- rights.rights.identifier =
- p_strdup(aclobj->rights_pool, rights.rights.identifier);
- array_append(&aclobj->rights, &rights.rights, 1);
-
- acl_cache_update(aclobj->aclobj.backend->cache,
- aclobj->aclobj.name, &rights);
+ rights.identifier = p_strdup(aclobj->rights_pool, rights.identifier);
+ array_append(&aclobj->rights, &rights, 1);
return 0;
}
@@ -406,7 +417,8 @@ static void acl_backend_remove_all_acces
}
static int
-acl_backend_vfile_read(struct acl_object_vfile *aclobj, const char *path,
+acl_backend_vfile_read(struct acl_object_vfile *aclobj,
+ bool global, const char *path,
struct acl_vfile_validity *validity, bool try_retry,
bool *is_dir_r)
{
@@ -461,21 +473,11 @@ acl_backend_vfile_read(struct acl_object
i_info("acl vfile: reading file %s", path);
input = i_stream_create_fd(fd, 4096, FALSE);
-
- if (!array_is_created(&aclobj->rights)) {
- aclobj->rights_pool =
- pool_alloconly_create("acl rights",
- I_MAX(256, st.st_size / 2));
- i_array_init(&aclobj->rights, I_MAX(16, st.st_size / 40));
- } else {
- array_clear(&aclobj->rights);
- p_clear(aclobj->rights_pool);
- }
-
linenum = 1;
while ((line = i_stream_read_next_line(input)) != NULL) {
T_BEGIN {
- ret = acl_object_vfile_parse_line(aclobj, path, line,
+ ret = acl_object_vfile_parse_line(aclobj, global,
+ path, line,
linenum++);
} T_END;
if (ret < 0)
@@ -520,7 +522,7 @@ acl_backend_vfile_read(struct acl_object
static int
acl_backend_vfile_read_with_retry(struct acl_object_vfile *aclobj,
- const char *path,
+ bool global, const char *path,
struct acl_vfile_validity *validity)
{
unsigned int i;
@@ -531,7 +533,7 @@ acl_backend_vfile_read_with_retry(struct
return 0;
for (i = 0;; i++) {
- ret = acl_backend_vfile_read(aclobj, path, validity,
+ ret = acl_backend_vfile_read(aclobj, global, path, validity,
i < ACL_ESTALE_RETRY_COUNT,
&is_dir);
if (ret != 0)
@@ -610,6 +612,89 @@ int acl_backend_vfile_object_get_mtime(s
return 0;
}
+static int acl_rights_cmp(const void *p1, const void *p2)
+{
+ const struct acl_rights *r1 = p1, *r2 = p2;
+
+ if (r1->global != r2->global) {
+ /* globals have higher priority than locals */
+ return r1->global ? 1 : -1;
+ }
+
+ return r1->id_type - r2->id_type;
+}
+
+static void
+acl_rights_merge(pool_t pool, const char *const **destp, const char *const *src)
+{
+ const char *const *dest = *destp;
+ ARRAY_TYPE(const_string) rights;
+ unsigned int i;
+
+ t_array_init(&rights, 64);
+ for (i = 0; dest[i] != NULL; i++)
+ array_append(&rights, &dest[i], 1);
+ for (i = 0; src[i] != NULL; i++)
+ array_append(&rights, &src[i], 1);
+
+ *destp = acl_rights_alloc(pool, &rights);
+}
+
+static void acl_backend_vfile_rights_sort(struct acl_object_vfile *aclobj)
+{
+ struct acl_rights *rights;
+ unsigned int i, dest, count;
+
+ if (!array_is_created(&aclobj->rights))
+ return;
+
+ rights = array_get_modifiable(&aclobj->rights, &count);
+ qsort(rights, count, sizeof(*rights), acl_rights_cmp);
+
+ /* merge identical identifiers */
+ for (dest = 0, i = 1; i < count; i++) {
+ if (rights[i].global == rights[dest].global &&
+ rights[i].id_type == rights[dest].id_type &&
+ null_strcmp(rights[i].identifier,
+ rights[dest].identifier) == 0) {
+ /* add i's rights to dest and delete i */
+ acl_rights_merge(aclobj->rights_pool,
+ &rights[dest].rights,
+ rights[i].rights);
+ acl_rights_merge(aclobj->rights_pool,
+ &rights[dest].neg_rights,
+ rights[i].neg_rights);
+ } else {
+ if (++dest != i)
+ rights[dest] = rights[i];
+ }
+ }
+ if (++dest != count)
+ array_delete(&aclobj->rights, dest, count - dest);
+}
+
+static void acl_backend_vfile_cache_rebuild(struct acl_object_vfile *aclobj)
+{
+ struct acl_object *_aclobj = &aclobj->aclobj;
+ struct acl_rights_update ru;
+ const struct acl_rights *rights;
+ unsigned int i, count;
+
+ acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
+
+ if (!array_is_created(&aclobj->rights))
+ return;
+
+ memset(&ru, 0, sizeof(ru));
+ rights = array_get(&aclobj->rights, &count);
+ for (i = 0; i < count; i++) {
+ ru.modify_mode = ACL_MODIFY_MODE_REPLACE;
+ ru.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
+ ru.rights = rights[i];
+ acl_cache_update(_aclobj->backend->cache, _aclobj->name, &ru);
+ }
+}
+
static int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj)
{
struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
@@ -634,16 +719,26 @@ static int acl_backend_vfile_object_refr
return ret;
More information about the dovecot-cvs
mailing list