]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Initial support for LISTing users with shared mailboxes.
authorTimo Sirainen <tss@iki.fi>
Sun, 16 Nov 2008 17:20:28 +0000 (19:20 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 16 Nov 2008 17:20:28 +0000 (19:20 +0200)
--HG--
branch : HEAD

15 files changed:
src/plugins/acl/Makefile.am
src/plugins/acl/acl-api-private.h
src/plugins/acl/acl-api.c
src/plugins/acl/acl-backend-vfile-acllist.c
src/plugins/acl/acl-backend-vfile.c
src/plugins/acl/acl-lookup-dict.c [new file with mode: 0644]
src/plugins/acl/acl-lookup-dict.h [new file with mode: 0644]
src/plugins/acl/acl-mailbox-list.c
src/plugins/acl/acl-mailbox.c
src/plugins/acl/acl-plugin.c
src/plugins/acl/acl-plugin.h
src/plugins/acl/acl-shared-storage.c [new file with mode: 0644]
src/plugins/acl/acl-shared-storage.h [new file with mode: 0644]
src/plugins/acl/acl-storage.c
src/plugins/acl/acl-storage.h

index 4bb8e702d6fb9c9016ff02e90b5789017aa347bd..f60da78612ea4d99005275b6d66e878b728b5351 100644 (file)
@@ -1,5 +1,6 @@
 AM_CPPFLAGS = \
        -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-dict \
        -I$(top_srcdir)/src/lib-mail \
        -I$(top_srcdir)/src/lib-imap \
        -I$(top_srcdir)/src/lib-index \
@@ -16,9 +17,11 @@ lib01_acl_plugin_la_SOURCES = \
        acl-backend-vfile.c \
        acl-backend-vfile-acllist.c \
        acl-cache.c \
+       acl-lookup-dict.c \
        acl-mailbox.c \
        acl-mailbox-list.c \
        acl-plugin.c \
+       acl-shared-storage.c \
        acl-storage.c
 
 noinst_HEADERS = \
@@ -26,7 +29,9 @@ noinst_HEADERS = \
        acl-api-private.h \
        acl-backend-vfile.h \
        acl-cache.h \
+       acl-lookup-dict.h \
        acl-plugin.h \
+       acl-shared-storage.h \
        acl-storage.h
 
 install-exec-local:
index bd2d70a61432c35d5fbdb1ecdac8f0002c057afc..7b31392175cc3188636d458db06d7ff891da2a0b 100644 (file)
@@ -82,6 +82,7 @@ acl_backend_mask_get_names(struct acl_backend *backend,
                           const struct acl_mask *mask, pool_t pool);
 int acl_backend_get_default_rights(struct acl_backend *backend,
                                   const struct acl_mask **mask_r);
+void acl_rights_write_id(string_t *dest, const struct acl_rights *right);
 bool acl_rights_has_nonowner_lookup_changes(const struct acl_rights *rights);
 
 #endif
index 958af3eca4e52a3c154718cdba95bdcaf5930d8f..558c529d777842fffc81bd2ab5b8b76c6e2857d1 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "str.h"
 #include "hash.h"
 #include "acl-cache.h"
 #include "acl-api-private.h"
@@ -172,6 +173,35 @@ acl_backend_nonowner_lookups_iter_deinit(struct acl_mailbox_list_context **_ctx)
        ctx->backend->v.nonowner_lookups_iter_deinit(ctx);
 }
 
