changeset 1055:a72bba3f8a55 HEAD

Rewrote setting handling. Changed some existing settings also since POP3 support required changes anyway. POP3 seems to be really working now :)
author Timo Sirainen <tss@iki.fi>
date Thu, 30 Jan 2003 19:59:31 +0200
parents cd1ac4101adf
children a9b499b2611e
files dovecot-example.conf src/imap/main.c src/login-common/main.c src/master/.cvsignore src/master/Makefile.am src/master/auth-process.c src/master/common.h src/master/imap-process.c src/master/imap-process.h src/master/login-process.c src/master/mail-process.c src/master/mail-process.h src/master/main.c src/master/master-login-interface.h src/master/settings.c src/master/settings.h src/master/ssl-init.c
diffstat 17 files changed, 1093 insertions(+), 846 deletions(-) [+]
line wrap: on
line diff
--- a/dovecot-example.conf	Thu Jan 30 19:56:19 2003 +0200
+++ b/dovecot-example.conf	Thu Jan 30 19:59:31 2003 +0200
@@ -9,32 +9,32 @@
 # Base directory where to store runtime data.
 #base_dir = /var/run/dovecot/
 
-# Port to listen in for IMAP connections. This port is used for TLS
-# connections as well. Setting it to 0 disables it.
-#imap_port = 143
+# Protocols we want to be serving:
+#  imap imaps pop3 pop3s
+#protocols = imap imaps
 
-# Port to listen in for SSL IMAP connections. Setting it to 0 disables it.
-#imaps_port = 993
-
-# IP or host address where to listen in for IMAP connections. It's not
+# IP or host address where to listen in for connections. It's not currently
 # possible to specify multiple addresses. "*" listens in all IPv4 interfaces.
-# "::" listens in all IPv6 interfaces, but may also listen in all IPv4
-# interfaces depending on the operating system.
+# "[::]" listens in all IPv6 interfaces, but may also listen in all IPv4
+# interfaces depending on the operating system. You can specify ports with
+# "host:port".
 #imap_listen = *
+#pop3_listen = *
 
-# IP or host address where to listen in for SSL IMAP connections. Defaults
-# to imap_listen if not specified.
+# IP or host address where to listen in for SSL connections. Defaults
+# to above non-SSL equilevants if not specified.
 #imaps_listen = 
+#pop3s_listen = 
 
-# Disable SSL support.
+# Disable SSL/TLS support.
 #ssl_disable = no
 
 # PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
 # dropping root privileges, so keep the key file unreadable by anyone but
 # root. Included doc/mkcert.sh can be used to easily generate self-signed
 # certificate, just make sure to update the domains in dovecot-openssl.cnf
-#ssl_cert_file = /etc/ssl/certs/imapd.pem
-#ssl_key_file = /etc/ssl/private/imapd.pem
+#ssl_cert_file = /etc/ssl/certs/dovecot.pem
+#ssl_key_file = /etc/ssl/private/dovecot.pem
 
 # SSL parameter file. Master process generates this file for login processes.
 # It contains Diffie Hellman and RSA parameters.
@@ -60,37 +60,44 @@
 #log_timestamp = %b %d %H:%M:%S 
 
 ##
-## Login process
+## Login processes
 ##
 
+# Directory where authentication process places authentication UNIX sockets
+# which login needs to be able to connect to. The sockets are created when
+# running as root, so you don't have to worry about permissions.
+#login_dir = /var/run/dovecot/login
+
+# chroot login process to the login_dir. Only reason not to do this is if you
+# wish to run the whole Dovecot without roots.
+#login_chroot = yes
+
+
+##
+## IMAP login process
+##
+
+login = imap
+
 # Executable location.
 #login_executable = /usr/libexec/dovecot/imap-login
 
-# User to use for imap-login process. The user must belong to a group
-# where only it has access, it's used to control access for authentication
-# process named sockets.
-#login_user = imapd
+# User to use for the login process. The user must belong to a group where
+# only it has access, it's used to control access for authentication process
+# named sockets.
+#login_user = dovecot
 
 # Set max. process size in megabytes. If you don't use
 # login_process_per_connection you might need to grow this.
 #login_process_size = 16
 
-# Directory where imap-auth places authentication UNIX sockets which login
-# needs to be able to connect to. The sockets are created when running as
-# root, so you don't need to give imap-auth any access for it.
-#login_dir = /var/run/dovecot/login
-
-# chroot imap-login process to the login_dir. Only reason not to do this
-# is if you wish to run the whole imapd without roots.
-#login_chroot = yes
-
 # Should each login be processed in it's own process (yes), or should one
 # login process be allowed to process multiple connections (no)? Yes is more
 # secure, espcially with SSL/TLS enabled. No is faster since there's no need
 # to create processes all the time.
 #login_process_per_connection = yes
 
-# Number of imap-login processes to create. If login_process_per_user is
+# Number of login processes to create. If login_process_per_user is
 # yes, this is the number of extra processes waiting for users to log in.
 #login_processes_count = 3
 
@@ -109,27 +116,32 @@
 #max_logging_users = 256
 
 ##
-## IMAP process
+## POP3 login process
 ##
 
-# Executable location
-#imap_executable = /usr/libexec/dovecot/imap
+# Settings default to same as above, so you don't have to set anything
+# unless you want to override them.
+
+login = pop3
+
+# Exception to above rule being the executable location.
+#login_executable = /usr/libexec/dovecot/pop3-login
 
-# Set max. process size in megabytes. Most of the memory goes to mmap()ing
-# files, so it shouldn't harm much even if this limit is set pretty high.
-#imap_process_size = 256
+##
+## Mail processes
+##
 
-# Maximum number of running imap processes. When this limit is reached,
+# Maximum number of running mail processes. When this limit is reached,
 # new users aren't allowed to log in.
-#max_imap_processes = 1024
+#max_mail_processes = 1024
 
 # Show more verbose process titles (in ps). Currently shows user name and
 # IP address. Useful for seeing who are actually using the IMAP processes
 # (eg. shared mailboxes or if same uid is used for multiple accounts).
 #verbose_proctitle = no
 
-# Valid UID/GID ranges for imap users, defaults to 500 and above.
-# Note that denying root logins is hardcoded to imap-master binary and
+# Valid UID/GID ranges for users, defaults to 500 and above.
+# Note that denying root logins is hardcoded to dovecot-master binary and
 # can't be done even if first_valid_uid is set to 0.
 #first_valid_uid = 500
 #last_valid_uid = 0
@@ -137,7 +149,7 @@
 #first_valid_gid = 1
 #last_valid_gid = 0
 
-# ':' separated list of directories under which chrooting is allowed for imap
+# ':' separated list of directories under which chrooting is allowed for mail
 # processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too).
 # This setting doesn't affect login_chroot or auth_chroot variables.
 # WARNING: Never add directories here which local users can modify, that
@@ -257,6 +269,28 @@
 #umask = 0077
 
 ##
+## IMAP process
+##
+
+# Executable location
+#imap_executable = /usr/libexec/dovecot/imap
+
+# Set max. process size in megabytes. Most of the memory goes to mmap()ing
+# files, so it shouldn't harm much even if this limit is set pretty high.
+#imap_process_size = 256
+
+##
+## POP3 process
+##
+
+# Executable location
+#pop3_executable = /usr/libexec/dovecot/pop3
+
+# Set max. process size in megabytes. Most of the memory goes to mmap()ing
+# files, so it shouldn't harm much even if this limit is set pretty high.
+#pop3_process_size = 256
+
+##
 ## Authentication processes
 ##
 
@@ -302,7 +336,7 @@
 auth_passdb = pam
 
 # Executable location
-#auth_executable = /usr/libexec/dovecot/imap-auth
+#auth_executable = /usr/libexec/dovecot/dovecot-auth
 
 # Set max. process size in megabytes.
 #auth_process_size = 256
--- a/src/imap/main.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/imap/main.c	Thu Jan 30 19:59:31 2003 +0200
@@ -36,17 +36,17 @@
 	}
 	i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s)", user);
 
-	if (getenv("IMAP_USE_SYSLOG") != NULL)
+	if (getenv("USE_SYSLOG") != NULL)
 		i_set_failure_syslog(log_prefix, LOG_NDELAY, LOG_MAIL);
 	else {
 		/* log to file or stderr */
-		i_set_failure_file(getenv("IMAP_LOGFILE"), log_prefix);
+		i_set_failure_file(getenv("LOGFILE"), log_prefix);
 	}
 
-	if (getenv("IMAP_INFOLOGFILE") != NULL)
-		i_set_info_file(getenv("IMAP_INFOLOGFILE"));
+	if (getenv("INFOLOGFILE") != NULL)
+		i_set_info_file(getenv("INFOLOGFILE"));
 
-	i_set_failure_timestamp_format(getenv("IMAP_LOGSTAMP"));
+	i_set_failure_timestamp_format(getenv("LOGSTAMP"));
 }
 
 static void drop_privileges(void)
--- a/src/login-common/main.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/login-common/main.c	Thu Jan 30 19:59:31 2003 +0200
@@ -20,7 +20,7 @@
 unsigned int login_process_uid;
 
 static struct ioloop *ioloop;
-static struct io *io_listen, *io_listen_ssl;
+static struct io *io_listen, *io_ssl_listen;
 static int main_refcount;
 static int closing_down;
 
@@ -48,18 +48,18 @@
 
 	if (io_listen != NULL) {
 		if (close(LOGIN_LISTEN_FD) < 0)
-			i_fatal("can't close() IMAP listen handle");
+			i_fatal("close(listen) failed: %m");
 
 		io_remove(io_listen);
 		io_listen = NULL;
 	}
 
