[dovecot-cvs] dovecot/src/master mail-process.c,NONE,1.1 mail-process.h,NONE,1.1 .cvsignore,1.1.1.1,1.2 Makefile.am,1.7,1.8 auth-process.c,1.30,1.31 common.h,1.11,1.12 login-process.c,1.32,1.33 main.c,1.30,1.31 master-login-interface.h,1.1,1.2 settings.c,1.44,1.45 Message-Id: <20030130175934.4E638239A3@danu.procontrol.fi>

cras at procontrol.fi cras at procontrol.fi
Thu Jan 30 19:59:34 EET 2003


Update of /home/cvs/dovecot/src/master
In directory danu:/tmp/cvs-serv27713/src/master

Modified Files:
	.cvsignore Makefile.am auth-process.c common.h login-process.c 
	main.c master-login-interface.h settings.c settings.h 
	ssl-init.c 
Added Files:
	mail-process.c mail-process.h 
Removed Files:
	imap-process.c imap-process.h 
Log Message:
Rewrote setting handling. Changed some existing settings also since POP3
support required changes anyway. POP3 seems to be really working now :)



--- NEW FILE: mail-process.c ---
/* 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--;
}

--- NEW FILE: mail-process.h ---
#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

Index: .cvsignore
===================================================================
RCS file: /home/cvs/dovecot/src/master/.cvsignore,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -d -r1.1.1.1 -r1.2
--- .cvsignore	9 Aug 2002 09:15:55 -0000	1.1.1.1
+++ .cvsignore	30 Jan 2003 17:59:31 -0000	1.2
@@ -6,4 +6,4 @@
 Makefile
 Makefile.in
 so_locations
-imap-master
+dovecot

Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/master/Makefile.am,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- Makefile.am	27 Jan 2003 01:33:40 -0000	1.7
+++ Makefile.am	30 Jan 2003 17:59:31 -0000	1.8
@@ -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

Index: auth-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/auth-process.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- auth-process.c	27 Jan 2003 02:42:02 -0000	1.30
+++ auth-process.c	30 Jan 2003 17:59:31 -0000	1.31
@@ -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);
 	}
 }
 

Index: common.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/common.h,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- common.h	27 Jan 2003 01:33:40 -0000	1.11
+++ common.h	30 Jan 2003 17:59:32 -0000	1.12
@@ -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) \

Index: login-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/login-process.c,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -d -r1.32 -r1.33
--- login-process.c	27 Jan 2003 02:05:32 -0000	1.32
+++ login-process.c	30 Jan 2003 17:59:32 -0000	1.33
@@ -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_processes_start_missing(void *context __attr_unused__)
+static void login_group_start_missings(struct login_group *group)
 {
-	if (!set_login_process_per_connection) {
+	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 (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--;
+		if (group->listening_processes < group->set->processes_count)
+			(void)create_login_process(group);
+		return;
+	}
 
-		if (wanted_processes_count > set_login_max_processes_count)
-			wanted_processes_count = set_login_max_processes_count;
+	/* 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--;
 
-		while (listening_processes < wanted_processes_count)
-			(void)create_login_process();
+	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__)
+{
+	struct login_group *group;
+	struct login_settings *login;
+
+	if (login_groups == NULL) {
+		for (login = set->logins; login != NULL; login = login->next)
+			login_group_create(login);
 	}
+
+	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);

Index: main.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/main.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- main.c	27 Jan 2003 01:44:34 -0000	1.30
+++ main.c	30 Jan 2003 17:59:32 -0000	1.31
@@ -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;
 
-#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);
+	/* 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);
+		}
+
+		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[])

Index: master-login-interface.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/master-login-interface.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- master-login-interface.h	27 Jan 2003 01:33:40 -0000	1.1
+++ master-login-interface.h	30 Jan 2003 17:59:32 -0000	1.2
@@ -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;

Index: settings.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/settings.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- settings.c	27 Jan 2003 02:42:02 -0000	1.44
+++ settings.c	30 Jan 2003 17:59:32 -0000	1.45
@@ -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 {
-	const char *name;
+struct setting_def {
 	enum setting_type type;
-	void *ptr;
+	const char *name;
+	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) }
 
-	{ "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 },
+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),
 
-	{ "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 },
+	/* 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_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_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),
 
-	{ NULL, 0, NULL }
+	/* 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),
+
+	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),
+
+	/* pop3 */
+	DEF(SET_STR, pop3_executable),
+	DEF(SET_INT, pop3_process_size),
+
+	{ 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 login_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 login_setting_defs[] = {
+	DEF(SET_STR, executable),
+	DEF(SET_STR, user),
 
-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;
+	DEF(SET_BOOL, process_per_connection),
 
-/* 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";
+	DEF(SET_INT, process_size),
+	DEF(SET_INT, processes_count),
+	DEF(SET_INT, max_processes_count),
+	DEF(SET_INT, max_logging_users),
 
-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;
+	{ 0, NULL, 0 }
+};
 
-uid_t set_login_uid; /* generated from set_login_user */
-gid_t set_login_gid; /* generated from set_login_user */
+#undef DEF
+#define DEF(type, name) \
+	{ type, #name, offsetof(struct auth_settings, name) }
 
-/* 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;
+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),
 
-unsigned int set_first_valid_uid = 500, set_last_valid_uid = 0;
-unsigned int set_first_valid_gid = 1, set_last_valid_gid = 0;
+	DEF(SET_BOOL, use_cyrus_sasl),
+	DEF(SET_BOOL, verbose),
 
-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;
+	DEF(SET_INT, count),
+	DEF(SET_INT, process_size),
 
-/* auth */
-struct auth_config *auth_processes_config = NULL;
+	{ 0, NULL, 0 }
+};
 
-static void fix_base_path(char **str)
-{
-	char *fullpath;
+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,
+
+	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,
+
+	/* login */
+	MEMBER(login_dir) "login",
+	MEMBER(login_chroot) TRUE,
+
+	/* mail */
+	MEMBER(valid_chroot_dirs) NULL,
+	MEMBER(max_mail_processes) 1024,
+	MEMBER(verbose_proctitle) FALSE,
+
+	MEMBER(first_valid_uid) 500,
+	MEMBER(last_valid_uid) 0,
+	MEMBER(first_valid_gid) 1,
+	MEMBER(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,
+
+	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,
+
+	MEMBER(process_size) 16,
+	MEMBER(processes_count) 3,
+	MEMBER(max_processes_count) 128,
+	MEMBER(max_logging_users) 256,
+
+	MEMBER(uid) 0 /* generated */
+};
+
+static pool_t settings_pool;
+struct settings *set = NULL;
+
+static void fix_base_path(struct settings *set, const char **str)
+{
 	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,24 +250,39 @@
 	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;
 
-	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);
-		}
+	if (!sscanf(value, "%i", &num) || num < 0)
+		return t_strconcat("Invalid number: ", value, NULL);
+	*result = num;
+	return NULL;
+}
 
-		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 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);
+
+	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);
 	}
 }
 