+void acl_rights_write_id(string_t *dest, const struct acl_rights *right)
+{
+       switch (right->id_type) {
+       case ACL_ID_ANYONE:
+               str_append(dest, ACL_ID_NAME_ANYONE);
+               break;
+       case ACL_ID_AUTHENTICATED:
+               str_append(dest, ACL_ID_NAME_AUTHENTICATED);
+               break;
+       case ACL_ID_OWNER:
+               str_append(dest, ACL_ID_NAME_OWNER);
+               break;
+       case ACL_ID_USER:
+               str_append(dest, ACL_ID_NAME_USER_PREFIX);
+               str_append(dest, right->identifier);
+               break;
+       case ACL_ID_GROUP:
+               str_append(dest, ACL_ID_NAME_GROUP_PREFIX);
+               str_append(dest, right->identifier);
+               break;
+       case ACL_ID_GROUP_OVERRIDE:
+               str_append(dest, ACL_ID_NAME_GROUP_OVERRIDE_PREFIX);
+               str_append(dest, right->identifier);
+               break;
+       case ACL_ID_TYPE_COUNT:
+               i_unreached();
+       }
+}
+
 bool acl_rights_has_nonowner_lookup_changes(const struct acl_rights *rights)
 {
        const char *const *p;
index aa720d8da7638f5fa21722affc0de41cf705ccd2..3248be26e4cb34714f4d420d744b961d8bc6feee 100644 (file)
@@ -10,6 +10,7 @@
 #include "mail-storage.h"
 #include "acl-plugin.h"
 #include "acl-cache.h"
+#include "acl-lookup-dict.h"
 #include "acl-backend-vfile.h"
 
 #include <stdio.h>
@@ -241,8 +242,12 @@ int acl_backend_vfile_acllist_rebuild(struct acl_backend_vfile *backend)
                }
        }
        if (ret == 0) {
+               struct acl_user *auser = ACL_USER_CONTEXT(ns->user);
+
                backend->acllist_mtime = st.st_mtime;
                backend->acllist_last_check = ioloop_time;
+               /* FIXME: dict reubild is expensive, try to avoid it */
+               (void)acl_lookup_dict_rebuild(auser->acl_lookup_dict);
        } else {
                acllist_clear(backend, 0);
                if (unlink(str_c(path)) < 0 && errno != ENOENT)
index bf93d4b462c9a5ded065451c42fae1ce1704aa80..5349da527b33b446e8d00f335584f64b3612ff02 100644 (file)
@@ -999,32 +999,7 @@ vfile_write_right(string_t *dest, const struct acl_rights *right,
        const char *const *rights = neg ? right->neg_rights : right->rights;
 
        if (neg) str_append_c(dest,'-');
-
-       switch (right->id_type) {
-       case ACL_ID_ANYONE:
-               str_append(dest, ACL_ID_NAME_ANYONE);
-               break;
-       case ACL_ID_AUTHENTICATED:
-               str_append(dest, ACL_ID_NAME_AUTHENTICATED);
-               break;
-       case ACL_ID_OWNER:
-               str_append(dest, ACL_ID_NAME_OWNER);
-               break;
-       case ACL_ID_USER:
-               str_append(dest, ACL_ID_NAME_USER_PREFIX);
-               str_append(dest, right->identifier);
-               break;
-       case ACL_ID_GROUP:
-               str_append(dest, ACL_ID_NAME_GROUP_PREFIX);
-               str_append(dest, right->identifier);
-               break;
-       case ACL_ID_GROUP_OVERRIDE:
-               str_append(dest, ACL_ID_NAME_GROUP_OVERRIDE_PREFIX);
-               str_append(dest, right->identifier);
-               break;
-       case ACL_ID_TYPE_COUNT:
-               i_unreached();
-       }
+       acl_rights_write_id(dest, right);
        str_append_c(dest, ' ');
        vfile_write_rights_list(dest, rights);
        str_append_c(dest, '\n');
diff --git a/src/plugins/acl/acl-lookup-dict.c b/src/plugins/acl/acl-lookup-dict.c
new file mode 100644 (file)
index 0000000..b2d726a
--- /dev/null
@@ -0,0 +1,332 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "dict.h"
+#include "mail-user.h"
+#include "mail-namespace.h"
+#include "acl-api-private.h"
+#include "acl-storage.h"
+#include "acl-plugin.h"
+#include "acl-lookup-dict.h"
+
+#include <stdlib.h>
+
+#define DICT_SHARED_BOXES_PATH "shared-boxes/"
+
+struct acl_lookup_dict {
+       struct mail_user *user;
+};
+
+struct acl_lookup_dict_iter {
+       pool_t pool;
+       struct acl_lookup_dict *dict;
+
+       ARRAY_TYPE(const_string) iter_ids;
+       struct dict_iterate_context *dict_iter;
+       unsigned int iter_idx;
+
+       const char *prefix;
+       unsigned int prefix_len;
+
+       unsigned int failed:1;
+};
+
+static struct dict *acl_dict;
+
+void acl_lookup_dicts_init(void)
+{
+       const char *uri;
+
+       uri = getenv("ACL_SHARED_DICT");
+       if (uri == NULL) {
+               if (getenv("DEBUG") != NULL) {
+                       i_info("acl: No acl_shared_dict setting - "
+                              "shared mailbox listing is disabled");
+               }
+               return;
+       }
+
+       acl_dict = dict_init(uri, DICT_DATA_TYPE_STRING, "");
+       if (acl_dict == NULL)
+               i_fatal("acl: dict_init(%s) failed", uri);
+}
+
+void acl_lookup_dicts_deinit(void)
+{
+       if (acl_dict != NULL)
+               dict_deinit(&acl_dict);
+}
+
+struct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user)
+{
+       struct acl_lookup_dict *dict;
+
+       dict = i_new(struct acl_lookup_dict, 1);
+       dict->user = user;
+       return dict;
+}
+
+void acl_lookup_dict_deinit(struct acl_lookup_dict **_dict)
+{
+       struct acl_lookup_dict *dict = *_dict;
+
+       *_dict = NULL;
+       i_free(dict);
+}
+
+static void
+acl_lookup_dict_write_rights_id(string_t *dest, const struct acl_rights *right)
+{
+       switch (right->id_type) {
+       case ACL_ID_ANYONE:
+       case ACL_ID_AUTHENTICATED:
+               /* don't bother separating these */
+               str_append(dest, "anyone");
+               break;
+       case ACL_ID_USER:
+               str_append(dest, "user/");
+               str_append(dest, right->identifier);
+               break;
+       case ACL_ID_GROUP:
+       case ACL_ID_GROUP_OVERRIDE:
+               str_append(dest, "group/");
+               str_append(dest, right->identifier);
+               break;
+       case ACL_ID_OWNER:
+       case ACL_ID_TYPE_COUNT:
+               i_unreached();
+       }
+}
+
+static int acl_lookup_dict_rebuild_add_backend(struct mail_namespace *ns,
+                                              ARRAY_TYPE(const_string) *ids)
+{
+       struct acl_backend *backend;
+       struct acl_mailbox_list_context *ctx;
+       struct acl_object *aclobj;
+       struct acl_object_list_iter *iter;
+       struct acl_rights rights;
+       const char *name, *id_dup;
+       string_t *id;
+       int ret, ret2 = 0;
+
+       id = t_str_new(128);
+       backend = acl_storage_get_backend(ns->storage);
+       ctx = acl_backend_nonowner_lookups_iter_init(backend);
+       while ((ret = acl_backend_nonowner_lookups_iter_next(ctx, &name)) > 0) {
+               aclobj = acl_object_init_from_name(backend, ns->storage, name);
+
+               iter = acl_object_list_init(aclobj);
+               while ((ret = acl_object_list_next(iter, &rights)) > 0) {
+                       if (acl_rights_has_nonowner_lookup_changes(&rights)) {
+                               str_truncate(id, 0);
+                               acl_lookup_dict_write_rights_id(id, &rights);
+                               id_dup = t_strdup(str_c(id));
+                               array_append(ids, &id_dup, 1);
+                       }
+               }
+               acl_object_list_deinit(&iter);
+               if (ret < 0)
+                       ret2 = -1;
+               acl_object_deinit(&aclobj);
+       }
+       acl_backend_nonowner_lookups_iter_deinit(&ctx);
+       return ret < 0 || ret2 < 0 ? -1 : 0;
+}
+
+static int
+acl_lookup_dict_rebuild_update(struct acl_lookup_dict *dict,
+                              const ARRAY_TYPE(const_string) *new_ids_arr,
+                              bool no_removes)
+{
+       const char *username = dict->user->username;
+       struct dict_iterate_context *iter;
+       struct dict_transaction_context *dt;
+       const char *prefix, *key, *value, **old_ids, *const *new_ids, *p;
+       ARRAY_TYPE(const_string) old_ids_arr;
+       unsigned int newi, oldi, old_count, new_count;
+       string_t *path;
+       unsigned int prefix_len;
+       int ret;
+
+       /* get all existing identifiers for the user */
+       t_array_init(&old_ids_arr, 128);
+       prefix = DICT_PATH_SHARED DICT_SHARED_BOXES_PATH;
+       prefix_len = strlen(prefix);
+       iter = dict_iterate_init(acl_dict, prefix, DICT_ITERATE_FLAG_RECURSE);
+       while ((ret = dict_iterate(iter, &key, &value)) > 0) {
+               /* prefix/$dest/$source */
+               key += prefix_len;
+               p = strchr(key, '/');
+               if (p != NULL && strcmp(p + 1, username) == 0) {
+                       key = t_strdup_until(key, p);
+                       array_append(&old_ids_arr, &key, 1);
+               }
+       }
+       dict_iterate_deinit(&iter);
+       if (ret < 0) {
+               i_error("acl: dict iteration failed, can't update dict");
+               return -1;
+       }
+
+       /* sort the existing identifiers */
+       old_ids = array_get_modifiable(&old_ids_arr, &old_count);
+       qsort(old_ids, old_count, sizeof(*old_ids), i_strcmp_p);
+
+       /* sync the identifiers */
+       path = t_str_new(256);
+       str_append(path, prefix);
+
+       dt = dict_transaction_begin(acl_dict);
+       new_ids = array_get(new_ids_arr, &new_count);
+       for (newi = oldi = 0; newi < new_count || oldi < old_count; ) {
+               ret = newi == new_count ? 1 :
+                       oldi == old_count ? -1 :
+                       strcmp(new_ids[newi], old_ids[oldi]);
+               if (ret == 0) {
+                       newi++; oldi++;
+               } else if (ret < 0) {
+                       /* new identifier, add it */
+                       str_truncate(path, prefix_len);
+                       str_append(path, new_ids[newi]);
+                       str_append_c(path, '/');
+                       str_append(path, username);
+                       dict_set(dt, str_c(path), "1");
+                       newi++;
+               } else if (!no_removes) {
+                       /* old identifier removed */
+                       str_truncate(path, prefix_len);
+                       str_append(path, old_ids[oldi]);
+                       str_append_c(path, '/');
+                       str_append(path, username);
+                       dict_unset(dt, str_c(path));
+                       oldi++;
+               }
+       }
+       if (dict_transaction_commit(&dt) < 0) {
+               i_error("acl: dict commit failed");
+               return -1;
+       }
+       return 0;
+}
+
+int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict)
+{
+       struct mail_namespace *ns;
+       ARRAY_TYPE(const_string) ids_arr;
+       const char **ids;
+       unsigned int i, dest, count;
+       int ret = 0;
+
+       /* get all ACL identifiers with a positive lookup right */
+       t_array_init(&ids_arr, 128);
+       for (ns = dict->user->namespaces; ns != NULL; ns = ns->next) {
+               if (acl_lookup_dict_rebuild_add_backend(ns, &ids_arr) < 0)
+                       ret = -1;
+       }
+
+       /* sort identifiers and remove duplicates */
+       ids = array_get_modifiable(&ids_arr, &count);
+       qsort(ids, count, sizeof(*ids), i_strcmp_p);
+
+       for (i = 1, dest = 0; i < count; i++) {
+               if (strcmp(ids[dest], ids[i]) != 0) {
+                       if (++dest != i)
+                               ids[dest] = ids[i];
+               }
+       }
+       if (++dest < count)
+               array_delete(&ids_arr, dest, count-dest);
+
+       /* if lookup failed at some point we can still add new ids,
+          but we can't remove any existing ones */
+       if (acl_lookup_dict_rebuild_update(dict, &ids_arr, ret < 0) < 0)
+               ret = -1;
+       return ret;
+}
+
+static void acl_lookup_dict_iterate_start(struct acl_lookup_dict_iter *iter)
+{
+       const char *const *idp;
+
+       idp = array_idx(&iter->iter_ids, iter->iter_idx);
+       iter->iter_idx++;
+       iter->prefix = p_strconcat(iter->pool, DICT_PATH_SHARED
+                                  DICT_SHARED_BOXES_PATH, *idp, "/", NULL);
+       iter->prefix_len = strlen(iter->prefix);
+
+       iter->dict_iter = dict_iterate_init(acl_dict, iter->prefix,
+                                           DICT_ITERATE_FLAG_RECURSE);
+}
+
+struct acl_lookup_dict_iter *
+acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict)
+{
+       struct acl_user *auser = ACL_USER_CONTEXT(dict->user);
+       struct acl_lookup_dict_iter *iter;
+       const char *id;
+       unsigned int i;
+       pool_t pool;
+
+       pool = pool_alloconly_create("acl lookup dict iter", 512);
+       iter = p_new(pool, struct acl_lookup_dict_iter, 1);
+       iter->pool = pool;
+       iter->dict = dict;
+
+       p_array_init(&iter->iter_ids, pool, 16);
+       id = "anyone";
+       array_append(&iter->iter_ids, &id, 1);
+       id = p_strconcat(pool, "user/", dict->user->username, NULL);
+       array_append(&iter->iter_ids, &id, 1);
+
+       /* get all groups we belong to */
+       if (auser->groups != NULL) {
+               for (i = 0; auser->groups[i] != NULL; i++) {
+                       id = p_strconcat(pool, "group/", auser->groups[i],
+                                        NULL);
+                       array_append(&iter->iter_ids, &id, 1);
+               }
+       }
+
+       /* iterate through all identifiers that match us, start with the
+          first one */
+       acl_lookup_dict_iterate_start(iter);
+       return iter;
+}
+
+const char *
+acl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter)
+{
+       const char *key, *value;
+       int ret;
+
+       ret = dict_iterate(iter->dict_iter, &key, &value);
+       if (ret > 0) {
+               i_assert(iter->prefix_len < strlen(key));
+               return key + iter->prefix_len;
+       }
+       if (ret < 0)
+               iter->failed = TRUE;
+       dict_iterate_deinit(&iter->dict_iter);
+
+       if (iter->iter_idx < array_count(&iter->iter_ids)) {
+               /* get to the next iterator */
+               acl_lookup_dict_iterate_start(iter);
+               return acl_lookup_dict_iterate_visible_next(iter);
+       }
+       return NULL;
+}
+
+int acl_lookup_dict_iterate_visible_deinit(struct acl_lookup_dict_iter **_iter)
+{
+       struct acl_lookup_dict_iter *iter = *_iter;
+       int ret = iter->failed ? -1 : 0;
+
+       *_iter = NULL;
+       if (iter->dict_iter != NULL)
+               dict_iterate_deinit(&iter->dict_iter);
+       pool_unref(&iter->pool);
+       return ret;
+}
diff --git a/src/plugins/acl/acl-lookup-dict.h b/src/plugins/acl/acl-lookup-dict.h
new file mode 100644 (file)
index 0000000..f59c2bb
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef ACL_LOOKUP_DICT_H
+#define ACL_LOOKUP_DICT_H
+
+void acl_lookup_dicts_init(void);
+void acl_lookup_dicts_deinit(void);
+
+struct acl_lookup_dict *acl_lookup_dict_init(struct mail_user *user);
+void acl_lookup_dict_deinit(struct acl_lookup_dict **dict);
+
+int acl_lookup_dict_rebuild(struct acl_lookup_dict *dict);
+
+struct acl_lookup_dict_iter *
+acl_lookup_dict_iterate_visible_init(struct acl_lookup_dict *dict);
+const char *
+acl_lookup_dict_iterate_visible_next(struct acl_lookup_dict_iter *iter);
+int acl_lookup_dict_iterate_visible_deinit(struct acl_lookup_dict_iter **iter);
+
+#endif
index f3d90c9a2c72873767ddbe0c28e4d52077dfcf03..0f11cc73e6163887f1b32aab44faa305b4196a40 100644 (file)
@@ -7,12 +7,11 @@
 #include "mailbox-tree.h"
 #include "mail-namespace.h"
 #include "mailbox-list-private.h"