-	if (io_listen_ssl != NULL) {
+	if (io_ssl_listen != NULL) {
 		if (close(LOGIN_SSL_LISTEN_FD) < 0)
-			i_fatal("can't close() IMAPS listen handle");
+			i_fatal("close(ssl_listen) failed: %m");
 
-		io_remove(io_listen_ssl);
-		io_listen_ssl = NULL;
+		io_remove(io_ssl_listen);
+		io_ssl_listen = NULL;
 	}
 
 	closing_down = TRUE;
@@ -114,7 +114,7 @@
 
 static void open_logfile(const char *name)
 {
-	if (getenv("IMAP_USE_SYSLOG") != NULL)
+	if (getenv("USE_SYSLOG") != NULL)
 		i_set_failure_syslog(name, LOG_NDELAY, LOG_MAIL);
 	else {
 		/* log to file or stderr */
@@ -167,24 +167,22 @@
 	auth_connection_init();
 	clients_init();
 
-	io_listen = io_listen_ssl = NULL;
+	io_listen = io_ssl_listen = NULL;
 
 	if (net_getsockname(LOGIN_LISTEN_FD, NULL, NULL) == 0) {
-		/* we're listening for imap */
 		io_listen = io_add(LOGIN_LISTEN_FD, IO_READ,
 				   login_accept, NULL);
 	}
 
 	if (net_getsockname(LOGIN_SSL_LISTEN_FD, NULL, NULL) == 0) {
-		/* we're listening for imaps */
 		if (!ssl_initialized) {
 			/* this shouldn't happen, master should have
-			   disabled the imaps socket.. */
+			   disabled the ssl socket.. */
 			i_fatal("BUG: SSL initialization parameters not given "
 				"while they should have been");
 		}
 
-		io_listen_ssl = io_add(LOGIN_SSL_LISTEN_FD, IO_READ,
+		io_ssl_listen = io_add(LOGIN_SSL_LISTEN_FD, IO_READ,
 				       login_accept_ssl, NULL);
 	}
 
@@ -198,7 +196,7 @@
 		i_warning("Killed with signal %d", lib_signal_kill);
 
 	if (io_listen != NULL) io_remove(io_listen);
-	if (io_listen_ssl != NULL) io_remove(io_listen_ssl);
+	if (io_ssl_listen != NULL) io_remove(io_ssl_listen);
 
 	clients_deinit();
 	master_deinit();
--- a/src/master/.cvsignore	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/.cvsignore	Thu Jan 30 19:59:31 2003 +0200
@@ -6,4 +6,4 @@
 Makefile
 Makefile.in
 so_locations
-imap-master
+dovecot
--- a/src/master/Makefile.am	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/Makefile.am	Thu Jan 30 19:59:31 2003 +0200
@@ -1,6 +1,6 @@
 pkglibexecdir = $(libexecdir)/dovecot
 
-sbin_PROGRAMS = imap-master
+sbin_PROGRAMS = dovecot
 
 INCLUDES = \
 	-I$(top_srcdir)/src/lib \
@@ -9,14 +9,14 @@
 	-DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
 	-DSSLDIR=\""$(ssldir)\""
 
-imap_master_LDADD = \
+dovecot_LDADD = \
 	../lib/liblib.a \
 	$(SSL_LIBS)
 
-imap_master_SOURCES = \
+dovecot_SOURCES = \
 	auth-process.c \
-	imap-process.c \
 	login-process.c \
+	mail-process.c \
 	main.c \
 	settings.c \
 	ssl-init.c \
@@ -26,8 +26,8 @@
 noinst_HEADERS = \
 	auth-process.h \
 	common.h \
-	imap-process.h \
 	login-process.h \
+	mail-process.h \
 	master-login-interface.h \
 	settings.h \
 	ssl-init.h
--- a/src/master/auth-process.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/auth-process.c	Thu Jan 30 19:59:31 2003 +0200
@@ -222,7 +222,7 @@
 		}
 	}
 
-	(void)unlink(t_strconcat(set_login_dir, "/", p->name, NULL));
+	(void)unlink(t_strconcat(set->login_dir, "/", p->name, NULL));
 
 	hash_foreach(p->requests, request_hash_destroy, NULL);
 	hash_destroy(p->requests);
@@ -236,7 +236,7 @@
 	i_free(p);
 }
 
-static pid_t create_auth_process(struct auth_config *config)
+static pid_t create_auth_process(struct auth_settings *auth_set)
 {
 	static char *argv[] = { NULL, NULL };
 	const char *path;
@@ -244,8 +244,8 @@
 	pid_t pid;
 	int fd[2], listen_fd, i;
 
-	if ((pwd = getpwnam(config->user)) == NULL)
-		i_fatal("Auth user doesn't exist: %s", config->user);
+	if ((pwd = getpwnam(auth_set->user)) == NULL)
+		i_fatal("Auth user doesn't exist: %s", auth_set->user);
 
 	/* create communication to process with a socket pair */
 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) == -1) {
@@ -264,13 +264,13 @@
 	if (pid != 0) {
 		/* master */
 		fd_close_on_exec(fd[0], TRUE);
-		auth_process_new(pid, fd[0], config->name);
+		auth_process_new(pid, fd[0], auth_set->name);
 		(void)close(fd[1]);
 		return pid;
 	}
 
-	/* create socket for listening auth requests from imap-login */
-	path = t_strconcat(set_login_dir, "/", config->name, NULL);
+	/* create socket for listening auth requests from login */
+	path = t_strconcat(set->login_dir, "/", auth_set->name, NULL);
 	(void)unlink(path);
         (void)umask(0117); /* we want 0660 mode for the socket */
 
@@ -281,9 +281,9 @@
 	i_assert(listen_fd > 2);
 
 	/* set correct permissions */
-	if (chown(path, geteuid(), set_login_gid) < 0) {
+	if (chown(path, geteuid(), set->login_gid) < 0) {
 		i_fatal("login: chown(%s, %s, %s) failed: %m",
-			path, dec2str(set_login_uid), dec2str(set_login_gid));
+			path, dec2str(geteuid()), dec2str(set->login_gid));
 	}
 
 	/* move master communication handle to 0 */
@@ -315,34 +315,35 @@
 
 	/* setup access environment - needs to be done after
 	   clean_child_process() since it clears environment */
-	restrict_access_set_env(config->user, pwd->pw_uid, pwd->pw_gid,
-				config->chroot);
+	restrict_access_set_env(auth_set->user, pwd->pw_uid, pwd->pw_gid,
+				auth_set->chroot);
 
 	/* set other environment */
 	env_put(t_strconcat("AUTH_PROCESS=", dec2str(getpid()), NULL));
-	env_put(t_strconcat("MECHANISMS=", config->mechanisms, NULL));
-	env_put(t_strconcat("REALMS=", config->realms, NULL));
-	env_put(t_strconcat("USERDB=", config->userdb, NULL));
-	env_put(t_strconcat("USERDB_ARGS=", config->userdb_args, NULL));
-	env_put(t_strconcat("PASSDB=", config->passdb, NULL));
-	env_put(t_strconcat("PASSDB_ARGS=", config->passdb_args, NULL));
+	env_put(t_strconcat("MECHANISMS=", auth_set->mechanisms, NULL));
+	env_put(t_strconcat("REALMS=", auth_set->realms, NULL));
+	env_put(t_strconcat("USERDB=", auth_set->userdb, NULL));
+	env_put(t_strconcat("PASSDB=", auth_set->passdb, NULL));
 
-	if (config->use_cyrus_sasl)
+	if (auth_set->use_cyrus_sasl)
 		env_put("USE_CYRUS_SASL=1");
-	if (config->verbose)
+	if (auth_set->verbose)
 		env_put("VERBOSE=1");
 
-	restrict_process_size(config->process_size);
+	restrict_process_size(auth_set->process_size);
 
 	/* make sure we don't leak syslog fd, but do it last so that
 	   any errors above will be logged */
 	closelog();
 
 	/* hide the path, it's ugly */
-	argv[0] = strrchr(config->executable, '/');
-	if (argv[0] == NULL) argv[0] = config->executable; else argv[0]++;
+	argv[0] = strrchr(auth_set->executable, '/');
+	if (argv[0] == NULL)
+		argv[0] = i_strdup(auth_set->executable);
+	else
+		argv[0]++;
 
-	execv(config->executable, (char **) argv);
+	execv(auth_set->executable, argv);
 
 	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]);
 	return -1;
@@ -387,14 +388,14 @@
 static void
 auth_processes_start_missing(void *context __attr_unused__)
 {
-	struct auth_config *config;
+	struct auth_settings *auth_set;
 	unsigned int count;
 
-        config = auth_processes_config;
-	for (; config != NULL; config = config->next) {
-		count = auth_process_get_count(config->name);
-		for (; count < config->count; count++)
-			(void)create_auth_process(config);
+        auth_set = set->auths;
+	for (; auth_set != NULL; auth_set = auth_set->next) {
+		count = auth_process_get_count(auth_set->name);
+		for (; count < auth_set->count; count++)
+			(void)create_auth_process(auth_set);
 	}
 }
 
--- a/src/master/common.h	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/common.h	Thu Jan 30 19:59:31 2003 +0200
@@ -13,15 +13,24 @@
 	PROCESS_TYPE_UNKNOWN,
 	PROCESS_TYPE_AUTH,
 	PROCESS_TYPE_LOGIN,
-	PROCESS_TYPE_IMAP,
+	PROCESS_TYPE_MAIL,
 	PROCESS_TYPE_SSL_PARAM,
 
 	PROCESS_TYPE_MAX
 };
 
+enum {
+	FD_IMAP,
+	FD_IMAPS,
+	FD_POP3,
+	FD_POP3S,
+
+	FD_MAX
+};
+
 extern struct ioloop *ioloop;
 extern struct hash_table *pids;
-extern int null_fd, imap_fd, imaps_fd;
+extern int null_fd, mail_fd[FD_MAX];
 
 /* processes */
 #define PID_GET_PROCESS_TYPE(pid) \
--- a/src/master/imap-process.c	Thu Jan 30 19:56:19 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-/* Copyright (C) 2002 Timo Sirainen */
-
-#include "common.h"
-#include "fd-close-on-exec.h"
-#include "env-util.h"
-#include "str.h"
-#include "network.h"
-#include "restrict-access.h"
-#include "restrict-process-size.h"
-#include "var-expand.h"
-#include "imap-process.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <grp.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-static unsigned int imap_process_count = 0;
-
-static int validate_uid_gid(uid_t uid, gid_t gid)
-{
-	if (uid == 0) {
-		i_error("imap process isn't allowed for root");
-		return FALSE;
-	}
-
-	if (uid != 0 && gid == 0) {
-		i_error("imap process isn't allowed to be in group 0");
-		return FALSE;
-	}
-
-	if (uid < (uid_t)set_first_valid_uid ||
-	    (set_last_valid_uid != 0 && uid > (uid_t)set_last_valid_uid)) {
-		i_error("imap process isn't allowed to use UID %s",
-			dec2str(uid));
-		return FALSE;
-	}
-
-	if (gid < (gid_t)set_first_valid_gid ||
-	    (set_last_valid_gid != 0 && gid > (gid_t)set_last_valid_gid)) {
-		i_error("imap process isn't allowed to use "
-			"GID %s (UID is %s)", dec2str(gid), dec2str(uid));
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static int validate_chroot(const char *dir)
-{
-	const char *const *chroot_dirs;
-
-	if (*dir == '\0')
-		return FALSE;
-
-	if (set_valid_chroot_dirs == NULL)
-		return FALSE;
-
-	chroot_dirs = t_strsplit(set_valid_chroot_dirs, ":");
-	while (*chroot_dirs != NULL) {
-		if (**chroot_dirs != '\0' &&
-		    strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
-			return TRUE;
-		chroot_dirs++;
-	}
-
-	return FALSE;
-}
-
-static const char *expand_mail_env(const char *env, const char *user,
-				   const char *home)
-{
-	string_t *str;
-	const char *p;
-
-	str = t_str_new(256);
-
-	/* it's either type:data or just data */
-	p = strchr(env, ':');
-	if (p != NULL) {
-		while (env != p) {
-			str_append_c(str, *env);
-			env++;
-		}
-
-		str_append_c(str, *env++);
-	}
-
-	if (env[0] == '~' && env[1] == '/') {
-		/* expand home */
-		str_append(str, home);
-		env++;
-	}
-
-	/* expand %vars */
-        var_expand(str, env, user, home);
-	return str_c(str);
-}
-
-int create_imap_process(int socket, struct ip_addr *ip,
-			struct auth_master_reply *reply, const char *data)
-{
-	static char *argv[] = { NULL, NULL, NULL };
-	const char *host, *mail;
-	char title[1024];
-	pid_t pid;
-	int i, err;
-
-	if (imap_process_count == set_max_imap_processes) {
-		i_error("Maximum number of imap processes exceeded");
-		return FALSE;
-	}
-
-	if (!validate_uid_gid(reply->uid, reply->gid))
-		return FALSE;
-
-	if (reply->chroot && !validate_chroot(data + reply->home_idx))
-		return FALSE;
-
-	pid = fork();
-	if (pid < 0) {
-		i_error("fork() failed: %m");
-		return FALSE;
-	}
-
-	if (pid != 0) {
-		/* master */
-		imap_process_count++;
-		PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_IMAP);
-		return TRUE;
-	}
-
-	clean_child_process();
-
-	/* move the imap socket into stdin, stdout and stderr fds */
-	fd_close_on_exec(socket, FALSE);
-	for (i = 0; i < 3; i++) {
-		if (dup2(socket, i) < 0)
-			i_fatal("imap: dup2(%d) failed: %m", i);
-	}
-
-	if (close(socket) < 0)
-		i_error("imap: close(imap client) failed: %m");
-
-	/* setup environment - set the most important environment first
-	   (paranoia about filling up environment without noticing) */
-	restrict_access_set_env(data + reply->system_user_idx,
-				reply->uid, reply->gid,
-				reply->chroot ? data + reply->home_idx : NULL);
-	restrict_process_size(set_imap_process_size);
-
-	env_put("LOGGED_IN=1");
-	env_put(t_strconcat("HOME=", data + reply->home_idx, NULL));
-	env_put(t_strconcat("MAIL_CACHE_FIELDS=", set_mail_cache_fields, NULL));
-	env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=",
-			    set_mail_never_cache_fields, NULL));
-	env_put(t_strdup_printf("MAILBOX_CHECK_INTERVAL=%u",
-				set_mailbox_check_interval));
-
-	if (set_mail_save_crlf)
-		env_put("MAIL_SAVE_CRLF=1");
-	if (set_mail_read_mmaped)
-		env_put("MAIL_READ_MMAPED=1");
-	if (set_maildir_copy_with_hardlinks)
-		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
-	if (set_maildir_check_content_changes)
-		env_put("MAILDIR_CHECK_CONTENT_CHANGES=1");
-	if (set_overwrite_incompatible_index)
-		env_put("OVERWRITE_INCOMPATIBLE_INDEX=1");
-	if (umask(set_umask) != set_umask)
-		i_fatal("Invalid umask: %o", set_umask);
-
-	env_put(t_strconcat("MBOX_LOCKS=", set_mbox_locks, NULL));
-	env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u", set_mbox_lock_timeout));
-	env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u",
-				set_mbox_dotlock_change_timeout));
-	if (set_mbox_read_dotlock)
-		env_put("MBOX_READ_DOTLOCK=1");
-
-	/* user given environment - may be malicious. virtual_user comes from
-	   auth process, but don't trust that too much either. Some auth
-	   mechanism might allow leaving extra data there. */
-	mail = data + reply->mail_idx;
-	if (*mail == '\0' && set_default_mail_env != NULL) {
-		mail = expand_mail_env(set_default_mail_env,
-				       data + reply->virtual_user_idx,
-				       data + reply->home_idx);
-	}
-
-	env_put(t_strconcat("MAIL=", mail, NULL));
-	env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL));
-
-	if (set_verbose_proctitle) {
-		host = net_ip2host(ip);
-		if (host == NULL)
-			host = "??";
-
-		i_snprintf(title, sizeof(title), "[%s %s]",
-			   data + reply->virtual_user_idx, host);
-		argv[1] = title;
-	}
-
-	/* make sure we don't leak syslog fd, but do it last so that
-	   any errors above will be logged */
-	closelog();
-
-	/* hide the path, it's ugly */
-	argv[0] = strrchr(set_imap_executable, '/');
-	if (argv[0] == NULL) argv[0] = set_imap_executable; else argv[0]++;
-
-	execv(set_imap_executable, argv);
-	err = errno;
-
-	for (i = 0; i < 3; i++)
-		(void)close(i);
-
-	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", set_imap_executable);
-
-	/* not reached */
-	return FALSE;
-}
-
-void imap_process_destroyed(pid_t pid __attr_unused__)
-{
-	imap_process_count--;
-}
--- a/src/master/imap-process.h	Thu Jan 30 19:56:19 2003 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-#ifndef __IMAP_PROCESS_H
-#define __IMAP_PROCESS_H
-
-struct auth_master_reply;
-
-int create_imap_process(int socket, struct ip_addr *ip,
-			struct auth_master_reply *reply, const char *data);
-void imap_process_destroyed(pid_t pid);
-
-#endif
--- a/src/master/login-process.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/login-process.c	Thu Jan 30 19:59:31 2003 +0200
@@ -11,13 +11,31 @@
 #include "restrict-process-size.h"
 #include "login-process.h"
 #include "auth-process.h"
