]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
acl: Fixed handling 'k' right. Although box/child creation was prevented, box/child...
authorTimo Sirainen <tss@iki.fi>
Sun, 7 Sep 2008 12:18:29 +0000 (15:18 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 7 Sep 2008 12:18:29 +0000 (15:18 +0300)
--HG--
branch : HEAD

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

index b675da1c555a864b50f4bd4c2a08482716f5f739..6dd737210b1ad1adb8d8353179d805a04b35fdc1 100644 (file)
@@ -18,6 +18,9 @@ struct acl_backend_vfuncs {
        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);
index 7cf65d47f220fc047c1e24eeaa964785604d8e9f..39edba32c38c55750fee02e856735de6169f2ef5 100644 (file)
@@ -12,6 +12,13 @@ struct acl_object *acl_object_init_from_name(struct acl_backend *backend,
        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;
index 356c14949cbe4821d4d6e63a5a212e13b8bf44f0..3d25b2abac57d7ac9c72d04c8d90156be66e7dfa 100644 (file)
@@ -108,6 +108,9 @@ acl_backend_nonowner_lookups_iter_deinit(struct acl_mailbox_list_context **ctx);
 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
index 35605265f06727f460966b467bc8ede876dcb07c..7bb35fd5c78419ef0271d550fa5e3c0e6f066c17 100644 (file)
@@ -30,6 +30,7 @@ struct acl_vfile_validity {
 
 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 @@ static void acl_backend_vfile_deinit(struct acl_backend *_backend)
        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 @@ acl_backend_vfile_object_init(struct acl_backend *_backend,
                (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 @@ acl_backend_vfile_object_init(struct acl_backend *_backend,
                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 @@ acl_backend_vfile_refresh(struct acl_object *aclobj, const char *path,
                   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 @@ struct acl_backend_vfuncs acl_backend_vfile = {
        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,
index 09a1240eceec0d40af8bb9d8ab99bf593a6098ea..4349ce3ad37eb39f7a394eaa0207320854e1831e 100644 (file)
@@ -42,24 +42,19 @@ struct acl_backend *acl_mailbox_list_get_backend(struct mailbox_list *list)
        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 @@ static int
 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_mailbox_list_info_is_visible(struct acl_mailbox_list_iterate_context *ctx,
        }
 
        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 @@ acl_mailbox_list_iter_is_mailbox(struct mailbox_list_iterate_context *ctx,
                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 @@ static int acl_get_mailbox_name_status(struct mailbox_list *list,
        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 @@ static int acl_get_mailbox_name_status(struct mailbox_list *list,
        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 @@ acl_mailbox_list_delete(struct mailbox_list *list, const char *name)
        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 @@ acl_mailbox_list_rename(struct mailbox_list *list,
        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 @@ acl_mailbox_list_rename(struct mailbox_list *list,
 
        /* 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 @@ acl_mailbox_list_rename(struct mailbox_list *list,
                           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;
        }
index 196110ff83d3dfd3372caa6c58ec2a58b0062ee2..287e9936cf329d58426324b31b817a5099820cff 100644 (file)
@@ -44,13 +44,11 @@ struct mailbox *acl_mailbox_open_box(struct mailbox *box);
 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);
index dcc82bb78cf31cde2d86f2fe6d3a63b4b033314c..375bbaf90fba807b5cb6740a461f8a53e8edcc59 100644 (file)
@@ -38,7 +38,7 @@ void acl_storage_rights_ctx_init(struct acl_storage_rights_context *ctx,
 }
 
 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 acl_storage_rights_ctx_have_right(struct acl_storage_rights_context *ctx,
        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 @@ acl_storage_have_right(struct mail_storage *storage, const char *name,
        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 @@ static int acl_mailbox_create(struct mail_storage *storage, const char *name,
                              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 @@ static int acl_mailbox_create(struct mail_storage *storage, const char *name,
                           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;
        }