]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
shared mailboxes: Cleanups, fixes and optimizations.
authorTimo Sirainen <tss@iki.fi>
Sat, 1 Nov 2008 14:05:19 +0000 (16:05 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 1 Nov 2008 14:05:19 +0000 (16:05 +0200)
--HG--
branch : HEAD

src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/index/shared/shared-storage.c
src/lib-storage/index/shared/shared-storage.h

index 3f112b98c0cd5955dcc6ffc515ffcab3388deaa3..6751beecf8f5aa8866a767fea94fad6f746b92ad 100644 (file)
@@ -119,8 +119,13 @@ static int dbox_create(struct mail_storage *_storage, const char *data,
        } else if (mkdir_parents(list_set.root_dir,
                                 CREATE_MODE) == 0 || errno == EEXIST) {
        } else if (errno == EACCES) {
-               *error_r = mail_storage_eacces_msg("mkdir", list_set.root_dir);
-               return -1;
+               if (_storage->ns->type != NAMESPACE_SHARED) {
+                       *error_r = mail_storage_eacces_msg("mkdir",
+                                                          list_set.root_dir);
+                       return -1;
+               }
+               /* can't create a new user, but we don't want to fail
+                  the storage creation. */
        } else {
                *error_r = t_strdup_printf("mkdir(%s) failed: %m",
                                           list_set.root_dir);
index 8b8caaee172f461df0827e950e6208e154fc1a5e..564c67dedb923d3068aabed24d55da08e3f335fb 100644 (file)
@@ -317,6 +317,11 @@ static int mkdir_verify(struct mail_storage *storage,
        } else if (errno == ENOENT) {
                mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND,
                        "Mailbox was deleted while it was being created");
+       } else if (errno == EACCES && storage->ns->type == NAMESPACE_SHARED) {
+               /* shared namespace, don't log permission errors */
+               mail_storage_set_error(storage, MAIL_ERROR_PERM,
+                                      MAIL_ERRSTR_NO_PERMISSION);
+               return -1;
        } else {
                mail_storage_set_critical(storage,
                                          "mkdir(%s) failed: %m", dir);
index 8a4b0ab8e2595bd299ce70454441a7448311fcc6..5d3ab4e9d2ba1b70ae346825c7f6692b04899bd7 100644 (file)
@@ -353,6 +353,10 @@ mbox_get_list_settings(struct mailbox_list_settings *list_set,
                        *error_r = t_strdup_printf("lstat(%s) failed: %m",
                                                   list_set->root_dir);
                        return -1;
+               } else if (errno == ENOENT &&
+                          storage->ns->type == NAMESPACE_SHARED) {
+                       /* can't create a new user, but we don't want to fail
+                          the storage creation. */
                } else if ((flags & MAIL_STORAGE_FLAG_NO_AUTOCREATE) != 0) {
                        *error_r = t_strdup_printf(
                                        "Root mail directory doesn't exist: %s",
index 8477f9393aebd9b7432b6af8d2967353384db170..85168a797db2c7703f6858549a616fafcb6314b2 100644 (file)
@@ -9,6 +9,7 @@
 #include "shared-storage.h"
 
 #include <stdlib.h>
+#include <ctype.h>
 
 #define SHARED_LIST_CONTEXT(obj) \
        MODULE_CONTEXT(obj, shared_mailbox_list_module)
@@ -30,6 +31,10 @@ static struct mail_storage *shared_alloc(void)
        storage->storage.pool = pool;
        storage->storage.storage_class = &shared_storage;
 
+       storage->base_dir = p_strdup(pool, getenv("BASE_DIR"));
+       if (storage->base_dir == NULL)
+               storage->base_dir = PKG_RUNDIR;
+
        return &storage->storage;
 }
 
@@ -99,47 +104,62 @@ static int shared_create(struct mail_storage *_storage, const char *data,
        return 0;
 }
 
-static const char *lookup_home(const char *user)
+static void shared_storage_destroy(struct mail_storage *_storage)
 {
-       const char *auth_socket;
-       const char *home = NULL;
-       struct auth_connection *conn;
-       struct auth_user_reply *reply;
-       pool_t userdb_pool;
-       struct ioloop *userdb_ioloop;
-
-       auth_socket = getenv("AUTH_SOCKET_PATH");
-       if (auth_socket == NULL) {
-               const char *base_dir = getenv("BASE_DIR");
-               if (base_dir == NULL)
-                       base_dir = PKG_RUNDIR;
-               auth_socket = t_strconcat(base_dir, "/auth-master",
-                                         NULL);
-       }
+       struct shared_storage *storage = (struct shared_storage *)_storage;
+
+       if (storage->auth_master_conn != NULL)
+               auth_master_deinit(&storage->auth_master_conn);
+       index_storage_destroy(_storage);
+}
+
+static void shared_storage_auth_master_init(struct shared_storage *storage)
+{
+       const char *auth_socket_path;
+       bool debug;
 
-       userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
-       userdb_ioloop = io_loop_create();
-       conn = auth_master_init(auth_socket, getenv("DEBUG") != NULL);
-       reply = i_new(struct auth_user_reply, 1);
-
-       switch (auth_master_user_lookup(conn, user, "shared-storage", userdb_pool, reply)) {
-       case -1:
-               /* Some error during lookup... */
-       case 0:
-               /* User not found
-                  FIXME: It might be a good idea to handle this special case... */
-               break;
-       case 1:
-               home = i_strdup(reply->home);
+       auth_socket_path = getenv("AUTH_SOCKET_PATH");
+       if (auth_socket_path == NULL) {
+               auth_socket_path = t_strconcat(storage->base_dir,
+                                              "/auth-master", NULL);
        }
-       
-       i_free(reply);
-       if (conn != NULL)
-               auth_master_deinit(conn);
-       io_loop_destroy(&userdb_ioloop);
+
+       debug = (storage->storage.flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+       storage->auth_master_conn = auth_master_init(auth_socket_path, debug);
+}
+
+static int
+shared_storage_lookup_home(struct shared_storage *storage,
+                          const char *user, const char **home_r)
+{
+       struct auth_user_reply reply;
+       pool_t userdb_pool;
+       int ret;
+
+       if (storage->auth_master_conn == NULL)
+               shared_storage_auth_master_init(storage);
+
+       userdb_pool = pool_alloconly_create("userdb lookup", 512);
+       ret = auth_master_user_lookup(storage->auth_master_conn, user,
+                                     AUTH_SERVICE_INTERNAL,
+                                     userdb_pool, &reply);
+       if (ret > 0)
+               *home_r = t_strdup(reply.home);
        pool_unref(&userdb_pool);
+       return ret;
+}
 
-       return home;
+static void get_nonexisting_user_location(struct shared_storage *storage,
+                                         string_t *location)
+{
+       /* user wasn't found. we'll still need to create the storage
+          to avoid exposing which users exist and which don't. */
+       str_append(location, storage->storage_class->name);
+       str_append_c(location, ':');
+
+       /* use a reachable but non-existing path as the mail root directory */
+       str_append(location, storage->base_dir);
+       str_append(location, PKG_RUNDIR"/user-not-found");
 }
 
 int shared_storage_get_namespace(struct mail_storage *_storage,
@@ -157,9 +177,12 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
        };
        struct var_expand_table *tab;
        struct mail_namespace *ns;
-       const char *domain = NULL, *username = NULL, *userdomain = NULL, *userhome = NULL;
+       const char *domain = NULL, *username = NULL, *userdomain = NULL;
        const char *name, *p, *next, **dest, *error;
        string_t *prefix, *location;
+       int ret;
+
+       *ns_r = NULL;
 
        p = storage->ns_prefix_pattern;
        for (name = *_name; *p != '\0';) {
@@ -207,12 +230,6 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
                }
        }
 
-       userhome = lookup_home(userdomain);
-       if (userhome == NULL) {
-               i_error("Namespace '%s': could not lookup home for user %s", _storage->ns->prefix, userdomain);
-               return -1;
-       }
-
        /* expand the namespace prefix and see if it already exists.
           this should normally happen only when the mailbox is being opened */
        tab = t_malloc(sizeof(static_tab));
@@ -220,7 +237,7 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
        tab[0].value = userdomain;
        tab[1].value = username;
        tab[2].value = domain;
-       tab[3].value = userhome;
+
        prefix = t_str_new(128);
        str_append(prefix, _storage->ns->prefix);
        var_expand(prefix, storage->ns_prefix_pattern, tab);
@@ -232,6 +249,20 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
                return 0;
        }
 
+       if (!var_has_key(storage->location, 'h'))
+               ret = 1;
+       else {
+               /* we'll need to look up the user's home directory */
+               ret = shared_storage_lookup_home(storage, userdomain,
+                                                &tab[3].value);
+               if (ret < 0) {
+                       mail_storage_set_critical(_storage, "Namespace '%s': "
+                               "Could not lookup home for user %s",
+                               _storage->ns->prefix, userdomain);
+                       return -1;
+               }
+       }
+
        /* create the new namespace */
        ns = p_new(user->pool, struct mail_namespace, 1);
        ns->type = NAMESPACE_SHARED;
@@ -242,7 +273,10 @@ int shared_storage_get_namespace(struct mail_storage *_storage,
        ns->sep = _storage->ns->sep;
 
        location = t_str_new(256);
-       var_expand(location, storage->location, tab);
+       if (ret > 0)
+               var_expand(location, storage->location, tab);
+       else
+               get_nonexisting_user_location(storage, location);
        if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
                                _storage->lock_method, &error) < 0) {
                mail_storage_set_critical(_storage, "Namespace '%s': %s",
@@ -301,6 +335,7 @@ static int shared_mailbox_create(struct mail_storage *storage,
 
        if (shared_storage_get_namespace(storage, &name, &ns) < 0)
                return -1;
+
        ret = mail_storage_mailbox_create(ns->storage, name, directory);
        if (ret < 0)
                shared_mailbox_copy_error(storage, ns);
@@ -316,7 +351,7 @@ struct mail_storage shared_storage = {
                NULL,
                shared_alloc,
                shared_create,
-               index_storage_destroy,
+               shared_storage_destroy,
                NULL,
                shared_mailbox_open,
                shared_mailbox_create
index e16886f097a7859a6cc0d0acd8249468d5aa772a..0a15bf4736893499521b817f840463e61dc661e5 100644 (file)
@@ -10,14 +10,17 @@ struct shared_storage {
        struct mail_storage storage;
        union mailbox_list_module_context list_module_ctx;
 
+       const char *base_dir;
        const char *ns_prefix_pattern;
        const char *location;
+       struct auth_master_connection *auth_master_conn;
 
        struct mail_storage *storage_class;
 };
 
 struct mailbox_list *shared_mailbox_list_alloc(void);
 
+/* Returns -1 = error, 0 = user doesn't exist, 1 = ok */
 int shared_storage_get_namespace(struct mail_storage *storage,
                                 const char **name,
                                 struct mail_namespace **ns_r);