-#include "imap-process.h"
+#include "mail-process.h"
 #include "master-login-interface.h"
 
 #include <unistd.h>
 #include <syslog.h>
 
+struct login_group {
+	struct login_group *next;
+
+	struct login_settings *set;
+
+	unsigned int processes;
+	unsigned int listening_processes;
+	unsigned int wanted_processes_count;
+
+	struct login_process *oldest_nonlisten_process;
+	struct login_process *newest_nonlisten_process;
+
+	const char *executable;
+	unsigned int process_size;
+	int *listen_fd, *ssl_listen_fd;
+};
+
 struct login_process {
+	struct login_group *group;
 	struct login_process *prev_nonlisten, *next_nonlisten;
 	int refcount;
 
@@ -44,14 +62,40 @@
 static struct timeout *to;
 
 static struct hash_table *processes;
-static struct login_process *oldest_nonlisten_process;
-static struct login_process *newest_nonlisten_process;
-static unsigned int listening_processes;
-static unsigned int wanted_processes_count;
+static struct login_group *login_groups;
 
 static void login_process_destroy(struct login_process *p);
 static void login_process_unref(struct login_process *p);
 
+static void login_group_create(struct login_settings *login_set)
+{
+	struct login_group *group;
+
+	group = i_new(struct login_group, 1);
+	group->set = login_set;
+
+	if (strcmp(login_set->name, "imap") == 0) {
+		group->executable = set->imap_executable;
+		group->process_size = set->imap_process_size;
+		group->listen_fd = &mail_fd[FD_IMAP];
+		group->ssl_listen_fd = &mail_fd[FD_IMAPS];
+	} else if (strcmp(login_set->name, "pop3") == 0) {
+		group->executable = set->pop3_executable;
+		group->process_size = set->pop3_process_size;
+		group->listen_fd = &mail_fd[FD_POP3];
+		group->ssl_listen_fd = &mail_fd[FD_POP3S];
+	} else
+		i_panic("Unknown login group name '%s'", login_set->name);
+
+	group->next = login_groups;
+	login_groups = group;
+}
+
+static void login_group_destroy(struct login_group *group)
+{
+	i_free(group);
+}
+
 void auth_master_callback(struct auth_master_reply *reply,
 			  const unsigned char *data, void *context)
 {
@@ -61,9 +105,13 @@
 	if (reply == NULL || !reply->success)
 		master_reply.success = FALSE;
 	else {
+		struct login_group *group = request->process->group;
+
 		master_reply.success =
-			create_imap_process(request->fd, &request->ip, reply,
-					    (const char *) data);
+			create_mail_process(request->fd, &request->ip,
+					    group->executable,
+					    group->process_size,
+					    reply, (const char *) data);
 	}
 
 	/* reply to login */
@@ -74,7 +122,7 @@
 		login_process_destroy(request->process);
 
 	if (close(request->fd) < 0)
-		i_error("close(imap client) failed: %m");
+		i_error("close(mail client) failed: %m");
 	login_process_unref(request->process);
 	i_free(request);
 }
@@ -88,16 +136,16 @@
 	}
 
 	p->listening = FALSE;
-	listening_processes--;
+	p->group->listening_processes--;
 
-	p->prev_nonlisten = newest_nonlisten_process;
+	p->prev_nonlisten = p->group->newest_nonlisten_process;
 
-	if (newest_nonlisten_process != NULL)
-		newest_nonlisten_process->next_nonlisten = p;
-	newest_nonlisten_process = p;
+	if (p->group->newest_nonlisten_process != NULL)
+		p->group->newest_nonlisten_process->next_nonlisten = p;
+	p->group->newest_nonlisten_process = p;
 
-	if (oldest_nonlisten_process == NULL)
-		oldest_nonlisten_process = p;
+	if (p->group->oldest_nonlisten_process == NULL)
+		p->group->oldest_nonlisten_process = p;
 }
 
 static void login_process_input(void *context)
@@ -121,7 +169,7 @@
 
 		if (client_fd != -1) {
 			if (close(client_fd) < 0)
-				i_error("close(imap client) failed: %m");
+				i_error("close(mail client) failed: %m");
 		}
 
 		login_process_destroy(p);
@@ -162,13 +210,15 @@
 	}
 }
 
-static struct login_process *login_process_new(pid_t pid, int fd)
+static struct login_process *
+login_process_new(struct login_group *group, pid_t pid, int fd)
 {
 	struct login_process *p;
 
 	PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_LOGIN);
 
 	p = i_new(struct login_process, 1);
+	p->group = group;
 	p->refcount = 1;
 	p->pid = pid;
 	p->fd = fd;
@@ -179,19 +229,20 @@
 					 IO_PRIORITY_DEFAULT, FALSE);
 
 	hash_insert(processes, POINTER_CAST(pid), p);
-        listening_processes++;
+	p->group->processes++;
+	p->group->listening_processes++;
 	return p;
 }
 
 static void login_process_remove_from_lists(struct login_process *p)
 {
-	if (p == oldest_nonlisten_process)
-		oldest_nonlisten_process = p->next_nonlisten;
+	if (p == p->group->oldest_nonlisten_process)
+		p->group->oldest_nonlisten_process = p->next_nonlisten;
 	else
 		p->prev_nonlisten->next_nonlisten = p->next_nonlisten;
 
-	if (p == newest_nonlisten_process)
-		newest_nonlisten_process = p->prev_nonlisten;
+	if (p == p->group->newest_nonlisten_process)
+		p->group->newest_nonlisten_process = p->prev_nonlisten;
 	else
 		p->next_nonlisten->prev_nonlisten = p->prev_nonlisten;
 
@@ -209,7 +260,7 @@
 		io_loop_stop(ioloop);
 	}
 	if (p->listening)
-		listening_processes--;
+		p->group->listening_processes--;
 
 	o_stream_close(p->output);
 	io_remove(p->io);
@@ -219,6 +270,7 @@
 	if (!p->listening)
 		login_process_remove_from_lists(p);
 
+	p->group->processes--;
 	hash_remove(processes, POINTER_CAST(p->pid));
 
 	login_process_unref(p);
@@ -233,19 +285,20 @@
 	i_free(p);
 }
 
-static pid_t create_login_process(void)
+static pid_t create_login_process(struct login_group *group)
 {
-	static char *argv[] = { NULL, NULL };
+	static const char *argv[] = { NULL, NULL };
 	pid_t pid;
 	int fd[2];
 
-	if (set_login_process_per_connection &&
-	    hash_size(processes)-listening_processes >= set_max_logging_users) {
-		if (oldest_nonlisten_process != NULL)
-			login_process_destroy(oldest_nonlisten_process);
+	if (group->set->process_per_connection &&
+	    group->processes - group->listening_processes >=
+	    group->set->max_logging_users) {
+		if (group->oldest_nonlisten_process != NULL)
+			login_process_destroy(group->oldest_nonlisten_process);
 	}
 
-	if (set_login_uid == 0)
+	if (group->set->uid == 0)
 		i_fatal("Login process must not run as root");
 
 	/* create communication to process with a socket pair */
@@ -265,7 +318,7 @@
 	if (pid != 0) {
 		/* master */
 		fd_close_on_exec(fd[0], TRUE);
-		login_process_new(pid, fd[0]);
+		login_process_new(group, pid, fd[0]);
 		(void)close(fd[1]);
 		return pid;
 	}
@@ -276,21 +329,21 @@
 	fd_close_on_exec(LOGIN_MASTER_SOCKET_FD, FALSE);
 
 	/* move the listen handle */
-	if (dup2(imap_fd, LOGIN_IMAP_LISTEN_FD) < 0)
-		i_fatal("login: dup2(imap) failed: %m");
-	fd_close_on_exec(LOGIN_IMAP_LISTEN_FD, FALSE);
+	if (dup2(*group->listen_fd, LOGIN_LISTEN_FD) < 0)
+		i_fatal("login: dup2(listen_fd) failed: %m");
+	fd_close_on_exec(LOGIN_LISTEN_FD, FALSE);
 
 	/* move the SSL listen handle */
-	if (!set_ssl_disable) {
-		if (dup2(imaps_fd, LOGIN_IMAPS_LISTEN_FD) < 0)
-			i_fatal("login: dup2(imaps) failed: %m");
+	if (!set->ssl_disable) {
+		if (dup2(*group->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0)
+			i_fatal("login: dup2(ssl_listen_fd) failed: %m");
 	} else {
-		if (dup2(null_fd, LOGIN_IMAPS_LISTEN_FD) < 0)
-			i_fatal("login: dup2(imaps) failed: %m");
+		if (dup2(null_fd, LOGIN_SSL_LISTEN_FD) < 0)
+			i_fatal("login: dup2(ssl_listen_fd) failed: %m");
 	}
-	fd_close_on_exec(LOGIN_IMAPS_LISTEN_FD, FALSE);
+	fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE);
 
-	/* imap_fd and imaps_fd are closed by clean_child_process() */
+	/* listen_fds are closed by clean_child_process() */
 
 	(void)close(fd[0]);
 	(void)close(fd[1]);
@@ -299,58 +352,64 @@
 
 	/* setup access environment - needs to be done after
 	   clean_child_process() since it clears environment */
-	restrict_access_set_env(set_login_user, set_login_uid, set_login_gid,
-				set_login_chroot ? set_login_dir : NULL);
+	restrict_access_set_env(group->set->user,
+				group->set->uid, set->login_gid,
+				set->login_chroot ? set->login_dir : NULL);
 
-	if (!set_login_chroot) {
+	if (!set->login_chroot) {
 		/* no chrooting, but still change to the directory */
-		if (chdir(set_login_dir) < 0)
-			i_fatal("chdir(%s) failed: %m", set_login_dir);
+		if (chdir(set->login_dir) < 0)
+			i_fatal("chdir(%s) failed: %m", set->login_dir);
 	}
 
-	if (!set_ssl_disable) {
-		env_put(t_strconcat("SSL_CERT_FILE=", set_ssl_cert_file, NULL));
-		env_put(t_strconcat("SSL_KEY_FILE=", set_ssl_key_file, NULL));
+	if (!set->ssl_disable) {
+		env_put(t_strconcat("SSL_CERT_FILE=",
+				    set->ssl_cert_file, NULL));
+		env_put(t_strconcat("SSL_KEY_FILE=", set->ssl_key_file, NULL));
 		env_put(t_strconcat("SSL_PARAM_FILE=",
-				    set_ssl_parameters_file, NULL));
+				    set->ssl_parameters_file, NULL));
 	}
 
-	if (set_disable_plaintext_auth)
+	if (set->disable_plaintext_auth)
 		env_put("DISABLE_PLAINTEXT_AUTH=1");
-	if (set_verbose_proctitle)
+	if (set->verbose_proctitle)
 		env_put("VERBOSE_PROCTITLE=1");
 
-	if (set_login_process_per_connection) {
+	if (group->set->process_per_connection) {
 		env_put("PROCESS_PER_CONNECTION=1");
 		env_put("MAX_LOGGING_USERS=1");
 	} else {
 		env_put(t_strdup_printf("MAX_LOGGING_USERS=%u",
-					set_max_logging_users));
+					group->set->max_logging_users));
 	}
 
 	env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(getpid())));
 