+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)
 {
 	char *str, *p;
@@ -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();
+	for (login = set->logins; login != NULL; login = login->next) {
+		get_login_uid(set, login);
+		login_settings_verify(login);
+	}
 
-	if (access(set_login_executable, X_OK) < 0) {
-		i_fatal("Can't use login executable %s: %m",
-			set_login_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 (access(set_imap_executable, X_OK) < 0) {
-		i_fatal("Can't use imap executable %s: %m",
-			set_imap_executable);
+	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 (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;
-}
-
-static void auth_config_free(struct auth_config *auth)
-{
-	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);
+	auth->next = set->auths;
+        set->auths = auth;
 }
 
-static const char *parse_new_auth(const char *name)
+static const char *parse_new_auth(struct settings *set, 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;
-
-	if (auth == NULL)
-		return "Authentication process name not defined yet";
-
-	/* 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;
-
-	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 (strcmp(key, "auth_passdb") == 0) {
-		/* split it into passdb + passdb_args */
-		for (p = value; *p != ' ' && *p != '\0'; )
-			p++;
+	struct login_settings *login;
 
-		i_free(auth->passdb);
-		auth->passdb = i_strdup_until(value, p);
+	login = p_new(settings_pool, struct login_settings, 1);
 
-		while (*p == ' ') p++;
+	/* copy defaults */
+	*login = set->logins != NULL ? *set->logins :
+		default_login_settings;
 
-		i_free(auth->passdb_args);
-		auth->passdb_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_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;
-	}
+	login->next = set->logins;
+	set->logins = login;
+}
 
-	if (strcmp(key, "auth_process_size") == 0) {
-		int num;
+static const char *parse_new_login(struct settings *set, const char *name)
+{
+	struct login_settings *login;
 
-		if (!sscanf(value, "%i", &num) || num < 0)
-			return t_strconcat("Invalid number: ", value, NULL);
-                auth->process_size = num;
-		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";
+		}
 	}
 
-	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";
 
-		auth_processes_config = auth->next;
-                auth_config_free(auth);
+		return parse_setting_from_defs(auth_setting_defs,
+					       set->auths, key + 5, value);
+	}
+
+	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);
 }

Index: settings.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/settings.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- settings.h	27 Jan 2003 01:33:40 -0000	1.24
+++ settings.h	30 Jan 2003 17:59:32 -0000	1.25
@@ -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;
 
-/* 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;
+	unsigned int first_valid_uid, last_valid_uid;
+	unsigned int first_valid_gid, last_valid_gid;
 
-extern unsigned int set_first_valid_uid, set_last_valid_uid;
-extern unsigned int set_first_valid_gid, set_last_valid_gid;
+	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 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;
+	/* imap */
+	const char *imap_executable;
+	unsigned int imap_process_size;
 
-/* auth */
-struct auth_config {
-	struct auth_config *next;
+	/* imap */
+	const char *pop3_executable;
+	unsigned int pop3_process_size;
 
-	char *name;
-	char *mechanisms;
-	char *realms;
-	char *userdb, *userdb_args;
-	char *passdb, *passdb_args;
-	char *executable;
-	char *user;
-	char *chroot;
+	/* .. */
+	gid_t login_gid;
+
+	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;
+
+	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 */
+};
+
+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);
 

Index: ssl-init.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/ssl-init.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- ssl-init.c	27 Jan 2003 01:44:34 -0000	1.9
+++ ssl-init.c	30 Jan 2003 17:59:32 -0000	1.10
@@ -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();

--- imap-process.c DELETED ---

--- imap-process.h DELETED ---




More information about the dovecot-cvs mailing list