Mercurial > dovecot > original-hg > dovecot-1.2
changeset 8165:459c4c496983 HEAD
acl: Fixed handling 'k' right. Although box/child creation was prevented, box/child/child wasn't.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 07 Sep 2008 15:18:29 +0300 |
parents | 314fab62b3d1 |
children | a1f6c93afbc2 |
files | src/plugins/acl/acl-api-private.h src/plugins/acl/acl-api.c src/plugins/acl/acl-api.h src/plugins/acl/acl-backend-vfile.c src/plugins/acl/acl-mailbox-list.c src/plugins/acl/acl-plugin.h src/plugins/acl/acl-storage.c |
diffstat | 7 files changed, 169 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/src/plugins/acl/acl-api-private.h Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-api-private.h Sun Sep 07 15:18:29 2008 +0300 @@ -18,6 +18,9 @@ struct acl_object *(*object_init)(struct acl_backend *backend, struct mail_storage *storage, const char *name); + struct acl_object *(*object_init_parent)(struct acl_backend *backend, + struct mail_storage *storage, + const char *child_name); void (*object_deinit)(struct acl_object *aclobj); int (*object_refresh_cache)(struct acl_object *aclobj);
--- a/src/plugins/acl/acl-api.c Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-api.c Sun Sep 07 15:18:29 2008 +0300 @@ -12,6 +12,13 @@ return backend->v.object_init(backend, storage, name); } +struct acl_object *acl_object_init_from_parent(struct acl_backend *backend, + struct mail_storage *storage, + const char *child_name) +{ + return backend->v.object_init_parent(backend, storage, child_name); +} + void acl_object_deinit(struct acl_object **_aclobj) { struct acl_object *aclobj = *_aclobj;
--- a/src/plugins/acl/acl-api.h Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-api.h Sun Sep 07 15:18:29 2008 +0300 @@ -108,6 +108,9 @@ struct acl_object *acl_object_init_from_name(struct acl_backend *backend, struct mail_storage *storage, const char *name); +struct acl_object *acl_object_init_from_parent(struct acl_backend *backend, + struct mail_storage *storage, + const char *child_name); void acl_object_deinit(struct acl_object **aclobj); /* Returns 1 if we have the requested rights, 0 if not, or -1 if internal
--- a/src/plugins/acl/acl-backend-vfile.c Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-backend-vfile.c Sun Sep 07 15:18:29 2008 +0300 @@ -30,6 +30,7 @@ struct acl_backend_vfile_validity { struct acl_vfile_validity global_validity, local_validity; + struct acl_vfile_validity mailbox_validity; }; struct acl_letter_map { @@ -106,6 +107,20 @@ pool_unref(&backend->backend.pool); } +static const char * +acl_backend_vfile_get_local_dir(struct mail_storage *storage, const char *name) +{ + const char *dir; + bool is_file; + + dir = mail_storage_get_mailbox_path(storage, name, &is_file); + if (is_file) { + dir = mailbox_list_get_path(storage->list, name, + MAILBOX_LIST_PATH_TYPE_CONTROL); + } + return dir; +} + static struct acl_object * acl_backend_vfile_object_init(struct acl_backend *_backend, struct mail_storage *storage, const char *name) @@ -114,7 +129,6 @@ (struct acl_backend_vfile *)_backend; struct acl_object_vfile *aclobj; const char *dir; - bool is_file; aclobj = i_new(struct acl_object_vfile, 1); aclobj->aclobj.backend = _backend; @@ -127,16 +141,113 @@ dir = mailbox_list_get_path(_backend->list, NULL, MAILBOX_LIST_PATH_TYPE_DIR); } else { - dir = mail_storage_get_mailbox_path(storage, name, &is_file); - if (is_file) { - dir = mailbox_list_get_path(_backend->list, name, - MAILBOX_LIST_PATH_TYPE_CONTROL); - } + dir = acl_backend_vfile_get_local_dir(storage, name); } aclobj->local_path = i_strconcat(dir, "/"ACL_FILENAME, NULL); return &aclobj->aclobj; } +static const char * +get_parent_mailbox(struct mail_storage *storage, const char *name) +{ + const char *p; + char sep; + + sep = mailbox_list_get_hierarchy_sep(storage->list); + p = strrchr(name, sep); + return p == NULL ? NULL : t_strdup_until(name, p); +} + +static int +acl_backend_vfile_exists(struct acl_backend_vfile *backend, const char *path, + struct acl_vfile_validity *validity) +{ + struct stat st; + + if (validity->last_check + (time_t)backend->cache_secs > ioloop_time) { + /* use the cached value */ + return validity->last_mtime != VALIDITY_MTIME_NOTFOUND; + } + + validity->last_check = ioloop_time; + if (stat(path, &st) < 0) { + if (errno == ENOENT) { + validity->last_mtime = VALIDITY_MTIME_NOTFOUND; + return 0; + } + if (errno == EACCES) { + validity->last_mtime = VALIDITY_MTIME_NOACCESS; + return 1; + } + i_error("stat(%s) failed: %m", path); + return -1; + } + validity->last_mtime = st.st_mtime; + validity->last_size = st.st_size; + return 1; +} + +static bool +acl_backend_vfile_has_acl(struct acl_backend *_backend, + struct mail_storage *storage, const char *name) +{ + 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; + int ret; + + old_validity = acl_cache_get_validity(_backend->cache, name); + if (old_validity != NULL) + new_validity = *old_validity; + else + memset(&new_validity, 0, sizeof(new_validity)); + + /* See if the mailbox exists. If we wanted recursive lookups we could + skip this, but at least for now we assume that if an existing + mailbox has no ACL it's equivalent to default ACLs. */ + path = mailbox_list_get_path(storage->list, name, + MAILBOX_LIST_PATH_TYPE_MAILBOX); + ret = acl_backend_vfile_exists(backend, path, + &new_validity.mailbox_validity); + if (ret == 0) { + dir = acl_backend_vfile_get_local_dir(storage, name); + 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); + } + acl_cache_set_validity(_backend->cache, name, &new_validity); + return ret > 0; +} + +static struct acl_object * +acl_backend_vfile_object_init_parent(struct acl_backend *backend, + struct mail_storage *storage, + const char *child_name) +{ + const char *parent; + + /* stop at the first parent that + a) has global ACL file + b) has local ACL file + c) exists */ + while ((parent = get_parent_mailbox(storage, child_name)) != NULL) { + if (acl_backend_vfile_has_acl(backend, storage, parent)) + break; + child_name = parent; + } + if (parent == NULL) { + /* use the root */ + parent = ""; + } + return acl_backend_vfile_object_init(backend, storage, parent); +} + static void acl_backend_vfile_object_deinit(struct acl_object *_aclobj) { struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj; @@ -470,8 +581,9 @@ seconds) */ time_t cache_secs = backend->cache_secs; - if (st.st_mtime < validity->last_read_time - cache_secs || - ioloop_time - validity->last_read_time <= cache_secs) + if (validity->last_read_time != 0 && + (st.st_mtime < validity->last_read_time - cache_secs || + ioloop_time - validity->last_read_time <= cache_secs)) return 0; } @@ -591,6 +703,7 @@ acl_backend_vfile_nonowner_iter_next, acl_backend_vfile_nonowner_iter_deinit, acl_backend_vfile_object_init, + acl_backend_vfile_object_init_parent, acl_backend_vfile_object_deinit, acl_backend_vfile_object_refresh_cache, acl_backend_vfile_object_update,
--- a/src/plugins/acl/acl-mailbox-list.c Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-mailbox-list.c Sun Sep 07 15:18:29 2008 +0300 @@ -42,24 +42,19 @@ return alist->rights.backend; } -const char *acl_mailbox_list_get_parent_mailbox_name(struct mailbox_list *list, - const char *name) -{ - const char *p; - char sep; - - sep = mailbox_list_get_hierarchy_sep(list); - p = strrchr(name, sep); - return p == NULL ? "" : t_strdup_until(name, p); -} - static int -acl_mailbox_list_have_right(struct acl_mailbox_list *alist, const char *name, +acl_mailbox_list_have_right(struct mailbox_list *list, const char *name, unsigned int acl_storage_right_idx, bool *can_see_r) { - return acl_storage_rights_ctx_have_right(&alist->rights, name, - acl_storage_right_idx, - can_see_r); + struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list); + int ret; + + ret = acl_storage_rights_ctx_have_right(&alist->rights, name, FALSE, + acl_storage_right_idx, + can_see_r); + if (ret < 0) + mailbox_list_set_internal_error(list); + return ret; } static void @@ -185,7 +180,6 @@ acl_mailbox_list_info_is_visible(struct acl_mailbox_list_iterate_context *ctx, const struct mailbox_info *info) { - struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(ctx->ctx.list); const char *acl_name; int ret; @@ -195,7 +189,7 @@ } acl_name = acl_mailbox_list_iter_get_name(&ctx->ctx, info->name); - ret = acl_mailbox_list_have_right(alist, acl_name, + ret = acl_mailbox_list_have_right(ctx->ctx.list, acl_name, ACL_STORAGE_RIGHT_LOOKUP, NULL); if (ret != 0) @@ -255,7 +249,7 @@ return ret; mailbox_name = acl_mailbox_list_iter_get_name(ctx, mailbox_name); - return acl_mailbox_list_have_right(alist, mailbox_name, + return acl_mailbox_list_have_right(ctx->list, mailbox_name, ACL_STORAGE_RIGHT_LOOKUP, NULL); } @@ -283,14 +277,14 @@ struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(list); int ret; - ret = acl_mailbox_list_have_right(alist, name, ACL_STORAGE_RIGHT_LOOKUP, + ret = acl_mailbox_list_have_right(list, name, ACL_STORAGE_RIGHT_LOOKUP, NULL); if (ret < 0) return -1; if (ret == 0) { /* If we have INSERT right for the mailbox, we'll need to reveal its existence so that APPEND and COPY works. */ - ret = acl_mailbox_list_have_right(alist, name, + ret = acl_mailbox_list_have_right(list, name, ACL_STORAGE_RIGHT_INSERT, NULL); if (ret < 0) @@ -314,16 +308,14 @@ case MAILBOX_NAME_NOINFERIORS: /* have to check if we are allowed to see the parent */ T_BEGIN { - const char *parent; - - parent = acl_mailbox_list_get_parent_mailbox_name(list, - name); - ret = acl_mailbox_list_have_right(alist, parent, - ACL_STORAGE_RIGHT_LOOKUP, NULL); + ret = acl_storage_rights_ctx_have_right(&alist->rights, name, + TRUE, ACL_STORAGE_RIGHT_LOOKUP, NULL); } T_END; - if (ret < 0) + if (ret < 0) { + mailbox_list_set_internal_error(list); return -1; + } if (ret == 0) { /* no permission to see the parent */ *status = MAILBOX_NAME_VALID; @@ -340,7 +332,7 @@ bool can_see; int ret; - ret = acl_mailbox_list_have_right(alist, name, ACL_STORAGE_RIGHT_DELETE, + ret = acl_mailbox_list_have_right(list, name, ACL_STORAGE_RIGHT_DELETE, &can_see); if (ret <= 0) { if (ret < 0) @@ -367,7 +359,7 @@ int ret; /* renaming requires rights to delete the old mailbox */ - ret = acl_mailbox_list_have_right(alist, oldname, + ret = acl_mailbox_list_have_right(list, oldname, ACL_STORAGE_RIGHT_DELETE, &can_see); if (ret <= 0) { if (ret < 0) @@ -384,9 +376,8 @@ /* and create the new one under the parent mailbox */ T_BEGIN { - ret = acl_mailbox_list_have_right(alist, - acl_mailbox_list_get_parent_mailbox_name(list, newname), - ACL_STORAGE_RIGHT_CREATE, NULL); + ret = acl_storage_rights_ctx_have_right(&alist->rights, newname, + TRUE, ACL_STORAGE_RIGHT_CREATE, NULL); } T_END; if (ret <= 0) { @@ -396,6 +387,8 @@ existence. Can't help it. */ mailbox_list_set_error(list, MAIL_ERROR_PERM, MAIL_ERRSTR_NO_PERMISSION); + } else { + mailbox_list_set_internal_error(list); } return -1; }
--- a/src/plugins/acl/acl-plugin.h Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-plugin.h Sun Sep 07 15:18:29 2008 +0300 @@ -44,13 +44,11 @@ void acl_storage_rights_ctx_init(struct acl_storage_rights_context *ctx, struct acl_backend *backend); int acl_storage_rights_ctx_have_right(struct acl_storage_rights_context *ctx, - const char *name, + const char *name, bool parent, unsigned int acl_storage_right_idx, bool *can_see_r); struct acl_backend *acl_mailbox_list_get_backend(struct mailbox_list *list); -const char *acl_mailbox_list_get_parent_mailbox_name(struct mailbox_list *list, - const char *name); void acl_plugin_init(void); void acl_plugin_deinit(void);
--- a/src/plugins/acl/acl-storage.c Sun Sep 07 10:54:46 2008 +0300 +++ b/src/plugins/acl/acl-storage.c Sun Sep 07 15:18:29 2008 +0300 @@ -38,7 +38,7 @@ } int acl_storage_rights_ctx_have_right(struct acl_storage_rights_context *ctx, - const char *name, + const char *name, bool parent, unsigned int acl_storage_right_idx, bool *can_see_r) { @@ -48,7 +48,9 @@ int ret, ret2; ns = mailbox_list_get_namespace(ctx->backend->list); - aclobj = acl_object_init_from_name(ctx->backend, ns->storage, name); + aclobj = !parent ? + acl_object_init_from_name(ctx->backend, ns->storage, name) : + acl_object_init_from_parent(ctx->backend, ns->storage, name); ret = acl_object_have_right(aclobj, idx_arr[acl_storage_right_idx]); if (can_see_r != NULL) { @@ -70,7 +72,7 @@ struct acl_mail_storage *astorage = ACL_CONTEXT(storage); int ret; - ret = acl_storage_rights_ctx_have_right(&astorage->rights, name, + ret = acl_storage_rights_ctx_have_right(&astorage->rights, name, FALSE, acl_storage_right_idx, can_see_r); if (ret < 0) @@ -131,13 +133,11 @@ bool directory) { struct acl_mail_storage *astorage = ACL_CONTEXT(storage); - struct mailbox_list *list = mail_storage_get_list(storage); int ret; T_BEGIN { - ret = acl_storage_have_right(storage, - acl_mailbox_list_get_parent_mailbox_name(list, name), - ACL_STORAGE_RIGHT_CREATE, NULL); + ret = acl_storage_rights_ctx_have_right(&astorage->rights, name, + TRUE, ACL_STORAGE_RIGHT_CREATE, NULL); } T_END; if (ret <= 0) { @@ -147,6 +147,8 @@ existence. Can't help it. */ mail_storage_set_error(storage, MAIL_ERROR_PERM, MAIL_ERRSTR_NO_PERMISSION); + } else { + mail_storage_set_internal_error(storage); } return -1; }