-	restrict_process_size(set_login_process_size);
+	restrict_process_size(group->set->process_size);
 
 	/* make sure we don't leak syslog fd, but do it last so that
 	   any errors above will be logged */
 	closelog();
 
 	/* hide the path, it's ugly */
-	argv[0] = strrchr(set_login_executable, '/');
-	if (argv[0] == NULL) argv[0] = set_login_executable; else argv[0]++;
+	argv[0] = strrchr(group->set->executable, '/');
+	if (argv[0] == NULL) argv[0] = group->set->executable; else argv[0]++;
 
-	execv(set_login_executable, (char **) argv);
+	execv(group->set->executable, (char **) argv);
 
 	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", argv[0]);
 	return -1;
 }
 
-void login_process_abormal_exit(pid_t pid __attr_unused__)
+void login_process_abormal_exit(pid_t pid)
 {
+	struct login_process *p;
+
 	/* don't start raising the process count if they're dying all
 	   the time */
-	wanted_processes_count = 0;
+	p = hash_lookup(processes, POINTER_CAST(pid));
+	if (p != NULL)
+		p->group->wanted_processes_count = 0;
 }
 
 static void login_hash_destroy(void *key __attr_unused__, void *value,
@@ -363,47 +422,64 @@
 {
 	hash_foreach(processes, login_hash_destroy, NULL);
 
-	/* don't double their amount when restarting */
-	wanted_processes_count = 0;
+	while (login_groups != NULL) {
+		struct login_group *group = login_groups;
+
+		login_groups = group->next;
+		login_group_destroy(group);
+	}
+}
+
+static void login_group_start_missings(struct login_group *group)
+{
+	if (!group->set->process_per_connection) {
+		/* create max. one process every second, that way if it keeps
+		   dying all the time we don't eat all cpu with fork()ing. */
+		if (group->listening_processes < group->set->processes_count)
+			(void)create_login_process(group);
+		return;
+	}
+
+	/* we want to respond fast when multiple clients are connecting
+	   at once, but we also want to prevent fork-bombing. use the
+	   same method as apache: check once a second if we need new
+	   processes. if yes and we've used all the existing processes,
+	   double their amount (unless we've hit the high limit).
+	   Then for each second that didn't use all existing processes,
+	   drop the max. process count by one. */
+	if (group->wanted_processes_count < group->set->processes_count)
+		group->wanted_processes_count = group->set->processes_count;
+	else if (group->listening_processes == 0)
+		group->wanted_processes_count *= 2;
+	else if (group->wanted_processes_count > group->set->processes_count)
+		group->wanted_processes_count--;
+
+	if (group->wanted_processes_count > group->set->max_processes_count)
+		group->wanted_processes_count = group->set->max_processes_count;
+
+	while (group->listening_processes < group->wanted_processes_count)
+		(void)create_login_process(group);
 }
 
 static void
 login_processes_start_missing(void *context __attr_unused__)
 {
-	if (!set_login_process_per_connection) {
-		/* create max. one process every second, that way if it keeps
-		   dying all the time we don't eat all cpu with fork()ing. */
-		if (listening_processes < set_login_processes_count)
-			(void)create_login_process();
-	} else {
-		/* we want to respond fast when multiple clients are connecting
-		   at once, but we also want to prevent fork-bombing. use the
-		   same method as apache: check once a second if we need new
-		   processes. if yes and we've used all the existing processes,
-		   double their amount (unless we've hit the high limit).
-		   Then for each second that didn't use all existing processes,
-		   drop the max. process count by one. */
-		if (wanted_processes_count < set_login_processes_count)
-			wanted_processes_count = set_login_processes_count;
-		else if (listening_processes == 0)
-			wanted_processes_count *= 2;
-		else if (wanted_processes_count > set_login_processes_count)
-			wanted_processes_count--;
+	struct login_group *group;
+	struct login_settings *login;
 
-		if (wanted_processes_count > set_login_max_processes_count)
-			wanted_processes_count = set_login_max_processes_count;
+	if (login_groups == NULL) {
+		for (login = set->logins; login != NULL; login = login->next)
+			login_group_create(login);
+	}
 
-		while (listening_processes < wanted_processes_count)
-			(void)create_login_process();
-	}
+	for (group = login_groups; group != NULL; group = group->next)
+		login_group_start_missings(group);
 }
 
 void login_processes_init(void)
 {
         auth_id_counter = 0;
-	listening_processes = 0;
-        wanted_processes_count = 0;
-	oldest_nonlisten_process = newest_nonlisten_process = NULL;
+	login_groups = NULL;
 
 	processes = hash_create(default_pool, default_pool, 128, NULL, NULL);
 	to = timeout_add(1000, login_processes_start_missing, NULL);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/master/mail-process.c	Thu Jan 30 19:59:31 2003 +0200
@@ -0,0 +1,233 @@
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "common.h"
+#include "fd-close-on-exec.h"
+#include "env-util.h"
+#include "str.h"
+#include "network.h"
+#include "restrict-access.h"
+#include "restrict-process-size.h"
+#include "var-expand.h"
+#include "mail-process.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <grp.h>
+#include <syslog.h>
+#include <sys/stat.h>
+
+static unsigned int mail_process_count = 0;
+
+static int validate_uid_gid(uid_t uid, gid_t gid)
+{
+	if (uid == 0) {
+		i_error("mail process isn't allowed for root");
+		return FALSE;
+	}
+
+	if (uid != 0 && gid == 0) {
+		i_error("mail process isn't allowed to be in group 0");
+		return FALSE;
+	}
+
+	if (uid < (uid_t)set->first_valid_uid ||
+	    (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) {
+		i_error("mail process isn't allowed to use UID %s",
+			dec2str(uid));
+		return FALSE;
+	}
+
+	if (gid < (gid_t)set->first_valid_gid ||
+	    (set->last_valid_gid != 0 && gid > (gid_t)set->last_valid_gid)) {
+		i_error("mail process isn't allowed to use "
+			"GID %s (UID is %s)", dec2str(gid), dec2str(uid));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int validate_chroot(const char *dir)
+{
+	const char *const *chroot_dirs;
+
+	if (*dir == '\0')
+		return FALSE;
+
+	if (set->valid_chroot_dirs == NULL)
+		return FALSE;
+
+	chroot_dirs = t_strsplit(set->valid_chroot_dirs, ":");
+	while (*chroot_dirs != NULL) {
+		if (**chroot_dirs != '\0' &&
+		    strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0)
+			return TRUE;
+		chroot_dirs++;
+	}
+
+	return FALSE;
+}
+
+static const char *expand_mail_env(const char *env, const char *user,
+				   const char *home)
+{
+	string_t *str;
+	const char *p;
+
+	str = t_str_new(256);
+
+	/* it's either type:data or just data */
+	p = strchr(env, ':');
+	if (p != NULL) {
+		while (env != p) {
+			str_append_c(str, *env);
+			env++;
+		}
+
+		str_append_c(str, *env++);
+	}
+
+	if (env[0] == '~' && env[1] == '/') {
+		/* expand home */
+		str_append(str, home);
+		env++;
+	}
+
+	/* expand %vars */
+        var_expand(str, env, user, home);
+	return str_c(str);
+}
+
+int create_mail_process(int socket, struct ip_addr *ip,
+			const char *executable, unsigned int process_size,
+			struct auth_master_reply *reply, const char *data)
+{
+	static const char *argv[] = { NULL, NULL, NULL };
+	const char *host, *mail;
+	char title[1024];
+	pid_t pid;
+	int i, err;
+
+	if (mail_process_count == set->max_mail_processes) {
+		i_error("Maximum number of mail processes exceeded");
+		return FALSE;
+	}
+
+	if (!validate_uid_gid(reply->uid, reply->gid))
+		return FALSE;
+
+	if (reply->chroot && !validate_chroot(data + reply->home_idx))
+		return FALSE;
+
+	pid = fork();
+	if (pid < 0) {
+		i_error("fork() failed: %m");
+		return FALSE;
+	}
+
+	if (pid != 0) {
+		/* master */
+		mail_process_count++;
+		PID_ADD_PROCESS_TYPE(pid, PROCESS_TYPE_MAIL);
+		return TRUE;
+	}
+
+	clean_child_process();
+
+	/* move the client socket into stdin and stdout fds */
+	fd_close_on_exec(socket, FALSE);
+	if (dup2(socket, 0) < 0)
+		i_fatal("mail: dup2(stdin) failed: %m");
+	if (dup2(socket, 1) < 0)
+		i_fatal("mail: dup2(stdout) failed: %m");
+	if (dup2(null_fd, 2) < 0)
+		i_fatal("mail: dup2(stderr) failed: %m");
+
+	if (close(socket) < 0)
+		i_error("mail: close(mail client) failed: %m");
+
+	/* setup environment - set the most important environment first
+	   (paranoia about filling up environment without noticing) */
+	restrict_access_set_env(data + reply->system_user_idx,
+				reply->uid, reply->gid,
+				reply->chroot ? data + reply->home_idx : NULL);
+
+	restrict_process_size(process_size);
+
+	env_put("LOGGED_IN=1");
+	env_put(t_strconcat("HOME=", data + reply->home_idx, NULL));
+	env_put(t_strconcat("MAIL_CACHE_FIELDS=",
+			    set->mail_cache_fields, NULL));
+	env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=",
+			    set->mail_never_cache_fields, NULL));
+	env_put(t_strdup_printf("MAILBOX_CHECK_INTERVAL=%u",
+				set->mailbox_check_interval));
+
+	if (set->mail_save_crlf)
+		env_put("MAIL_SAVE_CRLF=1");
+	if (set->mail_read_mmaped)
+		env_put("MAIL_READ_MMAPED=1");
+	if (set->maildir_copy_with_hardlinks)
+		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
+	if (set->maildir_check_content_changes)
+		env_put("MAILDIR_CHECK_CONTENT_CHANGES=1");
+	if (set->overwrite_incompatible_index)
+		env_put("OVERWRITE_INCOMPATIBLE_INDEX=1");
+	if (umask(set->umask) != set->umask)
+		i_fatal("Invalid umask: %o", set->umask);
+
+	env_put(t_strconcat("MBOX_LOCKS=", set->mbox_locks, NULL));
+	env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u",
+				set->mbox_lock_timeout));
+	env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u",
+				set->mbox_dotlock_change_timeout));
+	if (set->mbox_read_dotlock)
+		env_put("MBOX_READ_DOTLOCK=1");
+
+	/* user given environment - may be malicious. virtual_user comes from
+	   auth process, but don't trust that too much either. Some auth
+	   mechanism might allow leaving extra data there. */
+	mail = data + reply->mail_idx;
+	if (*mail == '\0' && set->default_mail_env != NULL) {
+		mail = expand_mail_env(set->default_mail_env,
+				       data + reply->virtual_user_idx,
+				       data + reply->home_idx);
+	}
+
+	env_put(t_strconcat("MAIL=", mail, NULL));
+	env_put(t_strconcat("USER=", data + reply->virtual_user_idx, NULL));
+
+	if (set->verbose_proctitle) {
+		host = net_ip2host(ip);
+		if (host == NULL)
+			host = "??";
+
+		i_snprintf(title, sizeof(title), "[%s %s]",
+			   data + reply->virtual_user_idx, host);
+		argv[1] = title;
+	}
+
+	/* make sure we don't leak syslog fd, but do it last so that
+	   any errors above will be logged */
+	closelog();
+
+	/* hide the path, it's ugly */
+	argv[0] = strrchr(executable, '/');
+	if (argv[0] == NULL) argv[0] = executable; else argv[0]++;
+
+	execv(executable, (char **) argv);
+	err = errno;
+
+	for (i = 0; i < 3; i++)
+		(void)close(i);
+
+	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
+
+	/* not reached */
+	return FALSE;
+}
+
+void mail_process_destroyed(pid_t pid __attr_unused__)
+{
+	mail_process_count--;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/master/mail-process.h	Thu Jan 30 19:59:31 2003 +0200
@@ -0,0 +1,12 @@
+#ifndef __MAIL_PROCESS_H
+#define __MAIL_PROCESS_H
+
+struct auth_master_reply;
+
+int create_mail_process(int socket, struct ip_addr *ip,
+			const char *executable, unsigned int process_size,
+			struct auth_master_reply *reply, const char *data);
+
+void mail_process_destroyed(pid_t pid);
+
+#endif
--- a/src/master/main.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/main.c	Thu Jan 30 19:59:31 2003 +0200
@@ -9,7 +9,7 @@
 
 #include "auth-process.h"
 #include "login-process.h"
-#include "imap-process.h"
+#include "mail-process.h"
 #include "ssl-init.h"
 
 #include <stdio.h>
@@ -33,7 +33,7 @@
 
 struct ioloop *ioloop;
 struct hash_table *pids;
-int null_fd, imap_fd, imaps_fd;
+int null_fd, mail_fd[FD_MAX];
 
 int validate_str(const char *str, size_t max_len)
 {
@@ -53,18 +53,20 @@
 	env_clean();
 
 	/* set the failure log */
-	if (set_log_path == NULL)
-		env_put("IMAP_USE_SYSLOG=1");
+	if (set->log_path == NULL)
+		env_put("USE_SYSLOG=1");
 	else
-		env_put(t_strconcat("IMAP_LOGFILE=", set_log_path, NULL));
+		env_put(t_strconcat("LOGFILE=", set->log_path, NULL));
 
-	if (set_info_log_path != NULL) {
-		env_put(t_strconcat("IMAP_INFOLOGFILE=",
-				    set_info_log_path, NULL));
+	if (set->info_log_path != NULL) {
+		env_put(t_strconcat("INFOLOGFILE=",
+				    set->info_log_path, NULL));
 	}
 
-	if (set_log_timestamp != NULL)
-		env_put(t_strconcat("IMAP_LOGSTAMP=", set_log_timestamp, NULL));
+	if (set->log_timestamp != NULL) {
+		env_put(t_strconcat("LOGSTAMP=",
+				    set->log_timestamp, NULL));
+	}
 }
 
 static void sig_quit(int signo __attr_unused__)
@@ -120,8 +122,8 @@
 		process_type = PID_GET_PROCESS_TYPE(pid);
 		PID_REMOVE_PROCESS_TYPE(pid);
 
-		if (process_type == PROCESS_TYPE_IMAP)
-			imap_process_destroyed(pid);
+		if (process_type == PROCESS_TYPE_MAIL)
+			mail_process_destroyed(pid);
 		if (process_type == PROCESS_TYPE_SSL_PARAM)
 			ssl_parameter_process_destroyed(pid);
 
@@ -153,13 +155,37 @@
 		i_warning("waitpid() failed: %m");
 }
 
-static struct ip_addr *resolve_ip(const char *name)
+static struct ip_addr *resolve_ip(const char *name, unsigned int *port)
 {
+	const char *p;
 	struct ip_addr *ip;
 	int ret, ips_count;
 
 	if (name == NULL)
-		return NULL; /* defaults to "*" or "::" */
+		return NULL; /* defaults to "*" or "[::]" */
+
+	if (name[0] == '[') {
+		/* IPv6 address */
+		p = strchr(name, ']');
+		if (p == NULL)
+			i_fatal("Missing ']' in address %s", name);
+
+		name = t_strdup_until(name, p);
+
+		p++;
+		if (*p != '\0' && *p != ':')
+			i_fatal("Invalid data after ']' in address %s", name);
+	} else {
+		p = strrchr(name, ':');
+		if (p != NULL)
+			name = t_strdup_until(name, p);
+	}
+
+	if (p != NULL) {
+		if (!is_numeric(p+1, '\0'))
+			i_fatal("Invalid port in address %s", name);
+		*port = atoi(p+1);
+	}
 
 	if (strcmp(name, "*") == 0) {
 		/* IPv4 any */
@@ -168,7 +194,7 @@
 		return ip;
 	}
 
-	if (strcmp(name, "::") == 0) {
+	if (strcmp(name, "[::]") == 0) {
 		/* IPv6 any */
 		ip = t_new(struct ip_addr, 1);
 		net_get_ip_any6(ip);
@@ -190,49 +216,86 @@
 
 static void open_fds(void)
 {
-	struct ip_addr *imap_ip, *imaps_ip;
+	struct ip_addr *imap_ip, *imaps_ip, *pop3_ip, *pop3s_ip, *ip;
+	const char *const *proto;
+	unsigned int imap_port = 143;
+	unsigned int pop3_port = 110;
+#ifdef HAVE_SSL
+	unsigned int imaps_port = 993;
+	unsigned int pop3s_port = 995;
+#else
+	unsigned int imaps_port = 0;
+	unsigned int pop3s_port = 0;
+#endif
+	unsigned int port;
+	int *fd, i;
 
-	imap_ip = resolve_ip(set_imap_listen);
-	imaps_ip = resolve_ip(set_imaps_listen);
+	/* resolve */
+	imap_ip = resolve_ip(set->imap_listen, &imap_port);
+	imaps_ip = resolve_ip(set->imaps_listen, &imaps_port);
+	pop3_ip = resolve_ip(set->pop3_listen, &pop3_port);
+	pop3s_ip = resolve_ip(set->pop3s_listen, &pop3s_port);
 
-	if (imaps_ip == NULL && set_imaps_listen == NULL)
+	if (imaps_ip == NULL && set->imaps_listen == NULL)
 		imaps_ip = imap_ip;
+	if (pop3s_ip == NULL && set->pop3s_listen == NULL)
+		pop3s_ip = pop3_ip;
 
+	/* initialize fds */
 	null_fd = open("/dev/null", O_RDONLY);
 	if (null_fd == -1)
 		i_fatal("Can't open /dev/null: %m");
 	fd_close_on_exec(null_fd, TRUE);
 
-	imap_fd = set_imap_port == 0 ? dup(null_fd) :
-		net_listen(imap_ip, &set_imap_port);
-	if (imap_fd == -1)
-		i_fatal("listen(%d) failed: %m", set_imap_port);
-	fd_close_on_exec(imap_fd, TRUE);
+	for (i = 0; i < FD_MAX; i++)
+		mail_fd[i] = -1;
+
+	/* register wanted protocols */
+	for (proto = t_strsplit(set->protocols, " "); *proto != NULL; proto++) {
+		if (strcasecmp(*proto, "imap") == 0) {
+			fd = &mail_fd[FD_IMAP]; ip = imap_ip; port = imap_port;
+		} else if (strcasecmp(*proto, "imaps") == 0) {
+			fd = &mail_fd[FD_IMAPS]; ip = imaps_ip; port = imaps_port;
+		} else if (strcasecmp(*proto, "pop3") == 0) {
+			fd = &mail_fd[FD_POP3]; ip = pop3_ip; port = pop3_port;
+		} else if (strcasecmp(*proto, "pop3s") == 0) {
+			fd = &mail_fd[FD_POP3S]; ip = pop3s_ip; port = pop3s_port;
+		} else {
+			i_fatal("Unknown protocol %s", *proto);
+		}
 
-#ifdef HAVE_SSL
-	imaps_fd = set_ssl_disable || set_imaps_port == 0 ? dup(null_fd) :
-		net_listen(imaps_ip, &set_imaps_port);
-#else
-	imaps_fd = dup(null_fd);
-#endif
-	if (imaps_fd == -1)
-		i_fatal("listen(%d) failed: %m", set_imaps_port);
-	fd_close_on_exec(imaps_fd, TRUE);
+		if (*fd != -1)
+			i_fatal("Protocol %s given more than once", *proto);
+
+		*fd = port == 0 ? dup(null_fd) : net_listen(ip, &port);
+		if (*fd == -1)
+			i_fatal("listen(%d) failed: %m", port);
+		fd_close_on_exec(*fd, TRUE);
+	}
+
+	for (i = 0; i < FD_MAX; i++) {
+		if (mail_fd[i] == -1) {
+			mail_fd[i] = dup(null_fd);
+			if (mail_fd[i] == -1)
+				i_fatal("dup(mail_fd[%d]) failed: %m", i);
+			fd_close_on_exec(mail_fd[i], TRUE);
+		}
+	}
 }
 
 static void open_logfile(void)
 {
-	if (set_log_path == NULL)
-		i_set_failure_syslog("imap-master", LOG_NDELAY, LOG_MAIL);
+	if (set->log_path == NULL)
+		i_set_failure_syslog("dovecot", LOG_NDELAY, LOG_MAIL);
 	else {
 		/* log to file or stderr */
-		i_set_failure_file(set_log_path, "imap-master");
+		i_set_failure_file(set->log_path, "dovecot");
 	}
 
-	if (set_info_log_path != NULL)
-		i_set_info_file(set_info_log_path);
+	if (set->info_log_path != NULL)
+		i_set_info_file(set->info_log_path);
 
-	i_set_failure_timestamp_format(set_log_timestamp);
+	i_set_failure_timestamp_format(set->log_timestamp);
 
 	i_info("Dovecot starting up");
 }
@@ -256,6 +319,8 @@
 
 static void main_deinit(void)
 {
+	int i;
+
         if (lib_signal_kill != 0)
 		i_warning("Killed with signal %d", lib_signal_kill);
 
@@ -270,10 +335,11 @@
 
 	if (close(null_fd) < 0)
 		i_error("close(null_fd) failed: %m");
-	if (close(imap_fd) < 0)
-		i_error("close(imap_fd) failed: %m");
-	if (close(imaps_fd) < 0)
-		i_error("close(imaps_fd) failed: %m");
+
+	for (i = 0; i < FD_MAX; i++) {
+		if (close(mail_fd[i]) < 0)
+			i_error("close(mail_fd[%d]) failed: %m", i);
+	}
 
 	hash_destroy(pids);
 	closelog();
@@ -296,7 +362,7 @@
 
 static void print_help(void)
 {
-	printf("Usage: imap-master [-F] [-c <config file>]\n");
+	printf("Usage: dovecot [-F] [-c <config file>]\n");
 }
 
 int main(int argc, char *argv[])
--- a/src/master/master-login-interface.h	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/master-login-interface.h	Thu Jan 30 19:59:31 2003 +0200
@@ -4,8 +4,8 @@
 #include "network.h"
 
 #define LOGIN_MASTER_SOCKET_FD 0
-#define LOGIN_IMAP_LISTEN_FD 1
-#define LOGIN_IMAPS_LISTEN_FD 2
+#define LOGIN_LISTEN_FD 1
+#define LOGIN_SSL_LISTEN_FD 2
 
 struct master_login_request {
 	unsigned int tag;
--- a/src/master/settings.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/settings.c	Thu Jan 30 19:59:31 2003 +0200
@@ -7,6 +7,7 @@
 #include "settings.h"
 
 #include <stdio.h>
+#include <stddef.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <pwd.h>
@@ -17,157 +18,224 @@
 	SET_BOOL
 };
 
-struct setting {
+struct setting_def {
+	enum setting_type type;
 	const char *name;
-	enum setting_type type;
-	void *ptr;
+	size_t offset;
 };
 
-static struct setting settings[] = {
-	{ "base_dir",		SET_STR, &set_base_dir },
-	{ "log_path",		SET_STR, &set_log_path },
-	{ "info_log_path",	SET_STR, &set_info_log_path },
-	{ "log_timestamp",	SET_STR, &set_log_timestamp },
+#define DEF(type, name) \
+	{ type, #name, offsetof(struct settings, name) }
+
+static struct setting_def setting_defs[] = {
+	/* common */
+	DEF(SET_STR, base_dir),
+	DEF(SET_STR, log_path),
+	DEF(SET_STR, info_log_path),
+	DEF(SET_STR, log_timestamp),
+
+	/* general */
+	DEF(SET_STR, protocols),
+	DEF(SET_STR, imap_listen),
+	DEF(SET_STR, imaps_listen),
+	DEF(SET_STR, pop3_listen),
+	DEF(SET_STR, pop3s_listen),
 
-	{ "imap_port",		SET_INT, &set_imap_port },
-	{ "imaps_port",		SET_INT, &set_imaps_port },
-	{ "imap_listen",	SET_STR, &set_imap_listen },
-	{ "imaps_listen",	SET_STR, &set_imaps_listen },
-	{ "ssl_disable",	SET_BOOL,&set_ssl_disable, },
-	{ "ssl_cert_file",	SET_STR, &set_ssl_cert_file },
-	{ "ssl_key_file",	SET_STR, &set_ssl_key_file },
-	{ "ssl_parameters_file",SET_STR, &set_ssl_parameters_file },
-	{ "ssl_parameters_regenerate",
-				SET_INT, &set_ssl_parameters_regenerate },
-	{ "disable_plaintext_auth",
-				SET_BOOL,&set_disable_plaintext_auth },
+	DEF(SET_BOOL, ssl_disable),
+	DEF(SET_STR, ssl_cert_file),
+	DEF(SET_STR, ssl_key_file),
+	DEF(SET_STR, ssl_parameters_file),
+	DEF(SET_STR, ssl_parameters_regenerate),
+	DEF(SET_BOOL, disable_plaintext_auth),
 
-	{ "login_executable",	SET_STR, &set_login_executable },
-	{ "login_user",		SET_STR, &set_login_user },
-	{ "login_process_size",	SET_INT, &set_login_process_size },
-	{ "login_dir",		SET_STR, &set_login_dir },
-	{ "login_chroot",	SET_BOOL,&set_login_chroot },
-	{ "login_process_per_connection",
-				SET_BOOL,&set_login_process_per_connection },
-	{ "login_processes_count",
-				SET_INT, &set_login_processes_count },
-	{ "max_logging_users",	SET_INT, &set_max_logging_users },
+	/* login */
+	DEF(SET_STR, login_dir),
+	DEF(SET_BOOL, login_chroot),
+
+	/* mail */
+	DEF(SET_STR, valid_chroot_dirs),
+	DEF(SET_INT, max_mail_processes),
+	DEF(SET_BOOL, verbose_proctitle),
+
+	DEF(SET_INT, first_valid_uid),
+	DEF(SET_INT, last_valid_uid),
+	DEF(SET_INT, first_valid_gid),
+	DEF(SET_INT, last_valid_gid),
 
-	{ "imap_executable",	SET_STR, &set_imap_executable },
-	{ "imap_process_size",	SET_INT, &set_imap_process_size },
-	{ "valid_chroot_dirs",	SET_STR, &set_valid_chroot_dirs },
-	{ "max_imap_processes",	SET_INT, &set_max_imap_processes },
-	{ "verbose_proctitle",	SET_BOOL,&set_verbose_proctitle },
-	{ "first_valid_uid",	SET_INT, &set_first_valid_uid },
-	{ "last_valid_uid",	SET_INT, &set_last_valid_uid },
-	{ "first_valid_gid",	SET_INT, &set_first_valid_gid },
-	{ "last_valid_gid",	SET_INT, &set_last_valid_gid },
-	{ "default_mail_env",	SET_STR, &set_default_mail_env },
-	{ "mail_cache_fields",	SET_STR, &set_mail_cache_fields },
-	{ "mail_never_cache_fields",
-				SET_STR, &set_mail_never_cache_fields },
-	{ "mailbox_check_interval",
-				SET_INT, &set_mailbox_check_interval },
-	{ "mail_save_crlf",	SET_BOOL,&set_mail_save_crlf },
-	{ "mail_read_mmaped",	SET_BOOL,&set_mail_read_mmaped },
-	{ "maildir_copy_with_hardlinks",
-				SET_BOOL,&set_maildir_copy_with_hardlinks },
-	{ "maildir_check_content_changes",
-				SET_BOOL,&set_maildir_check_content_changes },
-	{ "mbox_locks",		SET_STR, &set_mbox_locks, },
-	{ "mbox_read_dotlock",	SET_BOOL,&set_mbox_read_dotlock, },
-	{ "mbox_lock_timeout",	SET_INT, &set_mbox_lock_timeout, },
-	{ "mbox_dotlock_change_timeout",
-				SET_INT, &set_mbox_dotlock_change_timeout, },
-	{ "overwrite_incompatible_index",
-				SET_BOOL,&set_overwrite_incompatible_index },
-	{ "umask",		SET_INT, &set_umask },
+	DEF(SET_STR, default_mail_env),
+	DEF(SET_STR, mail_cache_fields),
+	DEF(SET_STR, mail_never_cache_fields),
+	DEF(SET_STR, mailbox_check_interval),
+	DEF(SET_STR, mail_save_crlf),
+	DEF(SET_STR, mail_read_mmaped),
+	DEF(SET_STR, maildir_copy_with_hardlinks),
+	DEF(SET_STR, maildir_check_content_changes),
+	DEF(SET_STR, mbox_locks),
+	DEF(SET_STR, mbox_read_dotlock),
+	DEF(SET_STR, mbox_lock_timeout),
+	DEF(SET_STR, mbox_dotlock_change_timeout),
+	DEF(SET_STR, overwrite_incompatible_index),
+	DEF(SET_STR, umask),
+
+	/* imap */
+	DEF(SET_STR, imap_executable),
+	DEF(SET_INT, imap_process_size),
 
-	{ NULL, 0, NULL }
+	/* pop3 */
+	DEF(SET_STR, pop3_executable),
+	DEF(SET_INT, pop3_process_size),
+
+	{ 0, NULL, 0 }
+};
+
+#undef DEF
+#define DEF(type, name) \
+	{ type, #name, offsetof(struct login_settings, name) }
+
+static struct setting_def login_setting_defs[] = {
+	DEF(SET_STR, executable),
+	DEF(SET_STR, user),
+
+	DEF(SET_BOOL, process_per_connection),
+
+	DEF(SET_INT, process_size),
+	DEF(SET_INT, processes_count),
+	DEF(SET_INT, max_processes_count),
+	DEF(SET_INT, max_logging_users),
+
+	{ 0, NULL, 0 }
 };
 
-/* common */
-char *set_base_dir = PKG_RUNDIR;
-char *set_log_path = NULL;
-char *set_info_log_path = NULL;
-char *set_log_timestamp = DEFAULT_FAILURE_STAMP_FORMAT;
+#undef DEF
+#define DEF(type, name) \
+	{ type, #name, offsetof(struct auth_settings, name) }
 
-/* general */
-unsigned int set_imap_port = 143;
-unsigned int set_imaps_port = 993;
-char *set_imap_listen = "*";
-char *set_imaps_listen = NULL;
+static struct setting_def auth_setting_defs[] = {
+	DEF(SET_STR, mechanisms),
+	DEF(SET_STR, realms),
+	DEF(SET_STR, userdb),
+	DEF(SET_STR, passdb),
+	DEF(SET_STR, executable),
+	DEF(SET_STR, user),
+	DEF(SET_STR, chroot),
+
+	DEF(SET_BOOL, use_cyrus_sasl),
+	DEF(SET_BOOL, verbose),
+
+	DEF(SET_INT, count),
+	DEF(SET_INT, process_size),
+
+	{ 0, NULL, 0 }
+};
 
-int set_ssl_disable = FALSE;
-char *set_ssl_cert_file = SSLDIR"/certs/imapd.pem";
-char *set_ssl_key_file = SSLDIR"/private/imapd.pem";
-char *set_ssl_parameters_file = "ssl-parameters.dat";
-unsigned int set_ssl_parameters_regenerate = 24;
-int set_disable_plaintext_auth = FALSE;
+struct settings default_settings = {
+	/* common */
+	MEMBER(base_dir) PKG_RUNDIR,
+	MEMBER(log_path) NULL,
+	MEMBER(info_log_path) NULL,
+	MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT,
+
+	/* general */
+	MEMBER(protocols) "imap imaps",
+	MEMBER(imap_listen) "*",
+	MEMBER(imaps_listen) NULL,
+	MEMBER(pop3_listen) "*",
+	MEMBER(pop3s_listen) NULL,
 
-/* login */
-char *set_login_executable = PKG_LIBEXECDIR"/imap-login";
-unsigned int set_login_process_size = 16;
-char *set_login_user = "imapd";
-char *set_login_dir = "login";
+	MEMBER(ssl_disable) FALSE,
+	MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
+	MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem",
+	MEMBER(ssl_parameters_file) "ssl-parameters.dat",
+	MEMBER(ssl_parameters_regenerate) 24,
+	MEMBER(disable_plaintext_auth) FALSE,
 
-int set_login_chroot = TRUE;
-int set_login_process_per_connection = TRUE;
-unsigned int set_login_processes_count = 3;
-unsigned int set_login_max_processes_count = 128;
-unsigned int set_max_logging_users = 256;
+	/* login */
+	MEMBER(login_dir) "login",
+	MEMBER(login_chroot) TRUE,
 
-uid_t set_login_uid; /* generated from set_login_user */
-gid_t set_login_gid; /* generated from set_login_user */
+	/* mail */
+	MEMBER(valid_chroot_dirs) NULL,
+	MEMBER(max_mail_processes) 1024,
+	MEMBER(verbose_proctitle) FALSE,
 
-/* imap */
-char *set_imap_executable = PKG_LIBEXECDIR"/imap";
-unsigned int set_imap_process_size = 256;
-char *set_valid_chroot_dirs = NULL;
-unsigned int set_max_imap_processes = 1024;
-int set_verbose_proctitle = FALSE;
+	MEMBER(first_valid_uid) 500,
+	MEMBER(last_valid_uid) 0,
+	MEMBER(first_valid_gid) 1,
+	MEMBER(last_valid_gid) 0,
 
-unsigned int set_first_valid_uid = 500, set_last_valid_uid = 0;
-unsigned int set_first_valid_gid = 1, set_last_valid_gid = 0;
+	MEMBER(default_mail_env) NULL,
+	MEMBER(mail_cache_fields) "MessagePart",
+	MEMBER(mail_never_cache_fields) NULL,
+	MEMBER(mailbox_check_interval) 0,
+	MEMBER(mail_save_crlf) FALSE,
+	MEMBER(mail_read_mmaped) FALSE,
+	MEMBER(maildir_copy_with_hardlinks) FALSE,
+	MEMBER(maildir_check_content_changes) FALSE,
+	MEMBER(mbox_locks) "dotlock fcntl flock",
+	MEMBER(mbox_read_dotlock) FALSE,
+	MEMBER(mbox_lock_timeout) 300,
+	MEMBER(mbox_dotlock_change_timeout) 30,
+	MEMBER(overwrite_incompatible_index) FALSE,
+	MEMBER(umask) 0077,
+
+	/* imap */
+	MEMBER(imap_executable) PKG_LIBEXECDIR"/imap",
+	MEMBER(imap_process_size) 256,
+
+	/* pop3 */
+	MEMBER(pop3_executable) PKG_LIBEXECDIR"/pop3",
+	MEMBER(pop3_process_size) 256,
 
-char *set_default_mail_env = NULL;
-char *set_mail_cache_fields = "MessagePart";
-char *set_mail_never_cache_fields = NULL;
-unsigned int set_mailbox_check_interval = 0;
-int set_mail_save_crlf = FALSE;
-int set_mail_read_mmaped = FALSE;
-int set_maildir_copy_with_hardlinks = FALSE;
-int set_maildir_check_content_changes = FALSE;
-char *set_mbox_locks = "dotlock fcntl flock";
-int set_mbox_read_dotlock = FALSE;
-unsigned int set_mbox_lock_timeout = 300;
-unsigned int set_mbox_dotlock_change_timeout = 30;
-int set_overwrite_incompatible_index = FALSE;
-unsigned int set_umask = 0077;
+	MEMBER(login_gid) 0,
+	MEMBER(auths) NULL,
+	MEMBER(logins) NULL
+};
+
+struct login_settings default_login_settings = {
+	MEMBER(next) NULL,
+	MEMBER(name) NULL,
+
+	MEMBER(executable) NULL,
+	MEMBER(user) "dovecot",
+
+	MEMBER(process_per_connection) TRUE,
 
-/* auth */
-struct auth_config *auth_processes_config = NULL;
+	MEMBER(process_size) 16,
+	MEMBER(processes_count) 3,
+	MEMBER(max_processes_count) 128,
+	MEMBER(max_logging_users) 256,
 
-static void fix_base_path(char **str)
+	MEMBER(uid) 0 /* generated */
+};
+
+static pool_t settings_pool;
+struct settings *set = NULL;
+
+static void fix_base_path(struct settings *set, const char **str)
 {
-	char *fullpath;
-
 	if (*str != NULL && **str != '\0' && **str != '/') {
-		fullpath = i_strconcat(set_base_dir, "/", *str, NULL);
-		i_free(*str);
-		*str = i_strdup(fullpath);
+		*str = p_strconcat(settings_pool,
+				   set->base_dir, "/", *str, NULL);
 	}
 }
 
-static void get_login_uid(void)
+static void get_login_uid(struct settings *set,
+			  struct login_settings *login_set)
 {
 	struct passwd *pw;
 
-	if ((pw = getpwnam(set_login_user)) == NULL)
-		i_fatal("Login user doesn't exist: %s", set_login_user);
+	if ((pw = getpwnam(login_set->user)) == NULL)
+		i_fatal("Login user doesn't exist: %s", login_set->user);
 
-	set_login_uid = pw->pw_uid;
-	set_login_gid = pw->pw_gid;
+	if (set->login_gid == 0)
+		set->login_gid = pw->pw_gid;
+	else if (set->login_gid != pw->pw_gid) {
+		i_fatal("All login process users must belong to same group "
+			"(%s vs %s)", dec2str(set->login_gid),
+			dec2str(pw->pw_gid));
+	}
+
+	login_set->uid = pw->pw_uid;
 }
 
 static const char *get_bool(const char *value, int *result)
@@ -182,22 +250,37 @@
 	return NULL;
 }
 
-static void auth_settings_verify(void)
+static const char *get_uint(const char *value, unsigned int *result)
 {
-	struct auth_config *auth;
+	int num;
+
+	if (!sscanf(value, "%i", &num) || num < 0)
+		return t_strconcat("Invalid number: ", value, NULL);
+	*result = num;
+	return NULL;
+}
+
+static void auth_settings_verify(struct auth_settings *auth)
+{
+	if (access(auth->executable, X_OK) < 0)
+		i_fatal("Can't use auth executable %s: %m", auth->executable);
 
-	for (auth = auth_processes_config; auth != NULL; auth = auth->next) {
-		if (access(auth->executable, X_OK) < 0) {
-			i_fatal("Can't use auth executable %s: %m",
-				auth->executable);
-		}
+	fix_base_path(set, &auth->chroot);
+	if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) {
+		i_fatal("Can't access auth chroot directory %s: %m",
+			auth->chroot);
+	}
+}
 
-		fix_base_path(&auth->chroot);
-		if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) {
-			i_fatal("Can't access auth chroot directory %s: %m",
-				auth->chroot);
-		}
-	}
+static void login_settings_verify(struct login_settings *login)
+{
+	if (access(login->executable, X_OK) < 0)
+		i_fatal("Can't use login executable %s: %m", login->executable);
+
+	if (login->processes_count < 1)
+		i_fatal("login_processes_count must be at least 1");
+	if (login->max_logging_users < 1)
+		i_fatal("max_logging_users must be at least 1");
 }
 
 static const char *get_directory(const char *path)
@@ -214,86 +297,91 @@
 	}
 }
 
-static void settings_verify(void)
+static void settings_verify(struct settings *set)
 {
+	struct login_settings *login;
+	struct auth_settings *auth;
 	const char *const *str;
 	const char *dir;
 	int dotlock_got, fcntl_got, flock_got;
 
-	get_login_uid();
-
-	if (access(set_login_executable, X_OK) < 0) {
-		i_fatal("Can't use login executable %s: %m",
-			set_login_executable);
+	for (login = set->logins; login != NULL; login = login->next) {
+		get_login_uid(set, login);
+		login_settings_verify(login);
 	}
 
-	if (access(set_imap_executable, X_OK) < 0) {
-		i_fatal("Can't use imap executable %s: %m",
-			set_imap_executable);
+	if (strstr(set->protocols, "imap") != NULL) {
+		if (access(set->imap_executable, X_OK) < 0) {
+			i_fatal("Can't use imap executable %s: %m",
+				set->imap_executable);
+		}
 	}
 
-	if (set_log_path != NULL) {
-		dir = get_directory(set_log_path);
+	if (strstr(set->protocols, "pop3") != NULL) {
+		if (access(set->pop3_executable, X_OK) < 0) {
+			i_fatal("Can't use pop3 executable %s: %m",
+				set->pop3_executable);
+		}
+	}
+
+	if (set->log_path != NULL) {
+		dir = get_directory(set->log_path);
 		if (access(dir, W_OK) < 0)
 			i_fatal("Can't access log directory %s: %m", dir);
 	}
 
-	if (set_info_log_path != NULL) {
-		dir = get_directory(set_info_log_path);
+	if (set->info_log_path != NULL) {
+		dir = get_directory(set->info_log_path);
 		if (access(dir, W_OK) < 0)
 			i_fatal("Can't access info log directory %s: %m", dir);
 	}
 
 #ifdef HAVE_SSL
-	if (!set_ssl_disable) {
-		if (access(set_ssl_cert_file, R_OK) < 0) {
+	if (!set->ssl_disable) {
+		if (access(set->ssl_cert_file, R_OK) < 0) {
 			i_fatal("Can't use SSL certificate %s: %m",
-				set_ssl_cert_file);
+				set->ssl_cert_file);
 		}
 
-		if (access(set_ssl_key_file, R_OK) < 0) {
+		if (access(set->ssl_key_file, R_OK) < 0) {
 			i_fatal("Can't use SSL key file %s: %m",
-				set_ssl_key_file);
+				set->ssl_key_file);
 		}
 	}
 #endif
 
 	/* fix relative paths */
-	fix_base_path(&set_ssl_parameters_file);
-	fix_base_path(&set_login_dir);
+	fix_base_path(set, &set->ssl_parameters_file);
+	fix_base_path(set, &set->login_dir);
 
 	/* since they're under /var/run by default, they may have been
 	   deleted. */
-	if (safe_mkdir(set_base_dir, 0700, geteuid(), getegid()) == 0) {
+	if (safe_mkdir(set->base_dir, 0700, geteuid(), getegid()) == 0) {
 		i_warning("Corrected permissions for base directory %s",
 			  PKG_RUNDIR);
 	}
 
 	/* wipe out contents of login directory, if it exists */
-	if (unlink_directory(set_login_dir, FALSE) < 0)
-		i_fatal("unlink_directory() failed for %s: %m", set_login_dir);
+	if (unlink_directory(set->login_dir, FALSE) < 0)
+		i_fatal("unlink_directory() failed for %s: %m", set->login_dir);
 
-	if (safe_mkdir(set_login_dir, 0750, geteuid(), set_login_gid) == 0) {
+	if (safe_mkdir(set->login_dir, 0750, geteuid(), set->login_gid) == 0) {
 		i_warning("Corrected permissions for login directory %s",
-			  set_login_dir);
+			  set->login_dir);
 	}
 
-	if (set_max_imap_processes < 1)
-		i_fatal("max_imap_processes must be at least 1");
-	if (set_login_processes_count < 1)
-		i_fatal("login_processes_count must be at least 1");
-	if (set_max_logging_users < 1)
-		i_fatal("max_logging_users must be at least 1");
+	if (set->max_mail_processes < 1)
+		i_fatal("max_mail_processes must be at least 1");
 
-	if (set_last_valid_uid != 0 &&
-	    set_first_valid_uid > set_last_valid_uid)
+	if (set->last_valid_uid != 0 &&
+	    set->first_valid_uid > set->last_valid_uid)
 		i_fatal("first_valid_uid can't be larger than last_valid_uid");
-	if (set_last_valid_gid != 0 &&
-	    set_first_valid_gid > set_last_valid_gid)
+	if (set->last_valid_gid != 0 &&
+	    set->first_valid_gid > set->last_valid_gid)
 		i_fatal("first_valid_gid can't be larger than last_valid_gid");
 
 	dotlock_got = fcntl_got = flock_got = FALSE;
-	for (str = t_strsplit(set_mbox_locks, " "); *str != NULL; str++) {
+	for (str = t_strsplit(set->mbox_locks, " "); *str != NULL; str++) {
 		if (strcasecmp(*str, "dotlock") == 0)
 			dotlock_got = TRUE;
 		else if (strcasecmp(*str, "fcntl") == 0)
@@ -315,189 +403,140 @@
 	if (!dotlock_got && !fcntl_got && !flock_got)
 		i_fatal("mbox_locks: No mbox locking methods selected");
 
-	if (dotlock_got && !set_mbox_read_dotlock && !fcntl_got && !flock_got) {
+	if (dotlock_got && !set->mbox_read_dotlock &&
+	    !fcntl_got && !flock_got) {
 		i_warning("mbox_locks: Only dotlock selected, forcing "
 			  "mbox_read_dotlock = yes to avoid corruption.");
-                set_mbox_read_dotlock = TRUE;
+                set->mbox_read_dotlock = TRUE;
 	}
 
-	auth_settings_verify();
+	for (auth = set->auths; auth != NULL; auth = auth->next)
+		auth_settings_verify(auth);
 }
 
-static struct auth_config *auth_config_new(const char *name)
+static void auth_settings_new(struct settings *set, const char *name)
 {
-	struct auth_config *auth;
+	struct auth_settings *auth;
 
-	auth = i_new(struct auth_config, 1);
-	auth->name = i_strdup(name);
-	auth->executable = i_strdup(PKG_LIBEXECDIR"/imap-auth");
+	auth = p_new(settings_pool, struct auth_settings, 1);
+	auth->name = p_strdup(settings_pool, name);
+	auth->executable = p_strdup(settings_pool,
+				    PKG_LIBEXECDIR"/dovecot-auth");
 	auth->count = 1;
 
-	auth->next = auth_processes_config;
-        auth_processes_config = auth;
-	return auth;
+	auth->next = set->auths;
+        set->auths = auth;
 }
 
-static void auth_config_free(struct auth_config *auth)
+static const char *parse_new_auth(struct settings *set, const char *name)
 {
-	i_free(auth->name);
-	i_free(auth->mechanisms);
-	i_free(auth->realms);
-	i_free(auth->userdb);
-	i_free(auth->userdb_args);
-	i_free(auth->passdb);
-	i_free(auth->passdb_args);
-	i_free(auth->executable);
-	i_free(auth->user);
-	i_free(auth->chroot);
-	i_free(auth);
-}
-
-static const char *parse_new_auth(const char *name)
-{
-	struct auth_config *auth;
+	struct auth_settings *auth;
 
 	if (strchr(name, '/') != NULL)
 		return "Authentication process name must not contain '/'";
 
-	for (auth = auth_processes_config; auth != NULL; auth = auth->next) {
+	for (auth = set->auths; auth != NULL; auth = auth->next) {
 		if (strcmp(auth->name, name) == 0) {
 			return "Authentication process already exists "
 				"with the same name";
 		}
 	}
 
-	(void)auth_config_new(name);
+	auth_settings_new(set, name);
 	return NULL;
 }
 
-static const char *parse_auth(const char *key, const char *value)
+static void login_settings_new(struct settings *set, const char *name)
 {
-	struct auth_config *auth = auth_processes_config;
-	const char *p;
-	char **ptr;
+	struct login_settings *login;
 
-	if (auth == NULL)
-		return "Authentication process name not defined yet";
+	login = p_new(settings_pool, struct login_settings, 1);
 
-	/* check the easy string values first */
-	if (strcmp(key, "auth_mechanisms") == 0)
-		ptr = &auth->mechanisms;
-	else if (strcmp(key, "auth_realms") == 0)
-		ptr = &auth->realms;
-	else if (strcmp(key, "auth_executable") == 0)
-		ptr = &auth->executable;
-	else if (strcmp(key, "auth_user") == 0)
-		ptr = &auth->user;
-	else if (strcmp(key, "auth_chroot") == 0)
-		ptr = &auth->chroot;
-	else
-		ptr = NULL;
+	/* copy defaults */
+	*login = set->logins != NULL ? *set->logins :
+		default_login_settings;
 
-	if (ptr != NULL) {
-		i_free(*ptr);
-		*ptr = i_strdup(value);
-		return NULL;
-	}
-
-	if (strcmp(key, "auth_userdb") == 0) {
-		/* split it into userdb + userdb_args */
-		for (p = value; *p != ' ' && *p != '\0'; )
-			p++;
-
-		i_free(auth->userdb);
-		auth->userdb = i_strdup_until(value, p);
-
-		while (*p == ' ') p++;
-
-		i_free(auth->userdb_args);
-		auth->userdb_args = i_strdup(p);
-		return NULL;
+	if (strcasecmp(name, "imap") == 0) {
+		login->name = "imap";
+		login->executable = PKG_LIBEXECDIR"/imap-login";
+	} else if (strcasecmp(name, "pop3") == 0) {
+		login->name = "pop3";
+		login->executable = PKG_LIBEXECDIR"/pop3-login";
+	} else {
+		i_fatal("Unknown login process type '%s'", name);
 	}
 
-	if (strcmp(key, "auth_passdb") == 0) {
-		/* split it into passdb + passdb_args */
-		for (p = value; *p != ' ' && *p != '\0'; )
-			p++;
+	login->next = set->logins;
+	set->logins = login;
+}
 
-		i_free(auth->passdb);
-		auth->passdb = i_strdup_until(value, p);
+static const char *parse_new_login(struct settings *set, const char *name)
+{
+	struct login_settings *login;
 
-		while (*p == ' ') p++;
-
-		i_free(auth->passdb_args);
-		auth->passdb_args = i_strdup(p);
-		return NULL;
+	for (login = set->logins; login != NULL; login = login->next) {
+		if (strcmp(login->name, name) == 0) {
+			return "Login process already exists "
+				"with the same name";
+		}
 	}
 
-	if (strcmp(key, "auth_cyrus_sasl") == 0)
-		return get_bool(value, &auth->use_cyrus_sasl);
-
-	if (strcmp(key, "auth_verbose") == 0)
-		return get_bool(value, &auth->verbose);
-
-	if (strcmp(key, "auth_count") == 0) {
-		int num;
-
-		if (!sscanf(value, "%i", &num) || num < 0)
-			return t_strconcat("Invalid number: ", value, NULL);
-                auth->count = num;
-		return NULL;
-	}
-
-	if (strcmp(key, "auth_process_size") == 0) {
-		int num;
-
-		if (!sscanf(value, "%i", &num) || num < 0)
-			return t_strconcat("Invalid number: ", value, NULL);
-                auth->process_size = num;
-		return NULL;
-	}
-
-	return t_strconcat("Unknown setting: ", key, NULL);
+	login_settings_new(set, name);
+	return NULL;
 }
 
-static const char *parse_setting(const char *key, const char *value)
+static const char *
+parse_setting_from_defs(struct setting_def *defs, void *base,
+			const char *key, const char *value)
 {
-	struct setting *set;
+	struct setting_def *def;
 
-	if (strcmp(key, "auth") == 0)
-		return parse_new_auth(value);
-	if (strncmp(key, "auth_", 5) == 0)
-		return parse_auth(key, value);
+	for (def = defs; def->name != NULL; def++) {
+		if (strcmp(def->name, key) == 0) {
+			void *ptr = STRUCT_MEMBER_P(base, def->offset);
 
-	for (set = settings; set->name != NULL; set++) {
-		if (strcmp(set->name, key) == 0) {
-			switch (set->type) {
+			switch (def->type) {
 			case SET_STR:
-				i_free(*((char **)set->ptr));
-				*((char **)set->ptr) = i_strdup_empty(value);
-				break;
+				*((char **) ptr) =
+					p_strdup_empty(settings_pool, value);
+				return NULL;
 			case SET_INT:
 				/* use %i so we can handle eg. 0600
 				   as octal value with umasks */
-				if (!sscanf(value, "%i", (int *) set->ptr))
-					return t_strconcat("Invalid number: ",
-							   value, NULL);
-				break;
+				return get_uint(value, (unsigned int *) ptr);
 			case SET_BOOL:
-				return get_bool(value, set->ptr);
+				return get_bool(value, (int *) ptr);
 			}
-			return NULL;
 		}
 	}
 
 	return t_strconcat("Unknown setting: ", key, NULL);
 }
 
-static void settings_free(void)
+static const char *parse_setting(struct settings *set,
+				 const char *key, const char *value)
 {
-	while (auth_processes_config != NULL) {
-		struct auth_config *auth = auth_processes_config;
+	if (strcmp(key, "auth") == 0)
+		return parse_new_auth(set, value);
+	if (strncmp(key, "auth_", 5) == 0) {
+		if (set->auths == NULL)
+			return "Authentication process name not defined yet";
+
+		return parse_setting_from_defs(auth_setting_defs,
+					       set->auths, key + 5, value);
+	}
 
-		auth_processes_config = auth->next;
-                auth_config_free(auth);
+	if (strcmp(key, "login") == 0)
+		return parse_new_login(set, value);
+	if (strncmp(key, "login_", 6) == 0) {
+		if (set->logins == NULL)
+			return "Login process name not defined yet";
+
+		return parse_setting_from_defs(login_setting_defs,
+					       set->logins, key + 6, value);
 	}
+
+	return parse_setting_from_defs(setting_defs, set, key, value);
 }
 
 #define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
@@ -509,7 +548,9 @@
 	char *line, *key, *p;
 	int fd, linenum;
 
-	settings_free();
+	p_clear(settings_pool);
+	set = p_new(settings_pool, struct settings, 1);
+	*set = default_settings;
 
 	fd = open(path, O_RDONLY);
 	if (fd < 0)
@@ -558,7 +599,7 @@
 				p--;
 			*p = '\0';
 
-			errormsg = parse_setting(key, line);
+			errormsg = parse_setting(set, key, line);
 		}
 
 		if (errormsg != NULL) {
@@ -569,18 +610,10 @@
 
 	i_stream_unref(input);
 
-        settings_verify();
+        settings_verify(set);
 }
 
 void settings_init(void)
 {
-	struct setting *set;
-
-	/* strdup() all default settings */
-	for (set = settings; set->name != NULL; set++) {
-		if (set->type == SET_STR) {
-			char **str = set->ptr;
-			*str = i_strdup(*str);
-		}
-	}
+	settings_pool = pool_alloconly_create("settings", 1024);
 }
--- a/src/master/settings.h	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/settings.h	Thu Jan 30 19:59:31 2003 +0200
@@ -1,76 +1,97 @@
 #ifndef __SETTINGS_H
 #define __SETTINGS_H
 
-/* common */
-extern char *set_base_dir;
-extern char *set_log_path;
-extern char *set_info_log_path;
-extern char *set_log_timestamp;
+struct settings {
+	/* common */
+	const char *base_dir;
+	const char *log_path;
+	const char *info_log_path;
+	const char *log_timestamp;
 
-/* general */
-extern unsigned int set_imap_port;
-extern unsigned int set_imaps_port;
-extern char *set_imap_listen;
-extern char *set_imaps_listen;
+	/* general */
+	const char *protocols;
+	const char *imap_listen;
+	const char *imaps_listen;
+	const char *pop3_listen;
+	const char *pop3s_listen;
 
-extern int set_ssl_disable;
-extern char *set_ssl_cert_file;
-extern char *set_ssl_key_file;
-extern char *set_ssl_parameters_file;
-extern unsigned int set_ssl_parameters_regenerate;
-extern int set_disable_plaintext_auth;
+	int ssl_disable;
+	const char *ssl_cert_file;
+	const char *ssl_key_file;
+	const char *ssl_parameters_file;
+	unsigned int ssl_parameters_regenerate;
+	int disable_plaintext_auth;
 
-/* login */
-extern char *set_login_executable;
-extern char *set_login_user;
-extern unsigned int set_login_process_size;
-extern char *set_login_dir;
-extern int set_login_chroot;
-extern int set_login_process_per_connection;
-extern unsigned int set_login_processes_count;
-extern unsigned int set_login_max_processes_count;
-extern unsigned int set_max_logging_users;
+	/* login */
+	const char *login_dir;
+	int login_chroot;
 
-extern uid_t set_login_uid;
-extern gid_t set_login_gid;
+	/* mail */
+	const char *valid_chroot_dirs;
+	unsigned int max_mail_processes;
+	int verbose_proctitle;
+
+	unsigned int first_valid_uid, last_valid_uid;
+	unsigned int first_valid_gid, last_valid_gid;
 
-/* imap */
-extern char *set_imap_executable;
-extern unsigned int set_imap_process_size;
-extern char *set_valid_chroot_dirs;
-extern unsigned int set_max_imap_processes;
-extern int set_verbose_proctitle;
+	const char *default_mail_env;
+	const char *mail_cache_fields;
+	const char *mail_never_cache_fields;
+	unsigned int mailbox_check_interval;
+	int mail_save_crlf;
+	int mail_read_mmaped;
+	int maildir_copy_with_hardlinks;
+	int maildir_check_content_changes;
+	char *mbox_locks;
+	int mbox_read_dotlock;
+	unsigned int mbox_lock_timeout;
+	unsigned int mbox_dotlock_change_timeout;
+	int overwrite_incompatible_index;
+	unsigned int umask;
 
-extern unsigned int set_first_valid_uid, set_last_valid_uid;
-extern unsigned int set_first_valid_gid, set_last_valid_gid;
+	/* imap */
+	const char *imap_executable;
+	unsigned int imap_process_size;
+
+	/* imap */
+	const char *pop3_executable;
+	unsigned int pop3_process_size;
+
+	/* .. */
+	gid_t login_gid;
 
-extern char *set_default_mail_env;
-extern char *set_mail_cache_fields;
-extern char *set_mail_never_cache_fields;
-extern unsigned int set_mailbox_check_interval;
-extern int set_mail_save_crlf;
-extern int set_mail_read_mmaped;
-extern int set_maildir_copy_with_hardlinks;
-extern int set_maildir_check_content_changes;
-extern char *set_mbox_locks;
-extern int set_mbox_read_dotlock;
-extern unsigned int set_mbox_lock_timeout;
-extern unsigned int set_mbox_dotlock_change_timeout;
-extern int set_overwrite_incompatible_index;
-extern unsigned int set_umask;
+	struct auth_settings *auths;
+	struct login_settings *logins;
+};
+
+struct login_settings {
+	struct login_settings *next;
+
+	const char *name;
+	const char *executable;
+	const char *user;
+
+	int process_per_connection;
 
-/* auth */
-struct auth_config {
-	struct auth_config *next;
+	unsigned int process_size;
+	unsigned int processes_count;
+	unsigned int max_processes_count;
+	unsigned int max_logging_users;
+
+	uid_t uid; /* gid must be always same with all login processes */
+};
 
-	char *name;
-	char *mechanisms;
-	char *realms;
-	char *userdb, *userdb_args;
-	char *passdb, *passdb_args;
-	char *executable;
-	char *user;
-	char *chroot;
+struct auth_settings {
+	struct auth_settings *next;
+
+	const char *name;
+	const char *mechanisms;
+	const char *realms;
+	const char *userdb;
+	const char *passdb;
+	const char *executable;
+	const char *user;
+	const char *chroot;
 
 	int use_cyrus_sasl, verbose;
 
@@ -78,7 +99,7 @@
 	unsigned int process_size;
 };
 
-extern struct auth_config *auth_processes_config;
+extern struct settings *set;
 
 void settings_read(const char *path);
 
--- a/src/master/ssl-init.c	Thu Jan 30 19:56:19 2003 +0200
+++ b/src/master/ssl-init.c	Thu Jan 30 19:59:31 2003 +0200
@@ -50,7 +50,7 @@
 
 	if (pid == 0) {
 		/* child */
-		generate_parameters_file(set_ssl_parameters_file);
+		generate_parameters_file(set->ssl_parameters_file);
 		exit(0);
 	} else {
 		/* parent */
@@ -69,13 +69,13 @@
 	struct stat st;
 	time_t regen_time;
 
-	if (set_ssl_parameters_file == NULL || set_ssl_disable || generating)
+	if (set->ssl_parameters_file == NULL || set->ssl_disable || generating)
 		return;
 
-	if (lstat(set_ssl_parameters_file, &st) < 0) {
+	if (lstat(set->ssl_parameters_file, &st) < 0) {
 		if (errno != ENOENT) {
 			i_error("lstat() failed for SSL parameters file %s: %m",
-				set_ssl_parameters_file);
+				set->ssl_parameters_file);
 			return;
 		}
 
@@ -83,7 +83,8 @@
 	}
 
 	/* make sure it's new enough and the permissions are correct */
-        regen_time = st.st_mtime + (time_t)(set_ssl_parameters_regenerate*3600);
+	regen_time = st.st_mtime +
+		(time_t)(set->ssl_parameters_regenerate*3600);
 	if (regen_time < ioloop_time || (st.st_mode & 077) != 0 ||
 	    st.st_uid != geteuid() || st.st_gid != getegid())
 		start_generate_process();