-#include "acl-cache.h"
 #include "acl-api-private.h"
+#include "acl-cache.h"
+#include "acl-shared-storage.h"
 #include "acl-plugin.h"
 
-#include <stdlib.h>
-
 #define ACL_LIST_CONTEXT(obj) \
        MODULE_CONTEXT(obj, acl_mailbox_list_module)
 
@@ -134,6 +133,14 @@ acl_mailbox_list_iter_init(struct mailbox_list *list,
        ctx->ctx.list = list;
        ctx->ctx.flags = flags;
 
+       if (list->ns->type == NAMESPACE_SHARED &&
+           (list->ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+               /* before listing anything add namespaces for all users
+                  who may have visible mailboxes */
+               if (acl_shared_namespaces_add(list->ns) < 0)
+                       ctx->ctx.failed = TRUE;
+       }
+
        T_BEGIN {
                acl_mailbox_try_list_fast(ctx, patterns);
        } T_END;
@@ -394,11 +401,12 @@ acl_mailbox_list_rename(struct mailbox_list *list,
 
 void acl_mailbox_list_created(struct mailbox_list *list)
 {
+       struct acl_user *auser = ACL_USER_CONTEXT(list->ns->user);
        struct acl_mailbox_list *alist;
        struct acl_backend *backend;
        struct mail_namespace *ns;
        enum mailbox_list_flags flags;
-       const char *acl_env, *current_username, *owner_username;
+       const char *current_username, *owner_username;
        bool owner = TRUE;
 
        if ((list->ns->flags & NAMESPACE_FLAG_INTERNAL) != 0) {
@@ -406,11 +414,8 @@ void acl_mailbox_list_created(struct mailbox_list *list)
                return;
        }
 
-       acl_env = getenv("ACL");
-       i_assert(acl_env != NULL);
-
        owner_username = list->ns->user->username;
-       current_username = getenv("MASTER_USER");
+       current_username = auser->master_user;
        if (current_username == NULL)
                current_username = owner_username;
        else
@@ -423,10 +428,8 @@ void acl_mailbox_list_created(struct mailbox_list *list)
        if (ns->type != NAMESPACE_PRIVATE)
                owner = FALSE;
 
-       backend = acl_backend_init(acl_env, list, current_username,
-                                  getenv("ACL_GROUPS") == NULL ? NULL :
-                                  t_strsplit(getenv("ACL_GROUPS"), ","),
-                                  owner);
+       backend = acl_backend_init(auser->acl_env, list, current_username,
+                                  auser->groups, owner);
        if (backend == NULL)
                i_fatal("ACL backend initialization failed");
 
index 98359507f4e09b769d0630583b4d1e9394335f91..1fb293759fea4d4ab2af1ed23c2706d6fd184539 100644 (file)
@@ -30,6 +30,13 @@ struct acl_transaction_context {
 static MODULE_CONTEXT_DEFINE_INIT(acl_mail_module, &mail_module_register);
 static struct acl_transaction_context acl_transaction_failure;
 
+struct acl_backend *acl_storage_get_backend(struct mail_storage *storage)
+{
+       struct acl_mail_storage *astorage = ACL_CONTEXT(storage);
+
+       return astorage->rights.backend;
+}
+
 struct acl_object *acl_storage_get_default_aclobj(struct mail_storage *storage)
 {
        struct acl_mail_storage *astorage = ACL_CONTEXT(storage);
index 0fe0edb4e77e6d089b0146db96c51493e0b0ce16..117e9a31289cf2bebb56c2b64e749d765d8967b4 100644 (file)
@@ -3,12 +3,14 @@
 #include "lib.h"
 #include "mailbox-list-private.h"
 #include "acl-api.h"
+#include "acl-lookup-dict.h"
 #include "acl-plugin.h"
 
 #include <stdlib.h>
 
 void (*acl_next_hook_mail_storage_created)(struct mail_storage *storage);
 void (*acl_next_hook_mailbox_list_created)(struct mailbox_list *list);
+void (*acl_next_hook_mail_user_created)(struct mail_user *user);
 
 const char *acl_plugin_version = PACKAGE_VERSION;
 
@@ -21,6 +23,11 @@ void acl_plugin_init(void)
 
                acl_next_hook_mailbox_list_created = hook_mailbox_list_created;
                hook_mailbox_list_created = acl_mailbox_list_created;
+
+               acl_next_hook_mail_user_created = hook_mail_user_created;
+               hook_mail_user_created = acl_mail_user_created;
+
+               acl_lookup_dicts_init();
        } else {
                if (getenv("DEBUG") != NULL)
                        i_info("acl: No acl setting - ACLs are disabled");
@@ -30,9 +37,9 @@ void acl_plugin_init(void)
 void acl_plugin_deinit(void)
 {
        if (acl_next_hook_mail_storage_created != NULL) {
-               hook_mail_storage_created =
-                       acl_next_hook_mail_storage_created;
-               hook_mailbox_list_created =
-                       acl_next_hook_mailbox_list_created;
+               acl_lookup_dicts_deinit();
+               hook_mail_storage_created = acl_next_hook_mail_storage_created;
+               hook_mailbox_list_created = acl_next_hook_mailbox_list_created;
+               hook_mail_user_created = acl_next_hook_mail_user_created;
        }
 }
index d8f83349f8da88401af4488d51c24f599a2b7aca..8b0ef0b101a1432b9c580e8beb9025a240d1e655 100644 (file)
@@ -1,11 +1,25 @@
 #ifndef ACL_PLUGIN_H
 #define ACL_PLUGIN_H
 
+#include "mail-user.h"
 #include "mail-storage-private.h"
 #include "acl-storage.h"
 
 #define ACL_CONTEXT(obj) \
        MODULE_CONTEXT(obj, acl_storage_module)
+#define ACL_USER_CONTEXT(obj) \
+       MODULE_CONTEXT(obj, acl_user_module)
+
+struct acl_user {
+       union mail_user_module_context module_ctx;
+
+       const char *master_user;
+       const char *acl_env;
+       const char *const *groups;
+
+       struct acl_lookup_dict *acl_lookup_dict;
+       time_t last_shared_add_check;
+};
 
 struct acl_storage_rights_context {
        struct acl_backend *backend;
@@ -17,13 +31,15 @@ struct acl_mail_storage {
        struct acl_storage_rights_context rights;
 };
 
-extern void (*acl_next_hook_mail_storage_created)
-       (struct mail_storage *storage);
+extern void (*acl_next_hook_mail_storage_created)(struct mail_storage *storage);
 extern void (*acl_next_hook_mailbox_list_created)(struct mailbox_list *list);
+extern void (*acl_next_hook_mail_user_created)(struct mail_user *user);
 extern MODULE_CONTEXT_DEFINE(acl_storage_module, &mail_storage_module_register);
+extern MODULE_CONTEXT_DEFINE(acl_user_module, &mail_user_module_register);
 
 void acl_mail_storage_created(struct mail_storage *storage);
 void acl_mailbox_list_created(struct mailbox_list *list);
+void acl_mail_user_created(struct mail_user *list);
 
 struct mailbox *acl_mailbox_open_box(struct mailbox *box);
 
diff --git a/src/plugins/acl/acl-shared-storage.c b/src/plugins/acl/acl-shared-storage.c
new file mode 100644 (file)
index 0000000..27e2321
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "ioloop.h"
+#include "str.h"
+#include "var-expand.h"
+#include "acl-plugin.h"
+#include "acl-lookup-dict.h"
+#include "acl-shared-storage.h"
+#include "index/shared/shared-storage.h"
+
+#define SHARED_NS_RETRY_SECS (60*60)
+
+static void
+acl_shared_namespace_add(struct mail_user *user,
+                        struct shared_storage *sstorage,
+                        const char *userdomain)
+{
+       static struct var_expand_table static_tab[] = {
+               { 'u', NULL },
+               { 'n', NULL },
+               { 'd', NULL },
+               { '\0', NULL }
+       };
+       struct var_expand_table *tab;
+       struct mail_namespace *ns;
+       const char *p, *mailbox;
+       string_t *str;
+
+       if (strcmp(user->username, userdomain) == 0) {
+               /* skip ourself */
+               return;
+       }
+
+       p = strchr(userdomain, '@');
+
+       tab = t_malloc(sizeof(static_tab));
+       memcpy(tab, static_tab, sizeof(static_tab));
+       tab[0].value = userdomain;
+       tab[1].value = p == NULL ? userdomain : t_strdup_until(userdomain, p);
+       tab[2].value = p == NULL ? "" : p + 1;
+
+       str = t_str_new(128);
+       var_expand(str, sstorage->ns_prefix_pattern, tab);
+       mailbox = str_c(str);
+       shared_storage_get_namespace(&sstorage->storage, &mailbox, &ns);
+}
+
+int acl_shared_namespaces_add(struct mail_namespace *ns)
+{
+       struct shared_storage *sstorage = (struct shared_storage *)ns->storage;
+       struct acl_user *auser = ACL_USER_CONTEXT(ns->user);
+       struct acl_lookup_dict_iter *iter;
+       const char *name;
+
+       i_assert(ns->type == NAMESPACE_SHARED);
+       i_assert(strcmp(ns->storage->name, SHARED_STORAGE_NAME) == 0);
+
+       if (ioloop_time < auser->last_shared_add_check + SHARED_NS_RETRY_SECS) {
+               /* already added, don't bother rechecking */
+               return 0;
+       }
+       auser->last_shared_add_check = ioloop_time;
+
+       iter = acl_lookup_dict_iterate_visible_init(auser->acl_lookup_dict);
+       while ((name = acl_lookup_dict_iterate_visible_next(iter)) != NULL) {
+               T_BEGIN {
+                       acl_shared_namespace_add(ns->user, sstorage, name);
+               } T_END;
+       }
+       return acl_lookup_dict_iterate_visible_deinit(&iter);
+}
diff --git a/src/plugins/acl/acl-shared-storage.h b/src/plugins/acl/acl-shared-storage.h
new file mode 100644 (file)
index 0000000..6e7736b
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef ACL_SHARED_STORAGE_H
+#define ACL_SHARED_STORAGE_H
+
+int acl_shared_namespaces_add(struct mail_namespace *ns);
+
+#endif
index 1075071e4db6518bd896c1da6d9906e393b7e707..efb160ddbb4709b25cc9754b97d6ce2374023a59 100644 (file)
@@ -6,10 +6,15 @@
 #include "mail-namespace.h"
 #include "mailbox-list-private.h"
 #include "acl-api-private.h"
+#include "acl-lookup-dict.h"
 #include "acl-plugin.h"
 
+#include <stdlib.h>
+
 struct acl_storage_module acl_storage_module =
        MODULE_CONTEXT_INIT(&mail_storage_module_register);
+struct acl_user_module acl_user_module =
+       MODULE_CONTEXT_INIT(&mail_user_module_register);
 
 static const char *acl_storage_right_names[ACL_STORAGE_RIGHT_COUNT] = {
        MAIL_ACL_LOOKUP,
@@ -187,3 +192,37 @@ void acl_mail_storage_created(struct mail_storage *storage)
                acl_next_hook_mail_storage_created(storage);
 }
 
+static void acl_user_deinit(struct mail_user *user)
+{
+       struct acl_user *auser = ACL_USER_CONTEXT(user);
+
+       acl_lookup_dict_deinit(&auser->acl_lookup_dict);
+       auser->module_ctx.super.deinit(user);
+}
+
+void acl_mail_user_created(struct mail_user *user)
+{
+       struct acl_user *auser;
+       const char *env;
+
+       auser = p_new(user->pool, struct acl_user, 1);
+       auser->module_ctx.super = user->v;
+       user->v.deinit = acl_user_deinit;
+       auser->acl_lookup_dict = acl_lookup_dict_init(user);
+
+       auser->acl_env = getenv("ACL");
+       i_assert(auser->acl_env != NULL);
+       auser->master_user = getenv("MASTER_USER");
+
+       env = getenv("ACL_GROUPS");
+       if (env != NULL) {
+               auser->groups =
+                       (const char *const *)p_strsplit(user->pool, env, ",");
+       }
+
+       MODULE_CONTEXT_SET(user, acl_user_module, auser);
+
+       if (acl_next_hook_mail_user_created != NULL)
+               acl_next_hook_mail_user_created(user);
+}
+
index b2db1924741571c96524e0dff4600c86205a3eee..3ed7cf55832826a2d3a41a31d74fff720df28b77 100644 (file)
@@ -17,6 +17,8 @@ enum acl_storage_rights {
        ACL_STORAGE_RIGHT_COUNT
 };
 
+/* Returns acl_backend for the given mail storage. */
+struct acl_backend *acl_storage_get_backend(struct mail_storage *storage);
 /* Returns default acl_object for the given mail storage. */
 struct acl_object *acl_storage_get_default_aclobj(struct mail_storage *storage);
 /* Returns acl_object for the given mailbox. */