Namespace owner is now a pointer to struct mail_user rather than a string.
--HG--
branch : HEAD
dict_drivers_register_builtin();
duplicate_init();
+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
module_dir_init(modules);
- mail_user = mail_user_init(user, home);
+ mail_user = mail_user_init(user);
+ mail_user_set_home(mail_user, home);
if (mail_namespaces_init(mail_user) < 0)
i_fatal("Namespace initialization failed");
/* create a separate mail user for the internal namespace */
- raw_mail_user = mail_user_init(user, NULL);
+ raw_mail_user = mail_user_init(user);
+ mail_user_set_home(raw_mail_user, NULL);
raw_ns = mail_namespaces_init_empty(raw_mail_user);
raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
mailbox_transaction_rollback(&t);
mailbox_close(&box);
- mail_user_deinit(&mail_user);
- mail_user_deinit(&raw_mail_user);
+ mail_user_unref(&mail_user);
+ mail_user_unref(&raw_mail_user);
module_dir_unload(&modules);
mail_storage_deinit();
+ mail_users_deinit();
duplicate_deinit();
dict_drivers_unregister_builtin();
client_search_updates_free(client);
mailbox_close(&client->mailbox);
}
- mail_user_deinit(&client->user);
+ mail_user_unref(&client->user);
if (client->free_parser != NULL)
imap_parser_destroy(&client->free_parser);
str_append(capability_string, CAPABILITY_STRING);
dict_drivers_register_builtin();
+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
parse_workarounds();
- user = mail_user_init(username, home);
+ user = mail_user_init(username);
+ mail_user_set_home(user, home);
if (mail_namespaces_init(user) < 0)
i_fatal("Namespace initialization failed");
client = client_create(0, 1, user);
module_dir_unload(&modules);
commands_deinit();
- mail_storage_deinit();
+ mail_storage_deinit();
+ mail_users_deinit();
dict_drivers_unregister_builtin();
str_free(&capability_string);
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
- -I$(top_srcdir)/src/lib-index
+ -I$(top_srcdir)/src/lib-index \
+ -DPKG_RUNDIR=\""$(rundir)"\"
libstorage_a_SOURCES = \
mail.c \
enum mail_storage_flags flags = storage->flags;
struct mail_user *user = storage->ns->user;
bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
- const char *path;
+ const char *path, *home;
*layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME;
/* we'll need to figure out the maildir location ourself.
It's ~/Maildir unless we are chrooted. */
- if (user->home != NULL) {
- path = t_strconcat(user->home, "/Maildir", NULL);
+ if (mail_user_get_home(user, &home) > 0) {
+ path = t_strconcat(home, "/Maildir", NULL);
if (access(path, R_OK|W_OK|X_OK) == 0) {
if (debug) {
i_info("maildir: root exists (%s)",
const char *home, *path;
bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
- home = storage->ns->user->home;
- if (home != NULL) {
+ if (mail_user_get_home(storage->ns->user, &home) > 0) {
path = t_strconcat(home, "/mail", NULL);
if (access(path, R_OK|W_OK|X_OK) == 0) {
if (debug)
{
const char *home, *path;
- home = storage->ns->user->home;
- if (home == NULL) {
+ if (mail_user_get_home(storage->ns->user, &home) <= 0) {
*error_r = "Root mail directory not set and "
"home directory is missing";
return NULL;
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
- -I$(top_srcdir)/src/lib-auth \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
#include "array.h"
#include "str.h"
#include "ioloop.h"
-#include "auth-master.h"
#include "var-expand.h"
#include "index-storage.h"
#include "shared-storage.h"
return 0;
}
-static void shared_storage_destroy(struct mail_storage *_storage)
-{
- 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;
-
- auth_socket_path = getenv("AUTH_SOCKET_PATH");
- if (auth_socket_path == NULL) {
- auth_socket_path = t_strconcat(storage->base_dir,
- "/auth-master", NULL);
- }
-
- 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;
-}
-
-static void get_nonexisting_user_location(struct shared_storage *storage,
- string_t *location)
+static void
+get_nonexisting_user_location(struct shared_storage *storage,
+ const char *username, 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. */
/* 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");
+ str_append(location, "/user-not-found/");
+ str_append(location, username);
}
int shared_storage_get_namespace(struct mail_storage *_storage,
};
struct var_expand_table *tab;
struct mail_namespace *ns;
+ struct mail_user *owner;
const char *domain = NULL, *username = NULL, *userdomain = NULL;
const char *name, *p, *next, **dest, *error;
string_t *prefix, *location;
return 0;
}
+ owner = mail_user_init(userdomain);
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) {
+ if ((ret = mail_user_get_home(owner, &tab[3].value)) < 0) {
mail_storage_set_critical(_storage, "Namespace '%s': "
"Could not lookup home for user %s",
_storage->ns->prefix, userdomain);
+ mail_user_unref(&owner);
return -1;
}
}
ns->type = NAMESPACE_SHARED;
ns->user = user;
ns->prefix = i_strdup(str_c(prefix));
- ns->owner = i_strdup(userdomain);
+ ns->owner = owner;
ns->flags = NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
NAMESPACE_FLAG_AUTOCREATED;
ns->sep = _storage->ns->sep;
if (ret > 0)
var_expand(location, storage->location, tab);
else
- get_nonexisting_user_location(storage, location);
+ get_nonexisting_user_location(storage, userdomain, 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",
ns->prefix, error);
+ mail_namespace_destroy(ns);
return -1;
}
mail_user_add_namespace(user, ns);
NULL,
shared_alloc,
shared_create,
- shared_storage_destroy,
+ index_storage_destroy,
NULL,
shared_mailbox_open,
shared_mailbox_create
const char *base_dir;
const char *ns_prefix_pattern;
const char *location;
- struct auth_master_connection *auth_master_conn;
struct mail_storage *storage_class;
};
static void mail_namespace_free(struct mail_namespace *ns)
{
- i_free(ns->owner);
+ if (ns->owner != NULL)
+ mail_user_unref(&ns->owner);
i_free(ns->prefix);
i_free(ns);
}
if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0) {
ns->type = NAMESPACE_PRIVATE;
- ns->owner = i_strdup(user->username);
+ ns->owner = user;
+ mail_user_ref(ns->owner);
} else if (strncmp(type, "shared", 6) == 0)
ns->type = NAMESPACE_SHARED;
else if (strncmp(type, "public", 6) == 0)
}
ns = i_new(struct mail_namespace, 1);
- ns->owner = i_strdup(user->username);
ns->type = NAMESPACE_PRIVATE;
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_SUBSCRIPTIONS;
ns->prefix = i_strdup("");
ns->user = user;
+ ns->owner = user;
+ mail_user_ref(ns->owner);
if (mail_storage_create(ns, NULL, mail, flags, lock_method,
&error) < 0) {
ns = i_new(struct mail_namespace, 1);
ns->user = user;
+ ns->owner = user;
+ mail_user_ref(ns->owner);
ns->prefix = i_strdup("");
- ns->owner = i_strdup(user->username);
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_SUBSCRIPTIONS;
user->namespaces = ns;
char sep, real_sep, sep_str[3];
enum namespace_flags flags;
- char *prefix, *owner;
+ char *prefix;
size_t prefix_len;
- struct mail_user *user;
+ struct mail_user *user, *owner;
struct mailbox_list *list;
/* FIXME: we should support multiple storages in one namespace */
struct mail_storage *storage;
return -1;
}
- home = ns->user->home;
+ (void)mail_user_get_home(ns->user, &home);
if (home == NULL || *home == '\0') home = "(not set)";
*error_r = t_strdup_printf(
#include "lib.h"
#include "array.h"
+#include "auth-master.h"
#include "mail-namespace.h"
#include "mail-user.h"
+#include <stdlib.h>
+
struct mail_user_module_register mail_user_module_register = { 0 };
void (*hook_mail_user_created)(struct mail_user *user) = NULL;
+static struct auth_master_connection *auth_master_conn;
+
static void mail_user_deinit_base(struct mail_user *user)
{
mail_namespaces_deinit(&user->namespaces);
pool_unref(&user->pool);
}
-struct mail_user *mail_user_init(const char *username, const char *home)
+struct mail_user *mail_user_init(const char *username)
{
struct mail_user *user;
pool_t pool;
pool = pool_alloconly_create("mail user", 512);
user = p_new(pool, struct mail_user, 1);
user->pool = pool;
+ user->refcount = 1;
user->username = p_strdup_empty(pool, username);
- user->home = p_strdup(pool, home);
user->v.deinit = mail_user_deinit_base;
p_array_init(&user->module_contexts, user->pool, 5);
return user;
}
-void mail_user_deinit(struct mail_user **_user)
+void mail_user_ref(struct mail_user *user)
+{
+ i_assert(user->refcount > 0);
+
+ user->refcount++;
+}
+
+void mail_user_unref(struct mail_user **_user)
{
struct mail_user *user = *_user;
+ i_assert(user->refcount > 0);
+
*_user = NULL;
- user->v.deinit(user);
+ if (--user->refcount == 0)
+ user->v.deinit(user);
+}
+
+void mail_user_set_home(struct mail_user *user, const char *home)
+{
+ user->_home = p_strdup(user->pool, home);
+ user->home_looked_up = TRUE;
}
void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns)
return path;
}
+int mail_user_get_home(struct mail_user *user, const char **home_r)
+{
+ struct auth_user_reply reply;
+ pool_t userdb_pool;
+ int ret;
+
+ userdb_pool = pool_alloconly_create("userdb lookup", 512);
+ ret = auth_master_user_lookup(auth_master_conn, user->username,
+ AUTH_SERVICE_INTERNAL,
+ userdb_pool, &reply);
+ if (ret < 0)
+ *home_r = NULL;
+ else {
+ user->_home = ret == 0 ? NULL :
+ p_strdup(user->pool, reply.home);
+ user->home_looked_up = TRUE;
+ ret = user->_home != NULL ? 1 : 0;
+ *home_r = user->_home;
+ }
+ pool_unref(&userdb_pool);
+ return ret;
+}
+
int mail_user_try_home_expand(struct mail_user *user, const char **pathp)
{
- const char *path = *pathp;
+ const char *home, *path = *pathp;
+
+ if (!user->home_looked_up) {
+ if (mail_user_get_home(user, &home) < 0)
+ return -1;
+ }
if (path[0] == '~' && (path[1] == '/' || path[1] == '\0')) {
- if (user->home == NULL)
+ if (user->_home == NULL)
return -1;
- *pathp = t_strconcat(user->home, path + 1, NULL);
+ *pathp = t_strconcat(user->_home, path + 1, NULL);
}
return 0;
}
+
+void mail_users_init(const char *auth_socket_path, bool debug)
+{
+ const char *base_dir;
+
+ if (auth_socket_path == NULL) {
+ base_dir = getenv("BASE_DIR");
+ if (base_dir == NULL)
+ base_dir = PKG_RUNDIR;
+ auth_socket_path = t_strconcat(base_dir, "/auth-master", NULL);
+ }
+ auth_master_conn = auth_master_init(auth_socket_path, debug);
+}
+
+void mail_users_deinit(void)
+{
+ auth_master_deinit(&auth_master_conn);
+}
struct mail_user {
pool_t pool;
struct mail_user_vfuncs v;
+ int refcount;
const char *username;
- const char *home;
+ /* don't access the home directly. It may be set lazily. */
+ const char *_home;
struct mail_namespace *namespaces;
/* Module-specific contexts. See mail_storage_module_id. */
ARRAY_DEFINE(module_contexts, union mail_user_module_context *);
+
+ /* Either home is set or there is no home for the user. */
+ unsigned int home_looked_up:1;
};
struct mail_user_module_register {
/* Called after user has been created */
extern void (*hook_mail_user_created)(struct mail_user *user);
-struct mail_user *mail_user_init(const char *username, const char *home);
-void mail_user_deinit(struct mail_user **user);
+void mail_users_init(const char *auth_socket_path, bool debug);
+void mail_users_deinit(void);
+
+struct mail_user *mail_user_init(const char *username);
+void mail_user_ref(struct mail_user *user);
+void mail_user_unref(struct mail_user **user);
+
+/* Specify the user's home directory. This should be called also when it's
+ known that the user doesn't have a home directory to avoid the internal
+ lookup. */
+void mail_user_set_home(struct mail_user *user, const char *home);
+/* Get the home directory for the user. Returns 1 if home directory looked up
+ successfully, 0 if there is no home directory (either user doesn't exist or
+ has no home directory) or -1 if lookup failed. */
+int mail_user_get_home(struct mail_user *user, const char **home_r);
/* Add a new namespace to user's namespaces. */
void mail_user_add_namespace(struct mail_user *user, struct mail_namespace *ns);
str_truncate(id, 0);
acl_lookup_dict_write_rights_id(id, &rights);
str_append_c(id, '/');
- str_append(id, ns->owner);
+ str_append(id, ns->owner->username);
id_dup = t_strdup(str_c(id));
array_append(ids, &id_dup, 1);
}
struct convert_settings set;
memset(&set, 0, sizeof(set));
- if (namespaces->user->home == NULL)
+ if (mail_user_get_home(namespaces->user, &str) <= 0)
i_fatal("convert plugin: HOME unset");
set.skip_broken_mailboxes =
struct dotlock *dotlock;
enum mail_storage_flags src_flags;
enum file_lock_method lock_method;
- const char *path, *error;
+ const char *home, *path, *error;
int ret;
source_ns = mail_namespaces_init_empty(user);
return 0;
}
- path = t_strconcat(user->home, "/"CONVERT_LOCK_FILENAME, NULL);
+ if (mail_user_get_home(user, &home) <= 0)
+ i_unreached();
+ path = t_strconcat(home, "/"CONVERT_LOCK_FILENAME, NULL);
dotlock_settings.use_excl_lock =
(source_ns->storage->flags &
MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
lib_init();
lib_signals_init();
random_init();
+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
}
mail_storage_parse_env(&dest_flags, &lock_method);
- user = mail_user_init(argv[1], argv[2]);
+ user = mail_user_init(argv[1]);
+ mail_user_set_home(user, argv[2]);
dest_ns = mail_namespaces_init_empty(user);
if (mail_storage_create(dest_ns, NULL, argv[4],
i_error("Source storage not found");
else
i_error("Internal failure");
- mail_user_deinit(&user);
+ mail_user_unref(&user);
io_loop_destroy(&ioloop);
mail_storage_deinit();
+ mail_users_deinit();
lib_signals_deinit();
lib_deinit();
return ret <= 0 ? 1 : 0;
return 0;
}
- ctx->mail_user = mail_user_init(user, getenv("HOME"));
+ ctx->mail_user = mail_user_init(user);
+ mail_user_set_home(ctx->mail_user, getenv("HOME"));
if (mail_namespaces_init(ctx->mail_user) < 0)
return -1;
return 1;
static void user_deinit(struct expire_context *ctx)
{
- mail_user_deinit(&ctx->mail_user);
+ mail_user_unref(&ctx->mail_user);
i_free_and_null(ctx->user);
}
int ret;
dict_drivers_register_builtin();
+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
auth_master_deinit(&ctx.auth_conn);
mail_storage_deinit();
+ mail_users_deinit();
dict_drivers_unregister_builtin();
}
}
if (client->mailbox != NULL)
mailbox_close(&client->mailbox);
- mail_user_deinit(&client->user);
+ mail_user_unref(&client->user);
i_free(client->message_sizes);
i_free(client->deleted_bitmask);
}
dict_drivers_register_builtin();
+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
mail_storage_init();
mail_storage_register_all();
mailbox_list_register_all();
i_fatal("pop3_uidl_format setting doesn't contain any "
"%% variables.");
- user = mail_user_init(getenv("USER"), getenv("HOME"));
+ user = mail_user_init(getenv("USER"));
+ mail_user_set_home(user, getenv("HOME"));
if (mail_namespaces_init(user) < 0)
i_fatal("Namespace initialization failed");
module_dir_unload(&modules);
mail_storage_deinit();
+ mail_users_deinit();
dict_drivers_unregister_builtin();
lib_signals_deinit();