changeset 10130:d1384c2b08e5 HEAD

Merged single and multi mail_storage_service_*() functions.
author Timo Sirainen <tss@iki.fi>
date Wed, 21 Oct 2009 19:54:00 -0400
parents 3c87c0b18090
children 9ef0821a2ce7
files src/doveadm/doveadm-mail.c src/dsync/dsync.c src/imap/imap-client.c src/imap/imap-client.h src/imap/main.c src/lda/main.c src/lib-storage/mail-storage-service.c src/lib-storage/mail-storage-service.h src/lib-storage/mail-user.c src/lib-storage/mail-user.h src/lmtp/client.c src/lmtp/client.h src/lmtp/commands.c src/lmtp/main.c src/lmtp/main.h src/plugins/convert/convert-tool.c src/plugins/expire/expire-tool.c src/pop3/main.c src/pop3/pop3-client.c src/pop3/pop3-client.h
diffstat 20 files changed, 438 insertions(+), 474 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/doveadm-mail.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/doveadm/doveadm-mail.c	Wed Oct 21 19:54:00 2009 -0400
@@ -79,35 +79,44 @@
 			 enum mail_storage_service_flags service_flags,
 			 const char *args[])
 {
+	struct mail_storage_service_ctx *storage_service;
+	struct mail_storage_service_user *service_user;
 	struct mail_storage_service_input input;
 	struct mail_user *mail_user;
+	const char *error;
 
 	if (username == NULL)
 		i_fatal("USER environment is missing and -u option not used");
 
 	memset(&input, 0, sizeof(input));
 	input.username = username;
-	mail_user = mail_storage_service_init_user(master_service, &input, NULL,
-						   service_flags);
+
+	storage_service = mail_storage_service_init(master_service, NULL,
+						    service_flags);
+	if (mail_storage_service_lookup_next(storage_service, &input,
+					     &service_user, &mail_user,
+					     &error) <= 0)
+		i_fatal("%s", error);
 	cmd(mail_user, args);
 	mail_user_unref(&mail_user);
-	mail_storage_service_deinit_user();
+	mail_storage_service_user_free(&service_user);
+	mail_storage_service_deinit(&storage_service);
 }
 
 static int
 doveadm_mail_next_user(doveadm_mail_command_t *cmd,
-		       struct mail_storage_service_multi_ctx *multi,
+		       struct mail_storage_service_ctx *storage_service,
 		       const struct mail_storage_service_input *input,
-		       pool_t pool, const char *args[])
+		       const char *args[])
 {
-	struct mail_storage_service_multi_user *multi_user;
+	struct mail_storage_service_user *service_user;
 	struct mail_user *mail_user;
 	const char *error;
 	int ret;
 
 	i_set_failure_prefix(t_strdup_printf("doveadm(%s): ", input->username));
-	ret = mail_storage_service_multi_lookup(multi, input, pool,
-						&multi_user, &error);
+	ret = mail_storage_service_lookup(storage_service, input,
+					  &service_user, &error);
 	if (ret <= 0) {
 		if (ret == 0) {
 			i_info("User no longer exists, skipping");
@@ -117,14 +126,14 @@
 			return -1;
 		}
 	}
-	if (mail_storage_service_multi_next(multi, multi_user,
-					    &mail_user, &error) < 0) {
+	if (mail_storage_service_next(storage_service, service_user,
+				      &mail_user, &error) < 0) {
 		i_error("User init failed: %s", error);
-		mail_storage_service_multi_user_free(multi_user);
+		mail_storage_service_user_free(&service_user);
 		return -1;
 	}
-	mail_storage_service_multi_user_free(multi_user);
 	cmd(mail_user, args);
+	mail_storage_service_user_free(&service_user);
 	mail_user_unref(&mail_user);
 	return 0;
 }
@@ -140,10 +149,9 @@
 		       const char *args[])
 {
 	struct mail_storage_service_input input;
-	struct mail_storage_service_multi_ctx *multi;
+	struct mail_storage_service_ctx *storage_service;
 	unsigned int user_idx, user_count, interval, n;
 	const char *user;
-	pool_t pool;
 	int ret;
 
 	service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
@@ -151,25 +159,24 @@
 	memset(&input, 0, sizeof(input));
 	input.service = "doveadm";
 
-	multi = mail_storage_service_multi_init(master_service, NULL,
-						service_flags);
-	pool = pool_alloconly_create("multi user", 8192);
+	storage_service = mail_storage_service_init(master_service, NULL,
+						    service_flags);
 
         lib_signals_set_handler(SIGINT, FALSE, sig_die, NULL);
 	lib_signals_set_handler(SIGTERM, FALSE, sig_die, NULL);
 
-	user_count = mail_storage_service_multi_all_init(multi);
+	user_count = mail_storage_service_all_init(storage_service);
 	n = user_count / 10000;
 	for (interval = 10; n > 0 && interval < 1000; interval *= 10)
 		n /= 10;
 	
 	user_idx = 0;
-	while ((ret = mail_storage_service_multi_all_next(multi, &user)) > 0) {
-		p_clear(pool);
+	while ((ret = mail_storage_service_all_next(storage_service,
+						    &user)) > 0) {
 		input.username = user;
 		T_BEGIN {
-			ret = doveadm_mail_next_user(cmd, multi, &input,
-						     pool, args);
+			ret = doveadm_mail_next_user(cmd, storage_service,
+						     &input, args);
 		} T_END;
 		if (ret < 0)
 			break;
@@ -190,8 +197,7 @@
 	i_set_failure_prefix("doveadm: ");
 	if (ret < 0)
 		i_error("Failed to iterate through some users");
-	mail_storage_service_multi_deinit(&multi);
-	pool_unref(&pool);
+	mail_storage_service_deinit(&storage_service);
 }
 
 static void
--- a/src/dsync/dsync.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/dsync/dsync.c	Wed Oct 21 19:54:00 2009 -0400
@@ -69,10 +69,12 @@
 	enum mail_storage_service_flags ssflags =
 		MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR;
 	enum dsync_brain_flags brain_flags = 0;
+	struct mail_storage_service_ctx *storage_service;
+	struct mail_storage_service_user *service_user;
 	struct mail_storage_service_input input;
 	struct mail_user *mail_user;
 	struct dsync_worker *worker1, *worker2;
-	const char *username, *mailbox = NULL, *cmd = NULL;
+	const char *error, *username, *mailbox = NULL, *cmd = NULL;
 	bool dest = TRUE;
 	int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO;
 
@@ -112,8 +114,13 @@
 
 	memset(&input, 0, sizeof(input));
 	input.username = username;
-	mail_user = mail_storage_service_init_user(master_service,
-						   &input, NULL, ssflags);
+
+	storage_service = mail_storage_service_init(master_service, NULL,
+						    ssflags);
+	if (mail_storage_service_lookup_next(storage_service, &input,
+					     &service_user, &mail_user,
+					     &error) <= 0)
+		i_fatal("%s", error);
 
 	if (cmd != NULL) {
 		/* user initialization may exec doveconf, so do our forking
@@ -152,7 +159,8 @@
 		dsync_worker_deinit(&worker2);
 
 	mail_user_unref(&mail_user);
-	mail_storage_service_deinit_user();
+	mail_storage_service_user_free(&service_user);
+	mail_storage_service_deinit(&storage_service);
 	master_service_deinit(&master_service);
 	return ret < 0 ? 1 : 0;
 }
--- a/src/imap/imap-client.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/imap/imap-client.c	Wed Oct 21 19:54:00 2009 -0400
@@ -13,6 +13,7 @@
 #include "imap-resp-code.h"
 #include "imap-util.h"
 #include "mail-namespace.h"
+#include "mail-storage-service.h"
 #include "imap-commands.h"
 
 #include <stdlib.h>
@@ -31,6 +32,7 @@
 }
 
 struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+			     struct mail_storage_service_user *service_user,
 			     const struct imap_settings *set)
 {
 	struct client *client;
@@ -42,6 +44,7 @@
 
 	client = i_new(struct client, 1);
 	client->set = set;
+	client->service_user = service_user;
 	client->fd_in = fd_in;
 	client->fd_out = fd_out;
 	client->input = i_stream_create_fd(fd_in,
@@ -212,6 +215,7 @@
 		array_free(&client->search_updates);
 	str_free(&client->capability_string);
 	pool_unref(&client->command_pool);
+	mail_storage_service_user_free(&client->service_user);
 	i_free(client);
 
 	master_service_client_connection_destroyed(master_service);
--- a/src/imap/imap-client.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/imap/imap-client.h	Wed Oct 21 19:54:00 2009 -0400
@@ -94,6 +94,7 @@
 	struct ostream *output;
 	struct timeout *to_idle, *to_idle_output;
 
+	struct mail_storage_service_user *service_user;
         const struct imap_settings *set;
 	string_t *capability_string;
 
@@ -151,6 +152,7 @@
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
 struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+			     struct mail_storage_service_user *service_user,
 			     const struct imap_settings *set);
 void client_destroy(struct client *client, const char *reason);
 
--- a/src/imap/main.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/imap/main.c	Wed Oct 21 19:54:00 2009 -0400
@@ -23,13 +23,8 @@
 #define IS_STANDALONE() \
         (getenv(MASTER_UID_ENV) == NULL)
 
-static const struct setting_parser_info *set_roots[] = {
-	&imap_setting_parser_info,
-	NULL
-};
+static struct mail_storage_service_ctx *storage_service;
 static struct master_login *master_login = NULL;
-static enum mail_storage_service_flags storage_service_flags = 0;
-static bool user_initialized = FALSE;
 
 void (*hook_client_created)(struct client **client) = NULL;
 
@@ -87,7 +82,9 @@
 }
 
 static void
-main_stdio_init_user(const struct imap_settings *set, struct mail_user *user)
+main_stdio_init_user(const struct imap_settings *set,
+		     struct mail_user *mail_user,
+		     struct mail_storage_service_user *user)
 {
 	struct client *client;
 	buffer_t *input_buf;
@@ -97,7 +94,8 @@
 	input_buf = input_base64 == NULL ? NULL :
 		t_base64_decode_str(input_base64);
 
-	client = client_create(STDIN_FILENO, STDOUT_FILENO, user, set);
+	client = client_create(STDIN_FILENO, STDOUT_FILENO,
+			       mail_user, user, set);
 	client_add_input(client, input_buf);
 }
 
@@ -107,6 +105,10 @@
 	struct mail_user *mail_user;
 	const struct imap_settings *set;
 	const char *value;
+	struct mail_storage_service_user *user;
+	const char *error;
+	pool_t user_pool;
+	int ret;
 
 	memset(&input, 0, sizeof(input));
 	input.module = input.service = "imap";
@@ -120,11 +122,17 @@
 	if ((value = getenv("LOCAL_IP")) != NULL)
 		net_addr2ip(value, &input.local_ip);
 
-	user_initialized = TRUE;
-	mail_user = mail_storage_service_init_user(master_service,
-						   &input, set_roots,
-						   storage_service_flags);
-	set = mail_storage_service_get_settings(master_service);
+	user_pool = pool_alloconly_create("storage user pool", 512);
+	ret = mail_storage_service_lookup(storage_service, &input,
+					  &user, &error);
+	if (ret <= 0)
+		i_fatal("User lookup failed: %s", error);
+	if (mail_storage_service_next(storage_service,
+				      user, &mail_user, &error) < 0)
+		i_fatal("User init failed: %s", error);
+
+	set = mail_storage_service_user_get_set(user)[1];
+
 	restrict_access_allow_coredumps(TRUE);
 	if (set->shutdown_clients)
 		master_service_set_die_with_master(master_service, TRUE);
@@ -132,7 +140,7 @@
 	/* fake that we're running, so we know if client was destroyed
 	   while handling its initial input */
 	io_loop_set_running(current_ioloop);
-	main_stdio_init_user(set, mail_user);
+	main_stdio_init_user(set, mail_user, user);
 }
 
 static void
@@ -140,9 +148,11 @@
 		       const char *username, const char *const *extra_fields)
 {
 	struct mail_storage_service_input input;
+	struct mail_storage_service_user *user;
 	struct mail_user *mail_user;
 	struct client *imap_client;
 	const struct imap_settings *set;
+	const char *error;
 	buffer_t input_buf;
 
 	if (imap_clients != NULL) {
@@ -150,7 +160,6 @@
 		(void)close(client->fd);
 		return;
 	}
-	i_assert(!user_initialized);
 
 	memset(&input, 0, sizeof(input));
 	input.module = input.service = "imap";
@@ -164,13 +173,13 @@
 		(void)close(client->fd);
 		return;
 	}
-	user_initialized = TRUE;
 	master_login_deinit(&master_login);
 
-	mail_user = mail_storage_service_init_user(master_service,
-						   &input, set_roots,
-						   storage_service_flags);
-	set = mail_storage_service_get_settings(master_service);
+	if (mail_storage_service_lookup_next(storage_service, &input,
+					     &user, &mail_user, &error) <= 0)
+		i_fatal("%s", error);
+	set = mail_storage_service_user_get_set(user)[1];
+
 	restrict_access_allow_coredumps(TRUE);
 	if (set->shutdown_clients)
 		master_service_set_die_with_master(master_service, TRUE);
@@ -181,7 +190,8 @@
 
 	buffer_create_const_data(&input_buf, client->data,
 				 client->auth_req.data_size);
-	imap_client = client_create(client->fd, client->fd, mail_user, set);
+	imap_client = client_create(client->fd, client->fd, mail_user,
+				    user, set);
 	T_BEGIN {
 		client_add_input(imap_client, &input_buf);
 	} T_END;
@@ -199,7 +209,12 @@
 
 int main(int argc, char *argv[])
 {
+	static const struct setting_parser_info *set_roots[] = {
+		&imap_setting_parser_info,
+		NULL
+	};
 	enum master_service_flags service_flags = 0;
+	enum mail_storage_service_flags storage_service_flags = 0;
 
 	if (IS_STANDALONE() && getuid() == 0 &&
 	    net_getpeername(1, NULL, NULL) == 0) {
@@ -219,13 +234,17 @@
 	master_service = master_service_init("imap", service_flags,
 					     &argc, &argv, NULL);
 	if (master_getopt(master_service) > 0)
-		exit(FATAL_DEFAULT);
+		return FATAL_DEFAULT;
 	master_service_init_finish(master_service);
 
 	/* plugins may want to add commands, so this needs to be called early */
 	commands_init();
 	imap_fetch_handlers_init();
 
+	storage_service =
+		mail_storage_service_init(master_service,
+					  set_roots, storage_service_flags);
+
 	if (IS_STANDALONE()) {
 		T_BEGIN {
 			main_stdio_run();
@@ -242,8 +261,8 @@
 
 	if (master_login != NULL)
 		master_login_deinit(&master_login);
-	if (user_initialized)
-		mail_storage_service_deinit_user();
+	mail_storage_service_deinit(&storage_service);
+
 	imap_fetch_handlers_deinit();
 	commands_deinit();
 
--- a/src/lda/main.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lda/main.c	Wed Oct 21 19:54:00 2009 -0400
@@ -245,6 +245,8 @@
 	struct mail_deliver_context ctx;
 	enum mail_storage_service_flags service_flags = 0;
 	const char *user, *errstr, *path;
+	struct mail_storage_service_ctx *storage_service;
+	struct mail_storage_service_user *service_user;
 	struct mail_storage_service_input service_input;
 	struct mail_user *raw_mail_user;
 	struct mail_namespace *raw_ns;
@@ -380,14 +382,17 @@
 	service_input.username = user;
 
 	service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT;
-	ctx.dest_user = mail_storage_service_init_user(master_service,
-						       &service_input,
-						       set_roots,
-						       service_flags);
+	storage_service = mail_storage_service_init(master_service, set_roots,
+						    service_flags);
+	if (mail_storage_service_lookup_next(storage_service, &service_input,
+					     &service_user, &ctx.dest_user,
+					     &errstr) <= 0)
+		i_fatal("%s", errstr);
+
 #ifdef SIGXFSZ
         lib_signals_ignore(SIGXFSZ, TRUE);
 #endif
-	ctx.set = mail_storage_service_get_settings(master_service);
+	ctx.set = mail_storage_service_user_get_set(service_user)[1];
         duplicate_init(mail_user_set_get_storage_set(ctx.dest_user->set));
 
 	/* create a separate mail user for the internal namespace */
@@ -489,7 +494,8 @@
 	duplicate_deinit();
 	pool_unref(&ctx.pool);
 
-	mail_storage_service_deinit_user();
+	mail_storage_service_user_free(&service_user);
+	mail_storage_service_deinit(&storage_service);
 	master_service_deinit(&master_service);
         return EX_OK;
 }
--- a/src/lib-storage/mail-storage-service.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lib-storage/mail-storage-service.c	Wed Oct 21 19:54:00 2009 -0400
@@ -27,16 +27,18 @@
 #define MAX_TIME_BACKWARDS_SLEEP 5
 #define MAX_NOWARN_FORWARD_SECS 10
 
-struct mail_storage_service_multi_ctx {
+struct mail_storage_service_ctx {
 	struct master_service *service;
 	struct auth_master_connection *conn;
 	struct auth_master_user_list_ctx *auth_list;
+	const struct setting_parser_info **set_roots;
 	enum mail_storage_service_flags flags;
 
 	unsigned int modules_initialized:1;
+	unsigned int debug:1;
 };
 
-struct mail_storage_service_multi_user {
+struct mail_storage_service_user {
 	pool_t pool;
 	struct mail_storage_service_input input;
 
@@ -81,17 +83,15 @@
 }
 
 static int
-user_reply_handle(struct setting_parser_context *set_parser,
-		  const struct mail_user_settings *user_set,
+user_reply_handle(struct mail_storage_service_user *user,
 		  const struct auth_user_reply *reply,
-		  const char **system_groups_user_r, const char **error_r)
+		  const char **error_r)
 {
+	struct setting_parser_context *set_parser = user->set_parser;
 	const char *const *str, *p, *line, *key;
 	unsigned int i, count;
 	int ret = 0;
 
-	*system_groups_user_r = NULL;
-
 	if (reply->uid != (uid_t)-1) {
 		if (reply->uid == 0) {
 			*error_r = "userdb returned 0 as uid";
@@ -106,7 +106,7 @@
 		set_keyval(set_parser, "mail_home", reply->home);
 
 	if (reply->chroot != NULL) {
-		if (!validate_chroot(user_set, reply->chroot)) {
+		if (!validate_chroot(user->user_set, reply->chroot)) {
 			*error_r = t_strdup_printf(
 				"userdb returned invalid chroot directory: %s "
 				"(see valid_chroot_dirs setting)",
@@ -119,9 +119,10 @@
 	str = array_get(&reply->extra_fields, &count);
 	for (i = 0; i < count && ret == 0; i++) {
 		line = str[i];
-		if (strncmp(line, "system_groups_user=", 19) == 0)
-			*system_groups_user_r = t_strdup(line + 19);
-		else T_BEGIN {
+		if (strncmp(line, "system_groups_user=", 19) == 0) {
+			user->system_groups_user =
+				p_strdup(user->pool, line + 19);
+		} else T_BEGIN {
 			if (strncmp(line, "mail=", 5) == 0) {
 				line = t_strconcat("mail_location=",
 						   line + 5, NULL);
@@ -148,10 +149,8 @@
 }
 
 static int
-service_auth_userdb_lookup(struct auth_master_connection *conn,
-			   const char *service_name,
+service_auth_userdb_lookup(struct mail_storage_service_ctx *ctx,
 			   const struct mail_storage_service_input *input,
-			   const struct mail_user_settings *user_set,
 			   pool_t pool, const char **user,
 			   const char *const **fields_r,
 			   const char **error_r)
@@ -161,15 +160,15 @@
 	int ret;
 
 	memset(&info, 0, sizeof(info));
-	info.service = service_name;
+	info.service = ctx->service->name;
 	info.local_ip = input->local_ip;
 	info.remote_ip = input->remote_ip;
 
-	ret = auth_master_user_lookup(conn, *user, &info, pool,
+	ret = auth_master_user_lookup(ctx->conn, *user, &info, pool,
 				      &new_username, fields_r);
 	if (ret > 0) {
 		if (strcmp(*user, new_username) != 0) {
-			if (mail_user_set_get_storage_set(user_set)->mail_debug)
+			if (ctx->debug)
 				i_debug("changed username to %s", new_username);
 			*user = t_strdup(new_username);
 		}
@@ -290,56 +289,11 @@
 	}
 }
 
-static void
-mail_storage_service_init_settings(struct master_service *service,
-				   const struct mail_storage_service_input *input,
-				   const struct setting_parser_info *set_roots[],
-				   bool preserve_home)
-{
-	ARRAY_DEFINE(all_set_roots, const struct setting_parser_info *);
-	const struct setting_parser_info *info = &mail_user_setting_parser_info;
-	struct master_service_settings_input set_input;
-	const char *error;
-	unsigned int i;
-
-	(void)umask(0077);
-
-        mail_storage_init();
-	mail_storage_register_all();
-	mailbox_list_register_all();
-
-	t_array_init(&all_set_roots, 5);
-	array_append(&all_set_roots, &info, 1);
-	if (set_roots != NULL) {
-		for (i = 0; set_roots[i] != NULL; i++)
-			array_append(&all_set_roots, &set_roots[i], 1);
-	}
-	(void)array_append_space(&all_set_roots);
-
-	/* read settings after registering storages so they can have their
-	   own setting definitions too */
-	memset(&set_input, 0, sizeof(set_input));
-	set_input.roots = array_idx_modifiable(&all_set_roots, 0);
-	set_input.dyn_parsers = mail_storage_get_dynamic_parsers();
-	set_input.preserve_home = preserve_home;
-	if (input != NULL) {
-		set_input.module = input->module;
-		set_input.service = input->service;
-		set_input.username = input->username;
-		set_input.local_ip = input->local_ip;
-		set_input.remote_ip = input->remote_ip;
-	}
-	if (master_service_settings_read(service, &set_input, &error) < 0)
-		i_fatal("Error reading configuration: %s", error);
-}
-
 static int
-mail_storage_service_init_post(struct master_service *service,
+mail_storage_service_init_post(struct mail_storage_service_ctx *ctx,
 			       const struct mail_storage_service_input *input,
 			       const char *home,
 			       const struct mail_user_settings *user_set,
-			       bool setuid_root,
-			       enum mail_storage_service_flags flags,
 			       struct mail_user **mail_user_r,
 			       const char **error_r)
 {
@@ -350,16 +304,15 @@
 
 	if (mail_set->mail_debug) {
 		i_debug("Effective uid=%s, gid=%s, home=%s",
-			dec2str(geteuid()), dec2str(getegid()),
-			home != NULL ? home : "(none)");
+			dec2str(geteuid()), dec2str(getegid()), home);
 	}
 
-	if (setuid_root) {
+	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP) != 0) {
 		/* we don't want to write core files to any users' home
 		   directories since they could contain information about other
 		   users' mails as well. so do no chdiring to home. */
 	} else if (*home != '\0' &&
-		   (flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
+		   (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR) == 0) {
 		/* If possible chdir to home directory, so that core file
 		   could be written in case we crash. */
 		if (chdir(home) < 0) {
@@ -372,7 +325,7 @@
 
 	mail_user = mail_user_alloc(input->username, user_set);
 	mail_user_set_home(mail_user, *home == '\0' ? NULL : home);
-	mail_user_set_vars(mail_user, geteuid(), service->name,
+	mail_user_set_vars(mail_user, geteuid(), ctx->service->name,
 			   &input->local_ip, &input->remote_ip);
 	if (mail_user_init(mail_user, error_r) < 0) {
 		mail_user_unref(&mail_user);
@@ -436,7 +389,7 @@
 
 static void
 mail_storage_service_init_log(struct master_service *service,
-			      struct mail_storage_service_input *input)
+			      struct mail_storage_service_user *user)
 {
 	const struct mail_user_settings *user_set;
 	void **sets;
@@ -448,8 +401,8 @@
 		string_t *str;
 
 		str = t_str_new(256);
-		var_expand(str, user_set->mail_log_prefix,
-			   get_var_expand_table(service, input));
+		var_expand(str, user->user_set->mail_log_prefix,
+			   get_var_expand_table(service, &user->input));
 		master_service_init_log(service, str_c(str));
 	} T_END;
 }
@@ -485,273 +438,181 @@
 		}
 	}
 }
-static struct mail_user *
-init_user_real(struct master_service *service,
-	       const struct mail_storage_service_input *_input,
-	       const struct setting_parser_info *set_roots[],
-	       enum mail_storage_service_flags flags)
+
+struct mail_storage_service_ctx *
+mail_storage_service_init(struct master_service *service,
+			  const struct setting_parser_info *set_roots[],
+			  enum mail_storage_service_flags flags)
 {
-	struct mail_storage_service_input input = *_input;
-	const struct master_service_settings *set;
-	const struct mail_user_settings *user_set;
-	const struct mail_storage_settings *mail_set;
-	struct mail_user *mail_user;
-	struct auth_master_connection *conn;
-	void **sets;
-	const char *user, *orig_user, *home, *chroot, *error;
-	const char *system_groups_user = NULL, *const *userdb_fields = NULL;
-	unsigned int len;
-	bool userdb_lookup;
-	pool_t userdb_pool = NULL;
+	struct mail_storage_service_ctx *ctx;
+	unsigned int count;
 
+	(void)umask(0077);
 	io_loop_set_time_moved_callback(current_ioloop,
 					mail_storage_service_time_moved);
 
-	userdb_lookup = (flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0;
-	mail_storage_service_init_settings(service, &input, set_roots,
-					   !userdb_lookup);
-
-	/* the SET_VARS changes we do to set_parser are in their expanded form.
-	   lib-master should have already called settings_parse_set_expanded()
-	   to make this happen, but do it here again just in case. */
-	settings_parse_set_expanded(service->set_parser, TRUE);
-
-	if ((flags & MAIL_STORAGE_SERVICE_FLAG_DEBUG) != 0)
-		set_keyval(service->set_parser, "mail_debug", "yes");
-
-	mail_storage_service_init_log(service, &input);
-	set = master_service_settings_get(service);
-	sets = master_service_settings_get_others(service);
-	user_set = sets[0];
-	mail_set = mail_user_set_get_storage_set(user_set);
-
-	if (userdb_lookup) {
-		/* userdb lookup may change settings, do it as soon as
-		   possible. */
-		orig_user = user = input.username;
-		conn = auth_master_init(user_set->auth_socket_path,
-					mail_set->mail_debug);
-		userdb_pool = pool_alloconly_create("userdb lookup", 1024);
-		if (service_auth_userdb_lookup(conn, service->name, &input,
-					       user_set, userdb_pool, &user,
-					       &userdb_fields, &error) <= 0)
-			i_fatal("%s", error);
-		auth_master_deinit(&conn);
-		input.username = user;
-
-		/* set up logging again in case username changed */
-		mail_storage_service_init_log(service, &input);
-	} else if (input.userdb_fields != NULL) {
-		userdb_fields = input.userdb_fields;
-		userdb_pool = pool_alloconly_create("userdb fields", 1024);
-	}
-	if (userdb_fields != NULL) {
-		struct auth_user_reply reply;
-
-		auth_user_fields_parse(userdb_fields, userdb_pool, &reply);
-		if (user_reply_handle(service->set_parser, user_set, &reply,
-				      &system_groups_user, &error) < 0)
-			i_fatal("%s", error);
-	}
-	if (userdb_pool != NULL)
-		pool_unref(&userdb_pool);
-
-	/* variable strings are expanded in mail_user_init(),
-	   but we need the home and chroot sooner so do them separately here. */
-	home = user_expand_varstr(service, &input, user_set->mail_home);
-	chroot = user_expand_varstr(service, &input, user_set->mail_chroot);
-
-	if (!userdb_lookup) {
-		if (*home == '\0' && getenv("HOME") != NULL) {
-			home = getenv("HOME");
-			set_keyval(service->set_parser, "mail_home", home);
-		}
-	}
-
-	if (*home != '/') {
-		i_fatal("user %s: Relative home directory paths not supported: "
-			"%s", input.username, home);
-
-	}
+        mail_storage_init();
+	mail_storage_register_all();
+	mailbox_list_register_all();
 
-	len = strlen(chroot);
-	if (len > 2 && strcmp(chroot + len - 2, "/.") == 0 &&
-	    strncmp(home, chroot, len - 2) == 0) {
-		/* If chroot ends with "/.", strip chroot dir from home dir */
-		home += len - 2;
-		if (*home == '\0')
-			home = "/";
-
-		set_keyval(service->set_parser, "mail_home", home);
-		chroot = t_strndup(chroot, len - 2);
-	}
-
-	modules = *user_set->mail_plugins == '\0' ? NULL :
-		module_dir_load(user_set->mail_plugin_dir,
-				user_set->mail_plugins, TRUE,
-				master_service_get_version_string(service));
-
-	if ((flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) != 0) {
-		/* no changes */
-	} else if ((flags & MAIL_STORAGE_SERVICE_FLAG_RESTRICT_BY_ENV) != 0) {
-		restrict_access_by_env(home,
-			(flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0);
-	} else {
-		service_drop_privileges(user_set, system_groups_user,
-			home, chroot,
-			(flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0,
-			FALSE);
-	}
-	/* privileges are now dropped */
-	restrict_access_allow_coredumps(TRUE);
-
-	dict_drivers_register_builtin();
-	module_dir_init(modules);
-	mail_users_init(user_set->auth_socket_path, mail_set->mail_debug);
-	if (mail_storage_service_init_post(service, &input, home, user_set,
-					   FALSE, flags,
-					   &mail_user, &error) < 0)
-		i_fatal("%s", error);
-	return mail_user;
-}
-
-struct mail_user *
-mail_storage_service_init_user(struct master_service *service,
-			       const struct mail_storage_service_input *_input,
-			       const struct setting_parser_info *set_roots[],
-			       enum mail_storage_service_flags flags)
-{
-	struct mail_user *user;
-
-	T_BEGIN {
-		user = init_user_real(service, _input, set_roots, flags);
-	} T_END;
-	return user;
-}
-
-void mail_storage_service_deinit_user(void)
-{
-	module_dir_unload(&modules);
-	mail_storage_deinit();
-	mail_users_deinit();
-	dict_drivers_unregister_builtin();
-}
-
-struct mail_storage_service_multi_ctx *
-mail_storage_service_multi_init(struct master_service *service,
-				const struct setting_parser_info *set_roots[],
-				enum mail_storage_service_flags flags)
-{
-	struct mail_storage_service_multi_ctx *ctx;
-	const struct master_service_settings *set;
-	const struct mail_user_settings *user_set;
-	const struct mail_storage_settings *mail_set;
-	void **sets;
-
-	io_loop_set_time_moved_callback(current_ioloop,
-					mail_storage_service_time_moved);
-
-	ctx = i_new(struct mail_storage_service_multi_ctx, 1);
+	ctx = i_new(struct mail_storage_service_ctx, 1);
 	ctx->service = service;
 	ctx->flags = flags;
 
-	mail_storage_service_init_settings(service, NULL, set_roots, FALSE);
-
-	set = master_service_settings_get(service);
-	sets = master_service_settings_get_others(service);
-	user_set = sets[0];
-	mail_set = mail_user_set_get_storage_set(user_set);
+	/* @UNSAFE */
+	if (set_roots == NULL)
+		count = 0;
+	else
+		for (count = 0; set_roots[count] != NULL; count++) ;
+	ctx->set_roots = i_new(const struct setting_parser_info *, count + 2);
+	ctx->set_roots[0] = &mail_user_setting_parser_info;
+	memcpy(ctx->set_roots + 1, set_roots, sizeof(*ctx->set_roots) * count);
 
 	/* do all the global initialization. delay initializing plugins until
 	   we drop privileges the first time. */
 	master_service_init_log(service, t_strconcat(service->name, ": ", NULL));
 
-	modules = *user_set->mail_plugins == '\0' ? NULL :
-		module_dir_load(user_set->mail_plugin_dir,
-				user_set->mail_plugins, TRUE,
-				master_service_get_version_string(service));
-
-	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) {
-		ctx->conn = auth_master_init(user_set->auth_socket_path,
-					     mail_set->mail_debug);
-	}
-
 	dict_drivers_register_builtin();
-	mail_users_init(user_set->auth_socket_path, mail_set->mail_debug);
 	return ctx;
 }
 
 struct auth_master_connection *
-mail_storage_service_multi_get_auth_conn(struct mail_storage_service_multi_ctx *ctx)
+mail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx)
 {
 	return ctx->conn;
 }
 
-static int multi_userdb_lookup(struct mail_storage_service_multi_ctx *ctx,
-			       struct mail_storage_service_multi_user *user,
-			       pool_t userdb_pool, const char **error_r)
+static int
+mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
+				   const struct mail_storage_service_input *input,
+				   bool preserve_home, const char **error_r)
 {
-	struct auth_user_reply reply;
-	const char *username, *system_groups_user, *const *userdb_fields;
-	int ret;
+	struct master_service_settings_input set_input;
 
-	username = user->input.username;
-	ret = service_auth_userdb_lookup(ctx->conn, ctx->service->name,
-					 &user->input, user->user_set,
-					 userdb_pool, &username,
-					 &userdb_fields, error_r);
-	if (ret <= 0)
-		return ret;
+	/* read settings after registering storages so they can have their
+	   own setting definitions too */
+	memset(&set_input, 0, sizeof(set_input));
+	set_input.roots = ctx->set_roots;
+	set_input.dyn_parsers = mail_storage_get_dynamic_parsers();
+	set_input.preserve_home = preserve_home;
+	if (input != NULL) {
+		set_input.module = input->module;
+		set_input.service = input->service;
+		set_input.username = input->username;
+		set_input.local_ip = input->local_ip;
+		set_input.remote_ip = input->remote_ip;
+	}
+	if (master_service_settings_read(ctx->service, &set_input,
+					 error_r) < 0) {
+		*error_r = t_strdup_printf("Error reading configuration: %s",
+					   *error_r);
+		return -1;
+	}
+	return 0;
+}
 
-	auth_user_fields_parse(userdb_fields, userdb_pool, &reply);
-	ret = user_reply_handle(user->set_parser, user->user_set,
-				&reply, &system_groups_user, error_r);
-	if (ret <= 0)
-		return ret;
+static void
+mail_storage_service_first_init(struct mail_storage_service_ctx *ctx,
+				const struct mail_user_settings *user_set)
+{
+	const struct mail_storage_settings *mail_set;
+
+	mail_set = mail_user_set_get_storage_set(user_set);
+	ctx->debug = mail_user_set_get_storage_set(user_set)->mail_debug;
 
-	user->input.username = p_strdup(user->pool, username);
-	user->system_groups_user = p_strdup(user->pool, system_groups_user);
-	return 1;
+	modules = *user_set->mail_plugins == '\0' ? NULL :
+		module_dir_load(user_set->mail_plugin_dir,
+				user_set->mail_plugins, TRUE,
+				master_service_get_version_string(ctx->service));
+
+	ctx->conn = auth_master_init(user_set->auth_socket_path,
+				     mail_set->mail_debug);
+
+	i_assert(mail_user_auth_master_conn == NULL);
+	mail_user_auth_master_conn = ctx->conn;
 }
 
-int mail_storage_service_multi_lookup(struct mail_storage_service_multi_ctx *ctx,
-				      const struct mail_storage_service_input *input,
-				      pool_t pool,
-				      struct mail_storage_service_multi_user **user_r,
-				      const char **error_r)
+int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
+				const struct mail_storage_service_input *input,
+				struct mail_storage_service_user **user_r,
+				const char **error_r)
 {
-	struct mail_storage_service_multi_user *user;
+	struct mail_storage_service_user *user;
+	const char *username = input->username;
+	const struct mail_user_settings *user_set;
+	const char *const *userdb_fields;
+	struct auth_user_reply reply;
 	void **sets;
-	pool_t userdb_pool;
+	pool_t user_pool, temp_pool;
+	bool keep_home;
 	int ret = 1;
 
-	user = p_new(pool, struct mail_storage_service_multi_user, 1);
+	/* settings reader may exec doveconf, which is going to clear
+	   environment, and if we're not doing a userdb lookup we want to
+	   use $HOME */
+	keep_home = (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) == 0;
+	if (mail_storage_service_read_settings(ctx, input, keep_home,
+					       error_r) < 0)
+		return -1;
+	sets = settings_parser_get_list(ctx->service->set_parser);
+	user_set = sets[1];
+
+	if (ctx->conn == NULL)
+		mail_storage_service_first_init(ctx, user_set);
+
+	temp_pool = pool_alloconly_create("userdb lookup", 1024);
+	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) {
+		ret = service_auth_userdb_lookup(ctx, input, temp_pool,
+						 &username, &userdb_fields,
+						 error_r);
+		if (ret <= 0) {
+			pool_unref(&temp_pool);
+			return ret;
+		}
+	} else {
+		userdb_fields = input->userdb_fields;
+	}
+
+	user_pool = pool_alloconly_create("mail storage service user", 1024*3);
+	user = p_new(user_pool, struct mail_storage_service_user, 1);
 	memset(user_r, 0, sizeof(user_r));
-	user->pool = pool;
+	user->pool = user_pool;
 	user->input = *input;
-	user->input.username = p_strdup(pool, input->username);
+	user->input.userdb_fields = NULL;
+	user->input.username = p_strdup(user_pool, username);
 
-	user->set_parser = settings_parser_dup(ctx->service->set_parser, pool);
+	user->set_parser =
+		settings_parser_dup(ctx->service->set_parser, user_pool);
 	sets = settings_parser_get_list(user->set_parser);
 	user->user_set = sets[1];
 
-	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) {
-		userdb_pool = pool_alloconly_create("userdb lookup", 1024);
-		ret = multi_userdb_lookup(ctx, user, userdb_pool, error_r);
-		pool_unref(&userdb_pool);
+	if (keep_home) {
+		const char *home = getenv("HOME");
+		if (home != NULL)
+			set_keyval(user->set_parser, "mail_home", home);
 	}
+
+	if (userdb_fields != NULL) {
+		auth_user_fields_parse(userdb_fields, temp_pool, &reply);
+		if (user_reply_handle(user, &reply, error_r) < 0)
+			ret = -1;
+	}
+	pool_unref(&temp_pool);
+
 	*user_r = user;
-	return 1;
+	return ret;
 }
 
-int mail_storage_service_multi_next(struct mail_storage_service_multi_ctx *ctx,
-				    struct mail_storage_service_multi_user *user,
-				    struct mail_user **mail_user_r,
-				    const char **error_r)
+int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
+			      struct mail_storage_service_user *user,
+			      struct mail_user **mail_user_r,
+			      const char **error_r)
 {
 	const struct mail_user_settings *user_set = user->user_set;
 	const char *home, *chroot;
 	unsigned int len;
+	bool temp_priv_drop =
+		(ctx->flags & MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP);
 
 	/* variable strings are expanded in mail_user_init(),
 	   but we need the home and chroot sooner so do them separately here. */
@@ -760,13 +621,21 @@
 	chroot = user_expand_varstr(ctx->service, &user->input,
 				    user_set->mail_chroot);
 
-	mail_storage_service_init_log(ctx->service, &user->input);
+	if (*home != '/' && *home != '\0') {
+		i_error("user %s: Relative home directory paths not supported: "
+			"%s", user->input.username, home);
+		return -1;
+	}
+
+	mail_storage_service_init_log(ctx->service, user);
 
 	if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS) == 0) {
 		service_drop_privileges(user_set, user->system_groups_user,
 			home, chroot,
 			(ctx->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0,
-			TRUE);
+			temp_priv_drop);
+		if (!temp_priv_drop)
+			restrict_access_allow_coredumps(TRUE);
 	}
 	if (!ctx->modules_initialized) {
 		/* privileges dropped for the first time. initialize the
@@ -781,24 +650,59 @@
 	if (len > 2 && strcmp(chroot + len - 2, "/.") == 0 &&
 	    strncmp(home, chroot, len - 2) == 0) {
 		/* home dir already contains the chroot dir */
-	} else if (len > 0) {
+		if (!temp_priv_drop) {
+			home += len - 2;
+			if (*home == '\0')
+				home = "/";
+
+			set_keyval(user->set_parser, "mail_home", home);
+			chroot = t_strndup(chroot, len - 2);
+		}
+	} else if (len > 0 && temp_priv_drop) {
 		set_keyval(user->set_parser, "mail_home",
 			t_strconcat(chroot, "/", home, NULL));
 	}
-	if (mail_storage_service_init_post(ctx->service, &user->input,
-					   home, user_set, TRUE, ctx->flags,
+	if (mail_storage_service_init_post(ctx, &user->input, home, user_set,
 					   mail_user_r, error_r) < 0)
 		return -1;
 	return 0;
 }
 
-void mail_storage_service_multi_user_free(struct mail_storage_service_multi_user *user)
+int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
+				     const struct mail_storage_service_input *input,
+				     struct mail_storage_service_user **user_r,
+				     struct mail_user **mail_user_r,
+				     const char **error_r)
 {
+	struct mail_storage_service_user *user;
+	const char *error;
+	int ret;
+
+	ret = mail_storage_service_lookup(ctx, input, &user, &error);
+	if (ret <= 0) {
+		*error_r = t_strdup_printf("User lookup failed: %s", error);
+		return ret;
+	}
+	if (mail_storage_service_next(ctx, user, mail_user_r, &error) < 0) {
+		mail_storage_service_user_free(&user);
+		*error_r = t_strdup_printf("User init failed: %s", error);
+		return -1;
+	}
+	*user_r = user;
+	return 1;
+}
+
+void mail_storage_service_user_free(struct mail_storage_service_user **_user)
+{
+	struct mail_storage_service_user *user = *_user;
+
+	*_user = NULL;
 	settings_parser_deinit(&user->set_parser);
+	pool_unref(&user->pool);
 }
 
 unsigned int
-mail_storage_service_multi_all_init(struct mail_storage_service_multi_ctx *ctx)
+mail_storage_service_all_init(struct mail_storage_service_ctx *ctx)
 {
 	if (ctx->auth_list != NULL)
 		(void)auth_master_user_list_deinit(&ctx->auth_list);
@@ -806,8 +710,8 @@
 	return auth_master_user_list_count(ctx->auth_list);
 }
 
-int mail_storage_service_multi_all_next(struct mail_storage_service_multi_ctx *ctx,
-					const char **username_r)
+int mail_storage_service_all_next(struct mail_storage_service_ctx *ctx,
+				  const char **username_r)
 {
 	i_assert((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0);
 
@@ -817,20 +721,26 @@
 	return auth_master_user_list_deinit(&ctx->auth_list);
 }
 
-void mail_storage_service_multi_deinit(struct mail_storage_service_multi_ctx **_ctx)
+void mail_storage_service_deinit(struct mail_storage_service_ctx **_ctx)
 {
-	struct mail_storage_service_multi_ctx *ctx = *_ctx;
+	struct mail_storage_service_ctx *ctx = *_ctx;
 
 	*_ctx = NULL;
 	if (ctx->auth_list != NULL)
 		(void)auth_master_user_list_deinit(&ctx->auth_list);
-	if (ctx->conn != NULL)
+	if (ctx->conn != NULL) {
+		if (mail_user_auth_master_conn == ctx->conn)
+			mail_user_auth_master_conn = NULL;
 		auth_master_deinit(&ctx->conn);
+	}
 	i_free(ctx);
-	mail_storage_service_deinit_user();
+
+	module_dir_unload(&modules);
+	mail_storage_deinit();
+	dict_drivers_unregister_builtin();
 }
 
-void *mail_storage_service_multi_user_get_set(struct mail_storage_service_multi_user *user)
+void **mail_storage_service_user_get_set(struct mail_storage_service_user *user)
 {
 	return settings_parser_get_list(user->set_parser) + 1;
 }
--- a/src/lib-storage/mail-storage-service.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lib-storage/mail-storage-service.h	Wed Oct 21 19:54:00 2009 -0400
@@ -4,6 +4,7 @@
 #include "network.h"
 
 struct master_service;
+struct mail_user;
 
 enum mail_storage_service_flags {
 	/* Fail if we don't drop root privileges */
@@ -14,10 +15,10 @@
 	MAIL_STORAGE_SERVICE_FLAG_DEBUG			= 0x04,
 	/* Keep the current process permissions */
 	MAIL_STORAGE_SERVICE_FLAG_NO_RESTRICT_ACCESS	= 0x08,
-	/* Get the process permissions from environment */
-	MAIL_STORAGE_SERVICE_FLAG_RESTRICT_BY_ENV	= 0x10,
 	/* Don't chdir() to user's home */
-	MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR		= 0x20
+	MAIL_STORAGE_SERVICE_FLAG_NO_CHDIR		= 0x10,
+	/* Drop privileges only temporarily (keep running as setuid-root) */
+	MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP	= 0x20
 };
 
 struct mail_storage_service_input {
@@ -30,44 +31,42 @@
 };
 
 struct setting_parser_info;
-struct mail_storage_service_multi_user;
-
-struct mail_user *
-mail_storage_service_init_user(struct master_service *service,
-			       const struct mail_storage_service_input *input,
-			       const struct setting_parser_info *set_roots[],
-			       enum mail_storage_service_flags flags);
-void mail_storage_service_deinit_user(void);
+struct mail_storage_service_user;
 
-struct mail_storage_service_multi_ctx *
-mail_storage_service_multi_init(struct master_service *service,
-				const struct setting_parser_info *set_roots[],
-				enum mail_storage_service_flags flags);
+struct mail_storage_service_ctx *
+mail_storage_service_init(struct master_service *service,
+			  const struct setting_parser_info *set_roots[],
+			  enum mail_storage_service_flags flags);
 struct auth_master_connection *
-mail_storage_service_multi_get_auth_conn(struct mail_storage_service_multi_ctx *ctx);
+mail_storage_service_get_auth_conn(struct mail_storage_service_ctx *ctx);
 /* Returns 1 if ok, 0 if user wasn't found, -1 if error. */
-int mail_storage_service_multi_lookup(struct mail_storage_service_multi_ctx *ctx,
-				      const struct mail_storage_service_input *input,
-				      pool_t pool,
-				      struct mail_storage_service_multi_user **user_r,
-				      const char **error_r);
-int mail_storage_service_multi_next(struct mail_storage_service_multi_ctx *ctx,
-				    struct mail_storage_service_multi_user *user,
-				    struct mail_user **mail_user_r,
-				    const char **error_r);
-void mail_storage_service_multi_user_free(struct mail_storage_service_multi_user *user);
+int mail_storage_service_lookup(struct mail_storage_service_ctx *ctx,
+				const struct mail_storage_service_input *input,
+				struct mail_storage_service_user **user_r,
+				const char **error_r);
+int mail_storage_service_next(struct mail_storage_service_ctx *ctx,
+			      struct mail_storage_service_user *user,
+			      struct mail_user **mail_user_r,
+			      const char **error_r);
+/* Combine lookup() and next() into one call. */
+int mail_storage_service_lookup_next(struct mail_storage_service_ctx *ctx,
+				     const struct mail_storage_service_input *input,
+				     struct mail_storage_service_user **user_r,
+				     struct mail_user **mail_user_r,
+				     const char **error_r);
+void mail_storage_service_user_free(struct mail_storage_service_user **user);
 /* Initialize iterating through all users. Return the number of users. */
 unsigned int
-mail_storage_service_multi_all_init(struct mail_storage_service_multi_ctx *ctx);
+mail_storage_service_all_init(struct mail_storage_service_ctx *ctx);
 /* Iterate through all usernames. Returns 1 if username was returned, 0 if
    there are no more users, -1 if error. */
-int mail_storage_service_multi_all_next(struct mail_storage_service_multi_ctx *ctx,
-					const char **username_r);
-void mail_storage_service_multi_deinit(struct mail_storage_service_multi_ctx **ctx);
+int mail_storage_service_all_next(struct mail_storage_service_ctx *ctx,
+				  const char **username_r);
+void mail_storage_service_deinit(struct mail_storage_service_ctx **ctx);
 
 /* Return the settings pointed to by set_root parameter in _init().
    The settings contain all the changes done by userdb lookups. */
-void *mail_storage_service_multi_user_get_set(struct mail_storage_service_multi_user *user);
+void **mail_storage_service_user_get_set(struct mail_storage_service_user *user);
 
 /* Return the settings pointed to by set_root parameter in _init() */
 void *mail_storage_service_get_settings(struct master_service *service);
--- a/src/lib-storage/mail-user.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lib-storage/mail-user.c	Wed Oct 21 19:54:00 2009 -0400
@@ -19,9 +19,9 @@
 #include <stdlib.h>
 
 struct mail_user_module_register mail_user_module_register = { 0 };
-void (*hook_mail_user_created)(struct mail_user *user) = NULL;
+struct auth_master_connection *mail_user_auth_master_conn;
 
-static struct auth_master_connection *auth_master_conn;
+void (*hook_mail_user_created)(struct mail_user *user) = NULL;
 
 static void mail_user_deinit_base(struct mail_user *user)
 {
@@ -259,12 +259,13 @@
 		return user->_home != NULL ? 1 : 0;
 	}
 
-	if (auth_master_conn == NULL)
+	if (mail_user_auth_master_conn == NULL)
 		return 0;
 
 	userdb_pool = pool_alloconly_create("userdb lookup", 512);
-	ret = auth_master_user_lookup(auth_master_conn, user->username,
-				      &info, userdb_pool, &username, &fields);
+	ret = auth_master_user_lookup(mail_user_auth_master_conn,
+				      user->username, &info, userdb_pool,
+				      &username, &fields);
 	if (ret < 0)
 		*home_r = NULL;
 	else {
@@ -347,15 +348,3 @@
 	return t_strconcat(net_ip2addr(user->remote_ip), "/",
 			   str_tabescape(user->username), NULL);
 }
-
-void mail_users_init(const char *auth_socket_path, bool debug)
-{
-	auth_master_conn = auth_socket_path == NULL ? NULL :
-		auth_master_init(auth_socket_path, debug);
-}
-
-void mail_users_deinit(void)
-{
-	if (auth_master_conn != NULL)
-		auth_master_deinit(&auth_master_conn);
-}
--- a/src/lib-storage/mail-user.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lib-storage/mail-user.h	Wed Oct 21 19:54:00 2009 -0400
@@ -53,13 +53,11 @@
 	struct mail_user_module_register *reg;
 };
 extern struct mail_user_module_register mail_user_module_register;
+extern struct auth_master_connection *mail_user_auth_master_conn;
 
 /* Called after user has been created */
 extern void (*hook_mail_user_created)(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_alloc(const char *username,
 				  const struct mail_user_settings *set);
 /* Returns -1 if settings were invalid. */
--- a/src/lmtp/client.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lmtp/client.c	Wed Oct 21 19:54:00 2009 -0400
@@ -1,7 +1,7 @@
 /* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
-#include "buffer.h"
+#include "array.h"
 #include "str.h"
 #include "llist.h"
 #include "istream.h"
@@ -11,6 +11,7 @@
 #include "master-service-settings.h"
 #include "mail-namespace.h"
 #include "mail-storage.h"
+#include "mail-storage-service.h"
 #include "main.h"
 #include "lmtp-proxy.h"
 #include "commands.h"
@@ -228,6 +229,11 @@
 
 void client_state_reset(struct client *client)
 {
+	struct mail_recipient *rcpt;
+
+	array_foreach_modifiable(&client->state.rcpt_to, rcpt)
+		mail_storage_service_user_free(&rcpt->service_user);
+
 	if (client->state.raw_mail != NULL)
 		mail_free(&client->state.raw_mail);
 	if (client->state.raw_trans != NULL)
--- a/src/lmtp/client.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lmtp/client.h	Wed Oct 21 19:54:00 2009 -0400
@@ -7,7 +7,7 @@
 
 struct mail_recipient {
 	const char *name;
-	struct mail_storage_service_multi_user *multi_user;
+	struct mail_storage_service_user *service_user;
 };
 
 struct client_state {
--- a/src/lmtp/commands.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lmtp/commands.c	Wed Oct 21 19:54:00 2009 -0400
@@ -175,7 +175,7 @@
 	info.remote_port = client->remote_port;
 
 	pool = pool_alloconly_create("auth lookup", 1024);
-	auth_conn = mail_storage_service_multi_get_auth_conn(multi_service);
+	auth_conn = mail_storage_service_get_auth_conn(storage_service);
 	ret = auth_master_pass_lookup(auth_conn, address, &info,
 				      pool, &fields);
 	if (ret <= 0) {
@@ -312,9 +312,8 @@
 	input.local_ip = client->local_ip;
 	input.remote_ip = client->remote_ip;
 
-	ret = mail_storage_service_multi_lookup(multi_service, &input,
-						client->state_pool,
-						&rcpt.multi_user, &error);
+	ret = mail_storage_service_lookup(storage_service, &input,
+					  &rcpt.service_user, &error);
 
 	if (ret < 0) {
 		i_error("User lookup failed: %s", error);
@@ -371,14 +370,14 @@
 	int ret;
 
 	i_set_failure_prefix(t_strdup_printf("lmtp(%s): ", rcpt->name));
-	if (mail_storage_service_multi_next(multi_service, rcpt->multi_user,
-					    &client->state.dest_user,
-					    &error) < 0) {
+	if (mail_storage_service_next(storage_service, rcpt->service_user,
+				      &client->state.dest_user,
+				      &error) < 0) {
 		i_error("%s", error);
 		client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL, rcpt->name);
 		return -1;
 	}
-	sets = mail_storage_service_multi_user_get_set(rcpt->multi_user);
+	sets = mail_storage_service_user_get_set(rcpt->service_user);
 
 	memset(&dctx, 0, sizeof(dctx));
 	dctx.pool = pool_alloconly_create("mail delivery", 1024);
--- a/src/lmtp/main.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lmtp/main.c	Wed Oct 21 19:54:00 2009 -0400
@@ -22,7 +22,7 @@
 #define IS_STANDALONE() \
         (getenv(MASTER_UID_ENV) == NULL)
 
-struct mail_storage_service_multi_ctx *multi_service;
+struct mail_storage_service_ctx *storage_service;
 
 static void client_connected(const struct master_service_connection *conn)
 {
@@ -74,16 +74,15 @@
 		return FATAL_DEFAULT;
 	master_service_init_finish(master_service);
 
-	multi_service = mail_storage_service_multi_init(master_service,
-							set_roots,
-							storage_service_flags);
+	storage_service = mail_storage_service_init(master_service, set_roots,
+						    storage_service_flags);
 	restrict_access_allow_coredumps(TRUE);
 
 	main_init();
 	master_service_run(master_service, client_connected);
 
 	main_deinit();
-	mail_storage_service_multi_deinit(&multi_service);
+	mail_storage_service_deinit(&storage_service);
 	master_service_deinit(&master_service);
 	return 0;
 }
--- a/src/lmtp/main.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/lmtp/main.h	Wed Oct 21 19:54:00 2009 -0400
@@ -1,7 +1,7 @@
 #ifndef MAIN_H
 #define MAIN_H
 
-extern struct mail_storage_service_multi_ctx *multi_service;
+extern struct mail_storage_service_ctx *storage_service;
 
 void listener_client_destroyed(void);
 
--- a/src/plugins/convert/convert-tool.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/plugins/convert/convert-tool.c	Wed Oct 21 19:54:00 2009 -0400
@@ -17,6 +17,8 @@
 
 int main(int argc, char *argv[])
 {
+	struct mail_storage_service_ctx *storage_service;
+	struct mail_storage_service_user *service_user;
 	struct mail_storage_service_input input;
 	struct mail_user *user;
 	struct convert_plugin_settings set;
@@ -53,7 +55,10 @@
 
 	master_service_init_log(master_service,
 		t_strdup_printf("convert-tool(%s): ", input.username));
-	user = mail_storage_service_init_user(master_service, &input, NULL, 0);
+	storage_service = mail_storage_service_init(master_service, NULL, 0);
+	if (mail_storage_service_lookup_next(storage_service, &input,
+					     &service_user, &user, &error) <= 0)
+		i_fatal("%s", error);
 
 	memset(&ns_set, 0, sizeof(ns_set));
 	ns_set.location = argv[4];
@@ -75,7 +80,8 @@
 		i_error("Internal failure");
 
 	mail_user_unref(&user);
-	mail_storage_service_deinit_user();
+	mail_storage_service_user_free(&service_user);
+	mail_storage_service_deinit(&storage_service);
 	master_service_deinit(&master_service);
 	return ret <= 0 ? 1 : 0;
 }
--- a/src/plugins/expire/expire-tool.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/plugins/expire/expire-tool.c	Wed Oct 21 19:54:00 2009 -0400
@@ -18,8 +18,8 @@
 #include <time.h>
 
 struct expire_context {
-	pool_t multi_user_pool;
-	struct mail_storage_service_multi_ctx *multi;
+	struct mail_storage_service_ctx *storage_service;
+	struct mail_storage_service_user *service_user;
 	struct mail_user *mail_user;
 	struct expire_env *env;
 	bool testrun;
@@ -28,7 +28,6 @@
 static int expire_init_user(struct expire_context *ctx, const char *user)
 {
 	struct mail_storage_service_input input;
-	struct mail_storage_service_multi_user *multi_user;
 	const char *expire, *expire_altmove, *errstr;
 	int ret;
 
@@ -38,19 +37,12 @@
 	input.service = "expire-tool";
 	input.username = user;
 
-	p_clear(ctx->multi_user_pool);
-	ret = mail_storage_service_multi_lookup(ctx->multi, &input,
-						ctx->multi_user_pool,
-						&multi_user, &errstr);
+	ret = mail_storage_service_lookup_next(ctx->storage_service, &input,
+					       &ctx->service_user,
+					       &ctx->mail_user, &errstr);
 	if (ret <= 0) {
 		if (ret < 0 || ctx->testrun)
-			i_error("User lookup failed: %s", errstr);
-		return ret;
-	}
-	ret = mail_storage_service_multi_next(ctx->multi, multi_user,
-					      &ctx->mail_user, &errstr);
-	if (ret < 0) {
-		i_error("User init failed: %s", errstr);
+			i_error("%s", errstr);
 		return ret;
 	}
 
@@ -68,6 +60,7 @@
 static void expire_deinit_user(struct expire_context *ctx)
 {
 	mail_user_unref(&ctx->mail_user);
+	mail_storage_service_user_free(&ctx->service_user);
 	expire_env_deinit(&ctx->env);
 }
 
@@ -214,8 +207,7 @@
 	int ret;
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.multi_user_pool = pool_alloconly_create("multi user pool", 512);
-	ctx.multi = mail_storage_service_multi_init(service, NULL,
+	ctx.storage_service = mail_storage_service_init(service, NULL,
 				MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP);
 
 	sets = master_service_settings_get_others(service);
@@ -306,8 +298,7 @@
 
 	if (ctx.mail_user != NULL)
 		expire_deinit_user(&ctx);
-	mail_storage_service_multi_deinit(&ctx.multi);
-	pool_unref(&ctx.multi_user_pool);
+	mail_storage_service_deinit(&ctx.storage_service);
 }
 
 int main(int argc, char *argv[])
--- a/src/pop3/main.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/pop3/main.c	Wed Oct 21 19:54:00 2009 -0400
@@ -20,13 +20,8 @@
 #define IS_STANDALONE() \
         (getenv(MASTER_UID_ENV) == NULL)
 
-static const struct setting_parser_info *set_roots[] = {
-	&pop3_setting_parser_info,
-	NULL
-};
+static struct mail_storage_service_ctx *storage_service;
 static struct master_login *master_login = NULL;
-static enum mail_storage_service_flags storage_service_flags = 0;
-static bool user_initialized = FALSE;
 
 void (*hook_client_created)(struct client **client) = NULL;
 
@@ -50,7 +45,9 @@
 }
 
 static void
-main_stdio_init_user(const struct pop3_settings *set, struct mail_user *user)
+main_stdio_init_user(const struct pop3_settings *set,
+		     struct mail_user *mail_user,
+		     struct mail_storage_service_user *user)
 {
 	struct client *client;
 	buffer_t *input_buf;
@@ -60,7 +57,8 @@
 	input_buf = input_base64 == NULL ? NULL :
 		t_base64_decode_str(input_base64);
 
-	client = client_create(STDIN_FILENO, STDOUT_FILENO, user, set);
+	client = client_create(STDIN_FILENO, STDOUT_FILENO,
+			       mail_user, user, set);
 	client_add_input(client, input_buf);
 }
 
@@ -70,6 +68,10 @@
 	struct mail_user *mail_user;
 	const struct pop3_settings *set;
 	const char *value;
+	struct mail_storage_service_user *user;
+	const char *error;
+	pool_t user_pool;
+	int ret;
 
 	memset(&input, 0, sizeof(input));
 	input.module = input.service = "pop3";
@@ -83,11 +85,16 @@
 	if ((value = getenv("LOCAL_IP")) != NULL)
 		net_addr2ip(value, &input.local_ip);
 
-	user_initialized = TRUE;
-	mail_user = mail_storage_service_init_user(master_service,
-						   &input, set_roots,
-						   storage_service_flags);
-	set = mail_storage_service_get_settings(master_service);
+	user_pool = pool_alloconly_create("storage user pool", 512);
+	ret = mail_storage_service_lookup(storage_service, &input,
+					  &user, &error);
+	if (ret <= 0)
+		i_fatal("User lookup failed: %s", error);
+	if (mail_storage_service_next(storage_service,
+				      user, &mail_user, &error) < 0)
+		i_fatal("User init failed: %s", error);
+	set = mail_storage_service_user_get_set(user)[1];
+
 	restrict_access_allow_coredumps(TRUE);
 	if (set->shutdown_clients)
 		master_service_set_die_with_master(master_service, TRUE);
@@ -95,7 +102,7 @@
 	/* fake that we're running, so we know if client was destroyed
 	   while handling its initial input */
 	io_loop_set_running(current_ioloop);
-	main_stdio_init_user(set, mail_user);
+	main_stdio_init_user(set, mail_user, user);
 }
 
 static void
@@ -103,9 +110,11 @@
 		       const char *username, const char *const *extra_fields)
 {
 	struct mail_storage_service_input input;
+	struct mail_storage_service_user *user;
 	struct mail_user *mail_user;
 	struct client *pop3_client;
 	const struct pop3_settings *set;
+	const char *error;
 	buffer_t input_buf;
 
 	if (pop3_clients != NULL) {
@@ -113,7 +122,6 @@
 		(void)close(client->fd);
 		return;
 	}
-	i_assert(!user_initialized);
 
 	memset(&input, 0, sizeof(input));
 	input.module = input.service = "pop3";
@@ -127,13 +135,13 @@
 		(void)close(client->fd);
 		return;
 	}
-	user_initialized = TRUE;
 	master_login_deinit(&master_login);
 
-	mail_user = mail_storage_service_init_user(master_service,
-						   &input, set_roots,
-						   storage_service_flags);
-	set = mail_storage_service_get_settings(master_service);
+	if (mail_storage_service_lookup_next(storage_service, &input,
+					     &user, &mail_user, &error) <= 0)
+		i_fatal("%s", error);
+	set = mail_storage_service_user_get_set(user)[1];
+
 	restrict_access_allow_coredumps(TRUE);
 	if (set->shutdown_clients)
 		master_service_set_die_with_master(master_service, TRUE);
@@ -144,7 +152,8 @@
 
 	buffer_create_const_data(&input_buf, client->data,
 				 client->auth_req.data_size);
-	pop3_client = client_create(client->fd, client->fd, mail_user, set);
+	pop3_client = client_create(client->fd, client->fd, mail_user,
+				    user, set);
 	T_BEGIN {
 		client_add_input(pop3_client, &input_buf);
 	} T_END;
@@ -162,7 +171,12 @@
 
 int main(int argc, char *argv[])
 {
+	static const struct setting_parser_info *set_roots[] = {
+		&pop3_setting_parser_info,
+		NULL
+	};
 	enum master_service_flags service_flags = 0;
+	enum mail_storage_service_flags storage_service_flags = 0;
 
 	if (IS_STANDALONE() && getuid() == 0 &&
 	    net_getpeername(1, NULL, NULL) == 0) {
@@ -185,6 +199,10 @@
 		return FATAL_DEFAULT;
 	master_service_init_finish(master_service);
 
+	storage_service =
+		mail_storage_service_init(master_service,
+					  set_roots, storage_service_flags);
+
 	if (IS_STANDALONE()) {
 		T_BEGIN {
 			main_stdio_run();
@@ -201,8 +219,7 @@
 
 	if (master_login != NULL)
 		master_login_deinit(&master_login);
-	if (user_initialized)
-		mail_storage_service_deinit_user();
+	mail_storage_service_deinit(&storage_service);
 	master_service_deinit(&master_service);
 	return 0;
 }
--- a/src/pop3/pop3-client.c	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/pop3/pop3-client.c	Wed Oct 21 19:54:00 2009 -0400
@@ -12,6 +12,7 @@
 #include "var-expand.h"
 #include "master-service.h"
 #include "mail-storage.h"
+#include "mail-storage-service.h"
 #include "pop3-commands.h"
 #include "mail-search-build.h"
 #include "mail-namespace.h"
@@ -182,6 +183,7 @@
 }
 
 struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+			     struct mail_storage_service_user *service_user,
 			     const struct pop3_settings *set)
 {
 	struct mail_namespace *ns;
@@ -197,6 +199,7 @@
 	net_set_nonblock(fd_out, TRUE);
 
 	client = i_new(struct client, 1);
+	client->service_user = service_user;
 	client->set = set;
 	client->fd_in = fd_in;
 	client->fd_out = fd_out;
@@ -368,7 +371,7 @@
 		if (close(client->fd_out) < 0)
 			i_error("close(client out) failed: %m");
 	}
-
+	mail_storage_service_user_free(&client->service_user);
 	i_free(client);
 
 	master_service_client_connection_destroyed(master_service);
--- a/src/pop3/pop3-client.h	Wed Oct 21 16:58:10 2009 -0400
+++ b/src/pop3/pop3-client.h	Wed Oct 21 19:54:00 2009 -0400
@@ -21,6 +21,7 @@
 	command_func_t *cmd;
 	void *cmd_context;
 
+	struct mail_storage_service_user *service_user;
 	struct mail_user *user;
 	struct mail_namespace *inbox_ns;
 	struct mailbox *mailbox;
@@ -65,6 +66,7 @@
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
 struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+			     struct mail_storage_service_user *service_user,
 			     const struct pop3_settings *set);
 void client_destroy(struct client *client, const char *reason);