[dovecot-cvs] dovecot/src/master auth-process.c,1.46,1.47 common.h,1.15,1.16 login-process.c,1.46,1.47 login-process.h,1.5,1.6 mail-process.c,1.24,1.25 mail-process.h,1.3,1.4 main.c,1.44,1.45 master-settings.c,1.20,1.21 master-settings.h,1.13,1.14 ssl-init.c,1.10,1.11

cras at procontrol.fi cras at procontrol.fi
Thu Jul 10 07:04:09 EEST 2003


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

Modified Files:
	auth-process.c common.h login-process.c login-process.h 
	mail-process.c mail-process.h main.c master-settings.c 
	master-settings.h ssl-init.c 
Log Message:
New configuration file code. Some syntax changes, but tries to be somewhat
backwards compatible. SIGHUP now reverts back to old configuration if it
detected errors in new one.



Index: auth-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/auth-process.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -d -r1.46 -r1.47
--- auth-process.c	26 May 2003 15:26:29 -0000	1.46
+++ auth-process.c	10 Jul 2003 03:04:07 -0000	1.47
@@ -295,7 +295,7 @@
 	if (dup2(null_fd, 1) < 0)
 		i_fatal("login: dup2(1) failed: %m");
 
-	child_process_init_env();
+	child_process_init_env(group->set->parent->defaults);
 
 	/* move login communication handle to 3. do it last so we can be
 	   sure it's not closed afterwards. */
@@ -371,7 +371,8 @@
 	group->set = auth_set;
 
 	/* create socket for listening auth requests from login */
-	path = t_strconcat(set->login_dir, "/", auth_set->name, NULL);
+	path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
+			   auth_set->name, NULL);
 	(void)unlink(path);
         (void)umask(0117); /* we want 0660 mode for the socket */
 
@@ -382,9 +383,10 @@
 	fd_close_on_exec(group->listen_fd, TRUE);
 
 	/* set correct permissions */
-	if (chown(path, geteuid(), set->login_gid) < 0) {
+	if (chown(path, geteuid(), auth_set->parent->defaults->login_gid) < 0) {
 		i_fatal("login: chown(%s, %s, %s) failed: %m",
-			path, dec2str(geteuid()), dec2str(set->login_gid));
+			path, dec2str(geteuid()),
+			dec2str(auth_set->parent->defaults->login_gid));
 	}
 
 	group->next = process_groups;
@@ -401,7 +403,8 @@
                 group->processes = next;
 	}
 
-	(void)unlink(t_strconcat(set->login_dir, "/", group->set->name, NULL));
+	(void)unlink(t_strconcat(group->set->parent->defaults->login_dir, "/",
+				 group->set->name, NULL));
 
 	if (close(group->listen_fd) < 0)
 		i_error("close(auth group %s) failed: %m", group->set->name);
@@ -419,18 +422,28 @@
 	}
 }
 
+static void auth_process_groups_create(struct server_settings *server)
+{
+	struct auth_settings *auth_set;
+
+	while (server != NULL) {
+		auth_set = server->auths;
+		for (; auth_set != NULL; auth_set = auth_set->next)
+			auth_process_group_create(auth_set);
+
+                server = server->next;
+	}
+}
+
 static void
 auth_processes_start_missing(void *context __attr_unused__)
 {
-	struct auth_settings *auth_set;
 	struct auth_process_group *group;
 	unsigned int count;
 
 	if (process_groups == NULL) {
 		/* first time here, create the groups */
-		auth_set = set->auths;
-		for (; auth_set != NULL; auth_set = auth_set->next)
-                        auth_process_group_create(auth_set);
+		auth_process_groups_create(settings_root);
 	}
 
 	for (group = process_groups; group != NULL; group = group->next) {

Index: common.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/common.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- common.h	15 Apr 2003 16:58:48 -0000	1.15
+++ common.h	10 Jul 2003 03:04:07 -0000	1.16
@@ -20,18 +20,9 @@
 	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, mail_fd[FD_MAX], inetd_login_fd;
+extern int null_fd, inetd_login_fd;
 
 #define IS_INETD() \
 	(inetd_login_fd != -1)
@@ -46,7 +37,7 @@
 #define PID_REMOVE_PROCESS_TYPE(pid) \
 	hash_remove(pids, POINTER_CAST(pid))
 
-void child_process_init_env(void);
+void child_process_init_env(struct settings *set);
 
 /* misc */
 #define VALIDATE_STR(str) \

Index: login-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/login-process.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -d -r1.46 -r1.47
--- login-process.c	26 May 2003 15:26:29 -0000	1.46
+++ login-process.c	10 Jul 2003 03:04:07 -0000	1.47
@@ -17,25 +17,6 @@
 #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;
-	const char *module_dir;
-	unsigned int process_size;
-	int process_type;
-	int *listen_fd, *ssl_listen_fd;
-};
-
 struct login_process {
 	struct login_group *group;
 	struct login_process *prev_nonlisten, *next_nonlisten;
@@ -71,36 +52,14 @@
 static void login_process_unref(struct login_process *p);
 static int login_process_init_group(struct login_process *p);
 
-static void login_group_create(struct login_settings *login_set)
+static void login_group_create(struct settings *set)
 {
 	struct login_group *group;
 
-	if (strstr(set->protocols, login_set->name) == NULL) {
-		/* not enabled */
-		return;
-	}
-
 	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->process_type = PROCESS_TYPE_IMAP;
-		group->listen_fd = &mail_fd[FD_IMAP];
-		group->ssl_listen_fd = &mail_fd[FD_IMAPS];
-		group->module_dir = !set->imap_use_modules ? NULL :
-                        set->imap_modules;
-	} else if (strcmp(login_set->name, "pop3") == 0) {
-		group->executable = set->pop3_executable;
-		group->process_size = set->pop3_process_size;
-		group->process_type = PROCESS_TYPE_POP3;
-		group->listen_fd = &mail_fd[FD_POP3];
-		group->ssl_listen_fd = &mail_fd[FD_POP3S];
-		group->module_dir = !set->pop3_use_modules ? NULL :
-                        set->pop3_modules;
-	} else
-		i_panic("Unknown login group name '%s'", login_set->name);
+	group->set = set;
+	group->process_type = set->protocol == MAIL_PROTOCOL_IMAP ?
+		PROCESS_TYPE_IMAP : PROCESS_TYPE_POP3;
 
 	group->next = login_groups;
 	login_groups = group;
@@ -123,11 +82,7 @@
 		struct login_group *group = request->process->group;
 
 		master_reply.success =
-			create_mail_process(request->fd, &request->ip,
-					    group->executable,
-					    group->module_dir,
-					    group->process_size,
-					    group->process_type,
+			create_mail_process(group, request->fd, &request->ip,
 					    reply, (const char *) data);
 	}
 
@@ -168,18 +123,29 @@
 	}
 }
 
-static struct login_group *login_group_process_find(const char *name)
+static void login_process_groups_create(void)
 {
-	struct login_group *group;
-	struct login_settings *login;
+	struct server_settings *server;
 
-	if (login_groups == NULL) {
-		for (login = set->logins; login != NULL; login = login->next)
-			login_group_create(login);
+	for (server = settings_root; server != NULL; server = server->next) {
+		if (server->imap != NULL)
+			login_group_create(server->imap);
+		if (server->pop3 != NULL)
+			login_group_create(server->pop3);
 	}
+}
+
+static struct login_group *
+login_group_process_find(const char *name, enum mail_protocol protocol)
+{
+	struct login_group *group;
+
+	if (login_groups == NULL)
+                login_process_groups_create();
 
 	for (group = login_groups; group != NULL; group = group->next) {
-		if (strcmp(group->set->name, name) == 0)
+		if (strcmp(group->set->server->name, name) == 0 &&
+		    group->set->protocol == protocol)
 			return group;
 	}
 
@@ -189,8 +155,9 @@
 static int login_process_read_group(struct login_process *p)
 {
 	struct login_group *group;
-	const char *name;
+	const char *name, *proto;
 	char buf[256];
+	enum mail_protocol protocol;
 	unsigned int len;
 	ssize_t ret;
 
@@ -201,7 +168,7 @@
 	else {
 		len = buf[0];
 		if (len >= sizeof(buf)) {
-			i_error("login: Process name length too large");
+			i_error("login: Server name length too large");
 			return FALSE;
 		}
 
@@ -211,12 +178,29 @@
 	if (ret < 0)
 		i_error("login: read() failed: %m");
 	else if (len == 0 || (size_t)ret != len)
-		i_error("login: Process name wasn't sent");
+		i_error("login: Server name wasn't sent");
 	else {
 		name = t_strndup(buf, len);
-		group = login_group_process_find(name);
+		proto = strchr(buf, '/');
+		if (proto == NULL) {
+			i_error("login: Missing protocol from server name '%s'",
+				name);
+			return FALSE;
+		}
+		name = t_strdup_until(buf, proto++);
+
+		if (strcmp(proto, "imap") == 0)
+			protocol = MAIL_PROTOCOL_IMAP;
+		else if (strcmp(proto, "pop3") == 0)
+			protocol = MAIL_PROTOCOL_IMAP;
+		else {
+			i_error("login: Unknown protocol '%s'", proto);
+			return FALSE;
+		}
+
+		group = login_group_process_find(name, protocol);
 		if (group == NULL) {
-			i_error("login: Unknown process group '%s'", name);
+			i_error("login: Unknown server name '%s'", name);
 			return FALSE;
 		}
 
@@ -384,12 +368,13 @@
 
 static void login_process_init_env(struct login_group *group, pid_t pid)
 {
-	child_process_init_env();
+	struct settings *set = group->set;
+
+	child_process_init_env(set);
 
 	/* setup access environment - needs to be done after
 	   clean_child_process() since it clears environment */
-	restrict_access_set_env(group->set->user,
-				group->set->uid, set->login_gid,
+	restrict_access_set_env(set->login_user, set->login_uid, set->login_gid,
 				set->login_chroot ? set->login_dir : NULL,
 				0, 0);
 
@@ -398,7 +383,8 @@
 	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_KEY_FILE=",
+				    set->ssl_key_file, NULL));
 		env_put(t_strconcat("SSL_PARAM_FILE=",
 				    set->ssl_parameters_file, NULL));
 	}
@@ -410,12 +396,12 @@
 	if (set->verbose_ssl)
 		env_put("VERBOSE_SSL=1");
 
-	if (group->set->process_per_connection) {
+	if (set->login_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",
-					group->set->max_logging_users));
+					set->login_max_logging_users));
 	}
 
 	env_put(t_strdup_printf("PROCESS_UID=%s", dec2str(pid)));
@@ -427,14 +413,14 @@
 	pid_t pid;
 	int fd[2];
 
-	if (group->set->process_per_connection &&
+	if (group->set->login_process_per_connection &&
 	    group->processes - group->listening_processes >=
-	    group->set->max_logging_users) {
+	    group->set->login_max_logging_users) {
 		if (group->oldest_nonlisten_process != NULL)
 			login_process_destroy(group->oldest_nonlisten_process);
 	}
 
-	if (group->set->uid == 0)
+	if (group->set->login_uid == 0)
 		i_fatal("Login process must not run as root");
 
 	/* create communication to process with a socket pair */
@@ -461,12 +447,12 @@
 	}
 
 	/* move the listen handle */
-	if (dup2(*group->listen_fd, LOGIN_LISTEN_FD) < 0)
+	if (dup2(group->set->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 (dup2(*group->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0)
+	if (dup2(group->set->ssl_listen_fd, LOGIN_SSL_LISTEN_FD) < 0)
 		i_fatal("login: dup2(ssl_listen_fd) failed: %m");
 	fd_close_on_exec(LOGIN_SSL_LISTEN_FD, FALSE);
 
@@ -480,26 +466,31 @@
 
 	login_process_init_env(group, getpid());
 
-	if (!set->login_chroot) {
+	if (!group->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(group->set->login_dir) < 0) {
+			i_fatal("chdir(%s) failed: %m",
+				group->set->login_dir);
+		}
 	}
 
-	restrict_process_size(group->set->process_size, (unsigned int)-1);
+	restrict_process_size(group->set->login_process_size, (unsigned int)-1);
 
 	/* 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(group->set->executable, '/');
-	if (argv[0] == NULL) argv[0] = group->set->executable; else argv[0]++;
+	argv[0] = strrchr(group->set->login_executable, '/');
+	if (argv[0] == NULL)
+		argv[0] = group->set->login_executable;
+	else
+		argv[0]++;
 
-	execv(group->set->executable, (char **) argv);
+	execv(group->set->login_executable, (char **) argv);
 
 	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
-		       group->set->executable);
+		       group->set->login_executable);
 	return -1;
 }
 
@@ -534,10 +525,11 @@
 
 static void login_group_start_missings(struct login_group *group)
 {
-	if (!group->set->process_per_connection) {
+	if (!group->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 (group->listening_processes < group->set->processes_count)
+		if (group->listening_processes <
+		    group->set->login_processes_count)
 			(void)create_login_process(group);
 		return;
 	}
@@ -549,15 +541,20 @@
 	   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)
+	if (group->wanted_processes_count < group->set->login_processes_count) {
+		group->wanted_processes_count =
+			group->set->login_processes_count;
+	} else if (group->listening_processes == 0)
 		group->wanted_processes_count *= 2;
-	else if (group->wanted_processes_count > group->set->processes_count)
+	else if (group->wanted_processes_count >
+		 group->set->login_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;
+	if (group->wanted_processes_count >
+	    group->set->login_max_processes_count) {
+		group->wanted_processes_count =
+			group->set->login_max_processes_count;
+	}
 
 	while (group->listening_processes < group->wanted_processes_count)
 		(void)create_login_process(group);
@@ -567,12 +564,9 @@
 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);
-	}
+	if (login_groups == NULL)
+		login_process_groups_create();
 
 	for (group = login_groups; group != NULL; group = group->next)
 		login_group_start_missings(group);

Index: login-process.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/login-process.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- login-process.h	27 Jan 2003 01:33:40 -0000	1.5
+++ login-process.h	10 Jul 2003 03:04:07 -0000	1.6
@@ -1,6 +1,20 @@
 #ifndef __LOGIN_PROCESS_H
 #define __LOGIN_PROCESS_H
 
+struct login_group {
+	struct login_group *next;
+
+	int process_type;
+	struct 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;
+};
+
 void login_process_abormal_exit(pid_t pid);
 void login_processes_destroy_all(void);
 

Index: mail-process.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/mail-process.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- mail-process.c	2 Jul 2003 01:02:27 -0000	1.24
+++ mail-process.c	10 Jul 2003 03:04:07 -0000	1.25
@@ -9,6 +9,7 @@
 #include "restrict-process-size.h"
 #include "var-expand.h"
 #include "mail-process.h"
+#include "login-process.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -18,13 +19,20 @@
 
 static unsigned int mail_process_count = 0;
 
-static int validate_uid_gid(uid_t uid, gid_t gid, const char *user)
+static int validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
+			    const char *user)
 {
 	if (uid == 0) {
 		i_error("Logins with UID 0 not permitted (user %s)", user);
 		return FALSE;
 	}
 
+	if (set->login_uid == uid && geteuid() != uid) {
+		i_error("Can't log in using login processes UID %s (user %s) "
+			"(see login_user in config file).",
+			dec2str(uid), user);
+	}
+
 	if (uid < (uid_t)set->first_valid_uid ||
 	    (set->last_valid_uid != 0 && uid > (uid_t)set->last_valid_uid)) {
 		i_error("Logins with UID %s (user %s) not permitted "
@@ -44,7 +52,7 @@
 	return TRUE;
 }
 
-static int validate_chroot(const char *dir)
+static int validate_chroot(struct settings *set, const char *dir)
 {
 	const char *const *chroot_dirs;
 
@@ -95,30 +103,31 @@
 	return str_c(str);
 }
 
-int create_mail_process(int socket, struct ip_addr *ip,
-			const char *executable, const char *module_dir,
-			unsigned int process_size, int process_type,
+int create_mail_process(struct login_group *group, int socket,
+			struct ip_addr *ip,
 			struct auth_master_reply *reply, const char *data)
 {
 	static const char *argv[] = { NULL, NULL, NULL };
+	struct settings *set = group->set;
 	const char *addr, *mail, *chroot_dir, *home_dir, *full_home_dir;
 	char title[1024];
 	pid_t pid;
 	int i, err;
 
+	// FIXME: per-group
 	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,
+	if (!validate_uid_gid(set, reply->uid, reply->gid,
 			      data + reply->virtual_user_idx))
 		return FALSE;
 
 	home_dir = data + reply->home_idx;
 	chroot_dir = data + reply->chroot_idx;
 
-	if (*chroot_dir != '\0' && !validate_chroot(chroot_dir)) {
+	if (*chroot_dir != '\0' && !validate_chroot(set, chroot_dir)) {
 		i_error("Invalid chroot directory: %s", chroot_dir);
 		return FALSE;
 	}
@@ -132,11 +141,11 @@
 	if (pid != 0) {
 		/* master */
 		mail_process_count++;
-		PID_ADD_PROCESS_TYPE(pid, process_type);
+		PID_ADD_PROCESS_TYPE(pid, group->process_type);
 		return TRUE;
 	}
 
-	child_process_init_env();
+	child_process_init_env(set);
 
 	/* move the client socket into stdin and stdout fds */
 	fd_close_on_exec(socket, FALSE);
@@ -154,7 +163,7 @@
 				reply->uid, reply->gid, chroot_dir,
 				set->first_valid_gid, set->last_valid_gid);
 
-	restrict_process_size(process_size, (unsigned int)-1);
+	restrict_process_size(group->set->mail_process_size, (unsigned int)-1);
 
 	if (*home_dir != '\0') {
 		full_home_dir = *chroot_dir == '\0' ? home_dir :
@@ -200,8 +209,12 @@
 	if (set->mbox_read_dotlock)
 		env_put("MBOX_READ_DOTLOCK=1");
 
-	if (module_dir != NULL && *module_dir != '\0')
-		env_put(t_strconcat("MODULE_DIR=", module_dir, NULL));
+	if (group->set->mail_use_modules &&
+	    group->set->mail_modules != NULL &&
+	    *group->set->mail_modules != '\0') {
+		env_put(t_strconcat("MODULE_DIR=",
+				    group->set->mail_modules, NULL));
+	}
 
 	/* user given environment - may be malicious. virtual_user comes from
 	   auth process, but don't trust that too much either. Some auth
@@ -236,16 +249,20 @@
 		restrict_access_by_env(TRUE);
 
 	/* hide the path, it's ugly */
-	argv[0] = strrchr(executable, '/');
-	if (argv[0] == NULL) argv[0] = executable; else argv[0]++;
+	argv[0] = strrchr(group->set->mail_executable, '/');
+	if (argv[0] == NULL)
+		argv[0] = group->set->mail_executable;
+	else
+		argv[0]++;
 
-	execv(executable, (char **) argv);
+	execv(group->set->mail_executable, (char **) argv);
 	err = errno;
 
 	for (i = 0; i < 3; i++)
 		(void)close(i);
 
-	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", executable);
+	i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m",
+		       group->set->mail_executable);
 
 	/* not reached */
 	return FALSE;

Index: mail-process.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/mail-process.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- mail-process.h	14 May 2003 18:23:05 -0000	1.3
+++ mail-process.h	10 Jul 2003 03:04:07 -0000	1.4
@@ -1,11 +1,11 @@
 #ifndef __MAIL_PROCESS_H
 #define __MAIL_PROCESS_H
 
+struct login_group;
 struct auth_master_reply;
 
-int create_mail_process(int socket, struct ip_addr *ip,
-			const char *executable, const char *module_dir,
-			unsigned int process_size, int process_type,
+int create_mail_process(struct login_group *group, int socket,
+			struct ip_addr *ip,
 			struct auth_master_reply *reply, const char *data);
 
 void mail_process_destroyed(pid_t pid);

Index: main.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/main.c,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -d -r1.44 -r1.45
--- main.c	4 May 2003 16:16:26 -0000	1.44
+++ main.c	10 Jul 2003 03:04:07 -0000	1.45
@@ -34,7 +34,7 @@
 
 struct ioloop *ioloop;
 struct hash_table *pids;
-int null_fd, mail_fd[FD_MAX], inetd_login_fd;
+int null_fd, inetd_login_fd;
 
 int validate_str(const char *str, size_t max_len)
 {
@@ -48,7 +48,7 @@
 	return FALSE;
 }
 
-void child_process_init_env(void)
+void child_process_init_env(struct settings *set)
 {
 	/* remove all environment, we don't need them */
 	env_clean();
@@ -83,7 +83,8 @@
         login_processes_destroy_all();
         auth_processes_destroy_all();
 
-	master_settings_read(configfile);
+	if (!master_settings_read(configfile))
+		i_warning("Invalid configuration, keeping old one");
 }
 
 static const char *get_exit_status_message(enum fatal_exit_status status)
@@ -218,57 +219,65 @@
 	return ip;
 }
 
-static void listen_protocols(void)
+static void listen_protocols(struct settings *set)
 {
-	struct ip_addr *imap_ip, *imaps_ip, *pop3_ip, *pop3s_ip, *ip;
+	struct ip_addr *normal_ip, *ssl_ip, *ip;
 	const char *const *proto;
-	unsigned int imap_port = 143;
-	unsigned int pop3_port = 110;
+	unsigned int normal_port, ssl_port, port;
+	int *fd;
+
+	normal_port = set->protocol == MAIL_PROTOCOL_IMAP ? 143 : 110;
 #ifdef HAVE_SSL
-	unsigned int imaps_port = 993;
-	unsigned int pop3s_port = 995;
+	ssl_port = set->protocol == MAIL_PROTOCOL_IMAP ? 993 : 995;
 #else
-	unsigned int imaps_port = 0;
-	unsigned int pop3s_port = 0;
+	ssl_port = 0;
 #endif
-	unsigned int port;
-	int *fd, i;
 
 	/* 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);
+	normal_ip = resolve_ip(set->listen, &normal_port);
+	ssl_ip = resolve_ip(set->ssl_listen, &ssl_port);
 
-	if (imaps_ip == NULL && set->imaps_listen == NULL)
-		imaps_ip = imap_ip;
-	if (pop3s_ip == NULL && set->pop3s_listen == NULL)
-		pop3s_ip = pop3_ip;
+	if (ssl_ip == NULL && set->ssl_listen == NULL)
+		ssl_ip = normal_ip;
 
 	/* register wanted protocols */
 	for (proto = t_strsplit(set->protocols, " "); *proto != NULL; proto++) {
+		fd = NULL; ip = NULL; port = 0;
 		if (strcasecmp(*proto, "imap") == 0) {
-			fd = &mail_fd[FD_IMAP]; ip = imap_ip; port = imap_port;
+			if (set->protocol == MAIL_PROTOCOL_IMAP) {
+				fd = &set->listen_fd;
+				port = normal_port; ip = normal_ip;
+			}
 		} else if (strcasecmp(*proto, "imaps") == 0) {
-			fd = &mail_fd[FD_IMAPS]; ip = imaps_ip;
-			port = set->ssl_disable ? 0 : imaps_port;
+			if (set->protocol == MAIL_PROTOCOL_IMAP &&
+			    !set->ssl_disable) {
+				fd = &set->ssl_listen_fd;
+				port = ssl_port; ip = ssl_ip;
+			}
 		} else if (strcasecmp(*proto, "pop3") == 0) {
-			fd = &mail_fd[FD_POP3]; ip = pop3_ip; port = pop3_port;
+			if (set->protocol == MAIL_PROTOCOL_POP3) {
+				fd = &set->listen_fd;
+				port = normal_port; ip = normal_ip;
+			}
 		} else if (strcasecmp(*proto, "pop3s") == 0) {
-			fd = &mail_fd[FD_POP3S]; ip = pop3s_ip;
-			port = set->ssl_disable ? 0 : pop3s_port;
+			if (set->protocol == MAIL_PROTOCOL_POP3 &&
+			    !set->ssl_disable) {
+				fd = &set->ssl_listen_fd;
+				port = ssl_port; ip = ssl_ip;
+			}
 		} else {
 			i_fatal("Unknown protocol %s", *proto);
 		}
 
+		if (fd == NULL)
+			continue;
+
 		if (*fd != -1)
 			i_fatal("Protocol %s given more than once", *proto);
 
-		if (port == 0) {
-			*fd = dup(null_fd);
-			if (*fd == -1)
-				i_fatal("dup(null_fd) failed: %m");
-		} else {
+		if (port == 0)
+			*fd = null_fd;
+		else {
 			*fd = net_listen(ip, &port);
 			if (*fd == -1)
 				i_fatal("listen(%d) failed: %m", port);
@@ -277,19 +286,42 @@
 		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);
-		}
+	if (set->listen_fd == -1)
+		set->listen_fd = null_fd;
+	if (set->ssl_listen_fd == -1)
+		set->ssl_listen_fd = null_fd;
+}
+
+static int have_stderr_set(struct settings *set)
+{
+	if (set->log_path != NULL &&
+	    strcmp(set->log_path, "/dev/stderr") == 0)
+		return TRUE;
+
+	if (set->info_log_path != NULL &&
+	    strcmp(set->info_log_path, "/dev/stderr") == 0)
+		return TRUE;
+
+	return FALSE;
+}
+
+static int have_stderr(struct server_settings *server)
+{
+	while (server != NULL) {
+		if (server->imap != NULL && have_stderr_set(server->imap))
+			return TRUE;
+		if (server->pop3 != NULL && have_stderr_set(server->pop3))
+			return TRUE;
+
+		server = server->next;
 	}
+
+	return FALSE;
 }
 
 static void open_fds(void)
 {
-	int i;
+	struct server_settings *server;
 
 	/* initialize fds. */
 	null_fd = open("/dev/null", O_RDONLY);
@@ -303,11 +335,15 @@
 		fd_close_on_exec(null_fd, TRUE);
 	}
 
-	for (i = 0; i < FD_MAX; i++)
-		mail_fd[i] = -1;
-
-	if (!IS_INETD())
-		listen_protocols();
+	if (!IS_INETD()) {
+		server = settings_root;
+		for (; server != NULL; server = server->next) {
+			if (server->imap != NULL)
+				listen_protocols(server->imap);
+			if (server->pop3 != NULL)
+				listen_protocols(server->pop3);
+		}
+	}
 
 	/* close stdin and stdout. close stderr unless we're logging
 	   into /dev/stderr. */
@@ -316,16 +352,13 @@
 	if (dup2(null_fd, 1) < 0)
 		i_fatal("dup2(1) failed: %m");
 
-	if ((set->log_path == NULL ||
-	     strcmp(set->log_path, "/dev/stderr") != 0) &&
-	    (set->info_log_path == NULL ||
-	     strcmp(set->info_log_path, "/dev/stderr") != 0)) {
+	if (!have_stderr(settings_root)) {
 		if (dup2(null_fd, 2) < 0)
 			i_fatal("dup2(2) failed: %m");
 	}
 }
 
-static void open_logfile(void)
+static void open_logfile(struct settings *set)
 {
 	if (set->log_path == NULL)
 		i_set_failure_syslog("dovecot", LOG_NDELAY, LOG_MAIL);
@@ -347,7 +380,7 @@
 	/* deny file access from everyone else except owner */
         (void)umask(0077);
 
-	open_logfile();
+	open_logfile(settings_root->defaults);
 
 	lib_init_signals(sig_quit);
 
@@ -361,8 +394,6 @@
 
 static void main_deinit(void)
 {
-	int i;
-
         if (lib_signal_kill != 0)
 		i_warning("Killed with signal %d", lib_signal_kill);
 
@@ -378,18 +409,11 @@
 	if (close(null_fd) < 0)
 		i_error("close(null_fd) failed: %m");
 
-	for (i = 0; i < FD_MAX; i++) {
-		if (mail_fd[i] != -1) {
-			if (close(mail_fd[i]) < 0)
-				i_error("close(mail_fd[%d]) failed: %m", i);
-		}
-	}
-
 	hash_destroy(pids);
 	closelog();
 }
 
-static void daemonize(void)
+static void daemonize(struct settings *set)
 {
 	pid_t pid;
 
@@ -448,14 +472,15 @@
 
 	/* read and verify settings before forking */
 	master_settings_init();
-	master_settings_read(configfile);
+	if (!master_settings_read(configfile))
+		exit(FATAL_DEFAULT);
 	open_fds();
 
 	/* we don't need any environment */
 	env_clean();
 
 	if (!foreground)
-		daemonize();
+		daemonize(settings_root->defaults);
 
 	ioloop = io_loop_create(system_pool);
 

Index: master-settings.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/master-settings.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- master-settings.c	2 Jul 2003 01:02:27 -0000	1.20
+++ master-settings.c	10 Jul 2003 03:04:07 -0000	1.21
@@ -12,6 +12,22 @@
 #include <fcntl.h>
 #include <pwd.h>
 
+enum settings_type {
+	SETTINGS_TYPE_ROOT,
+	SETTINGS_TYPE_SERVER,
+	SETTINGS_TYPE_AUTH
+};
+
+struct settings_parse_ctx {
+	enum settings_type type, parent_type;
+	enum mail_protocol protocol;
+
+	struct server_settings *root, *server;
+	struct auth_settings *auth;
+
+	int level;
+};
+
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct settings, name) }
 
@@ -24,10 +40,8 @@
 
 	/* 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),
+	DEF(SET_STR, listen),
+	DEF(SET_STR, ssl_listen),
 
 	DEF(SET_BOOL, ssl_disable),
 	DEF(SET_STR, ssl_cert_file),
@@ -35,11 +49,20 @@
 	DEF(SET_STR, ssl_parameters_file),
 	DEF(SET_STR, ssl_parameters_regenerate),
 	DEF(SET_BOOL, disable_plaintext_auth),
+	DEF(SET_BOOL, verbose_ssl),
 
 	/* login */
 	DEF(SET_STR, login_dir),
+	DEF(SET_STR, login_executable),
+	DEF(SET_STR, login_user),
+
+	DEF(SET_BOOL, login_process_per_connection),
 	DEF(SET_BOOL, login_chroot),
-	DEF(SET_BOOL, verbose_ssl),
+
+	DEF(SET_INT, login_process_size),
+	DEF(SET_INT, login_processes_count),
+	DEF(SET_INT, login_max_processes_count),
+	DEF(SET_INT, login_max_logging_users),
 
 	/* mail */
 	DEF(SET_STR, valid_chroot_dirs),
@@ -70,36 +93,13 @@
 	DEF(SET_INT, umask),
 	DEF(SET_BOOL, mail_drop_priv_before_exec),
 
+	DEF(SET_STR, mail_executable),
+	DEF(SET_INT, mail_process_size),
+	DEF(SET_BOOL, mail_use_modules),
+	DEF(SET_STR, mail_modules),
+
 	/* imap */
-	DEF(SET_STR, imap_executable),
-	DEF(SET_INT, imap_process_size),
 	DEF(SET_INT, imap_max_line_length),
-	DEF(SET_BOOL, imap_use_modules),
-	DEF(SET_STR, imap_modules),
-
-	/* pop3 */
-	DEF(SET_STR, pop3_executable),
-	DEF(SET_INT, pop3_process_size),
-	DEF(SET_BOOL, pop3_use_modules),
-	DEF(SET_STR, pop3_modules),
-
-	{ 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 }
 };
@@ -130,6 +130,9 @@
 };
 
 struct settings default_settings = {
+	MEMBER(server) NULL,
+	MEMBER(protocol) 0,
+
 	/* common */
 	MEMBER(base_dir) PKG_RUNDIR,
 	MEMBER(log_path) NULL,
@@ -138,10 +141,8 @@
 
 	/* general */
 	MEMBER(protocols) "imap imaps",
-	MEMBER(imap_listen) "*",
-	MEMBER(imaps_listen) NULL,
-	MEMBER(pop3_listen) "*",
-	MEMBER(pop3s_listen) NULL,
+	MEMBER(listen) "*",
+	MEMBER(ssl_listen) NULL,
 
 	MEMBER(ssl_disable) FALSE,
 	MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
@@ -149,11 +150,20 @@
 	MEMBER(ssl_parameters_file) "ssl-parameters.dat",
 	MEMBER(ssl_parameters_regenerate) 24,
 	MEMBER(disable_plaintext_auth) FALSE,
+	MEMBER(verbose_ssl) FALSE,
 
 	/* login */
 	MEMBER(login_dir) "login",
+	MEMBER(login_executable) NULL,
+	MEMBER(login_user) "dovecot",
+
+	MEMBER(login_process_per_connection) TRUE,
 	MEMBER(login_chroot) TRUE,
-	MEMBER(verbose_ssl) FALSE,
+
+	MEMBER(login_process_size) 16,
+	MEMBER(login_processes_count) 3,
+	MEMBER(login_max_processes_count) 128,
+	MEMBER(login_max_logging_users) 256,
 
 	/* mail */
 	MEMBER(valid_chroot_dirs) NULL,
@@ -184,42 +194,23 @@
 	MEMBER(umask) 0077,
 	MEMBER(mail_drop_priv_before_exec) FALSE,
 
+	MEMBER(mail_executable) PKG_LIBEXECDIR"/imap",
+	MEMBER(mail_process_size) 256,
+	MEMBER(mail_use_modules) FALSE,
+	MEMBER(mail_modules) PKG_LIBDIR"/imap",
+
 	/* imap */
-	MEMBER(imap_executable) PKG_LIBEXECDIR"/imap",
-	MEMBER(imap_process_size) 256,
 	MEMBER(imap_max_line_length) 65536,
-	MEMBER(imap_use_modules) FALSE,
-	MEMBER(imap_modules) PKG_LIBDIR"/imap",
-
-	/* pop3 */
-	MEMBER(pop3_executable) PKG_LIBEXECDIR"/pop3",
-	MEMBER(pop3_process_size) 256,
-	MEMBER(pop3_use_modules) FALSE,
-	MEMBER(pop3_modules) PKG_LIBDIR"/imap",
 
+	/* .. */
+	MEMBER(login_uid) 0,
 	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 */
+	MEMBER(listen_fd) -1,
+	MEMBER(ssl_listen_fd) -1
 };
 
 struct auth_settings default_auth_settings = {
+	MEMBER(parent) NULL,
 	MEMBER(next) NULL,
 
 	MEMBER(name) NULL,
@@ -241,8 +232,8 @@
 	MEMBER(process_size) 256
 };
 
-static pool_t settings_pool;
-struct settings *set = NULL;
+static pool_t settings_pool, settings2_pool;
+struct server_settings *settings_root = NULL;
 
 static void fix_base_path(struct settings *set, const char **str)
 {
@@ -252,49 +243,42 @@
 	}
 }
 
-static void get_login_uid(struct settings *set,
-			  struct login_settings *login_set)
+static int get_login_uid(struct settings *set)
 {
 	struct passwd *pw;
 
-	if ((pw = getpwnam(login_set->user)) == NULL)
-		i_fatal("Login user doesn't exist: %s", login_set->user);
+	if ((pw = getpwnam(set->login_user)) == NULL) {
+		i_error("Login user doesn't exist: %s", set->login_user);
+		return FALSE;
+	}
 
 	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 "
+		i_error("All login process users must belong to same group "
 			"(%s vs %s)", dec2str(set->login_gid),
 			dec2str(pw->pw_gid));
+		return FALSE;
 	}
 
-	login_set->uid = pw->pw_uid;
+	set->login_uid = pw->pw_uid;
+	return TRUE;
 }
 
-static void auth_settings_verify(struct auth_settings *auth)
+static int 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);
+	if (access(auth->executable, X_OK) < 0) {
+		i_error("Can't use auth executable %s: %m", auth->executable);
+		return FALSE;
+	}
 
-	fix_base_path(set, &auth->chroot);
+	fix_base_path(auth->parent->defaults, &auth->chroot);
 	if (auth->chroot != NULL && access(auth->chroot, X_OK) < 0) {
-		i_fatal("Can't access auth chroot directory %s: %m",
+		i_error("Can't access auth chroot directory %s: %m",
 			auth->chroot);
+		return FALSE;
 	}
-}
-
-static void login_settings_verify(struct login_settings *login)
-{
-	if (strstr(set->protocols, login->name) != NULL) {
-		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");
+	return TRUE;
 }
 
 static const char *get_directory(const char *path)
@@ -311,82 +295,78 @@
 	}
 }
 
-static void settings_verify(struct settings *set)
+static int settings_is_active(struct settings *set)
+{
+	if (set->protocol == MAIL_PROTOCOL_IMAP) {
+		if (strstr(set->protocols, "imap") == NULL)
+			return FALSE;
+	} else {
+		if (strstr(set->protocols, "pop3") == NULL)
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int 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;
 
-	for (login = set->logins; login != NULL; login = login->next) {
-		get_login_uid(set, login);
-		login_settings_verify(login);
-	}
+	if (!get_login_uid(set))
+		return FALSE;
 
-	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);
-		}
-#ifdef HAVE_MODULES
-		if (set->imap_use_modules &&
-		    access(set->imap_modules, R_OK | X_OK) < 0) {
-			i_fatal("Can't access imap module directory: %s: %m",
-				set->imap_modules);
-		}
-#else
-		if (set->imap_use_modules) {
-			i_warning("Module support wasn't built into Dovecot, "
-				  "ignoring imap_use_modules setting");
-		}
-#endif
+	if (access(set->mail_executable, X_OK) < 0) {
+		i_error("Can't use mail executable %s: %m",
+			set->mail_executable);
+		return FALSE;
 	}
 
-	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);
-		}
 #ifdef HAVE_MODULES
-		if (set->pop3_use_modules &&
-		    access(set->pop3_modules, R_OK | X_OK) < 0) {
-			i_fatal("Can't access pop3 module directory: %s: %m",
-				set->imap_modules);
-		}
+	if (set->mail_use_modules &&
+	    access(set->mail_modules, R_OK | X_OK) < 0) {
+		i_error("Can't access mail module directory: %s: %m",
+			set->mail_modules);
+		return FALSE;
+	}
 #else
-		if (set->pop3_use_modules) {
-			i_warning("Module support wasn't built into Dovecot, "
-				  "ignoring pop3_use_modules setting");
-		}
-#endif
+	if (set->mail_use_modules) {
+		i_warning("Module support wasn't built into Dovecot, "
+			  "ignoring mail_use_modules setting");
 	}
+#endif
 
 	if (set->log_path != NULL && access(set->log_path, W_OK) < 0) {
 		dir = get_directory(set->log_path);
-		if (access(dir, W_OK) < 0)
-			i_fatal("Can't write to log directory %s: %m", dir);
+		if (access(dir, W_OK) < 0) {
+			i_error("Can't write to log directory %s: %m", dir);
+			return FALSE;
+		}
 	}
 
 	if (set->info_log_path != NULL &&
 	    access(set->info_log_path, W_OK) < 0) {
 		dir = get_directory(set->info_log_path);
 		if (access(dir, W_OK) < 0) {
-			i_fatal("Can't write to info log directory %s: %m",
+			i_error("Can't write to info log directory %s: %m",
 				dir);
+			return FALSE;
 		}
 	}
 
 #ifdef HAVE_SSL
 	if (!set->ssl_disable) {
 		if (access(set->ssl_cert_file, R_OK) < 0) {
-			i_fatal("Can't use SSL certificate %s: %m",
+			i_error("Can't use SSL certificate %s: %m",
 				set->ssl_cert_file);
+			return FALSE;
 		}
 
 		if (access(set->ssl_key_file, R_OK) < 0) {
-			i_fatal("Can't use SSL key file %s: %m",
+			i_error("Can't use SSL key file %s: %m",
 				set->ssl_key_file);
+			return FALSE;
 		}
 	}
 #endif
@@ -403,23 +383,31 @@
 	}
 
 	/* 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_error("unlink_directory() failed for %s: %m", set->login_dir);
+		return FALSE;
+	}
 
 	if (safe_mkdir(set->login_dir, 0750, geteuid(), set->login_gid) == 0) {
 		i_warning("Corrected permissions for login directory %s",
 			  set->login_dir);
 	}
 
-	if (set->max_mail_processes < 1)
-		i_fatal("max_mail_processes must be at least 1");
+	if (set->max_mail_processes < 1) {
+		i_error("max_mail_processes must be at least 1");
+		return FALSE;
+	}
 
 	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");
+	    set->first_valid_uid > set->last_valid_uid) {
+		i_error("first_valid_uid can't be larger than last_valid_uid");
+		return FALSE;
+	}
 	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");
+	    set->first_valid_gid > set->last_valid_gid) {
+		i_error("first_valid_gid can't be larger than last_valid_gid");
+		return FALSE;
+	}
 
 	dotlock_got = fcntl_got = flock_got = FALSE;
 	for (str = t_strsplit(set->mbox_locks, " "); *str != NULL; str++) {
@@ -429,20 +417,25 @@
 			fcntl_got = TRUE;
 		else if (strcasecmp(*str, "flock") == 0)
 			flock_got = TRUE;
-		else
-			i_fatal("mbox_locks: Invalid value %s", *str);
+		else {
+			i_error("mbox_locks: Invalid value %s", *str);
+			return FALSE;
+		}
 	}
 
 #ifndef HAVE_FLOCK
 	if (fcntl_got && !dotlock_got && !flock_got) {
-		i_fatal("mbox_locks: Only flock selected, "
+		i_error("mbox_locks: Only flock selected, "
 			"and flock() isn't supported in this system");
+		return FALSE;
 	}
 	flock_got = FALSE;
 #endif
 
-	if (!dotlock_got && !fcntl_got && !flock_got)
-		i_fatal("mbox_locks: No mbox locking methods selected");
+	if (!dotlock_got && !fcntl_got && !flock_got) {
+		i_error("mbox_locks: No mbox locking methods selected");
+		return FALSE;
+	}
 
 	if (dotlock_got && !set->mbox_read_dotlock &&
 	    !fcntl_got && !flock_got) {
@@ -451,11 +444,26 @@
                 set->mbox_read_dotlock = TRUE;
 	}
 
-	for (auth = set->auths; auth != NULL; auth = auth->next)
-		auth_settings_verify(auth);
+	if (access(set->login_executable, X_OK) < 0) {
+		i_error("Can't use login executable %s: %m",
+			set->login_executable);
+		return FALSE;
+	}
+
+	if (set->login_processes_count < 1) {
+		i_error("login_processes_count must be at least 1");
+		return FALSE;
+	}
+	if (set->login_max_logging_users < 1) {
+		i_error("login_max_logging_users must be at least 1");
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
-static void auth_settings_new(struct settings *set, const char *name)
+static struct auth_settings *
+auth_settings_new(struct server_settings *server, const char *name)
 {
 	struct auth_settings *auth;
 
@@ -463,124 +471,282 @@
 
 	/* copy defaults */
 	*auth = default_auth_settings;
+	auth->parent = server;
 	auth->name = p_strdup(settings_pool, name);
 
-	auth->next = set->auths;
-        set->auths = auth;
+	auth->next = server->auths;
+	server->auths = auth;
+
+	return auth;
 }
 
-static const char *parse_new_auth(struct settings *set, const char *name)
+static struct auth_settings *
+parse_new_auth(struct server_settings *server, const char *name,
+	       const char **errormsg)
 {
 	struct auth_settings *auth;
 
-	if (strchr(name, '/') != NULL)
-		return "Authentication process name must not contain '/'";
+	if (strchr(name, '/') != NULL) {
+		*errormsg = "Authentication process name must not contain '/'";
+		return NULL;
+	}
 
-	for (auth = set->auths; auth != NULL; auth = auth->next) {
+	for (auth = server->auths; auth != NULL; auth = auth->next) {
 		if (strcmp(auth->name, name) == 0) {
-			return "Authentication process already exists "
+			*errormsg = "Authentication process already exists "
 				"with the same name";
+			return NULL;
 		}
 	}
 
-	auth_settings_new(set, name);
-	return NULL;
+	return auth_settings_new(server, name);
 }
 
-static void login_settings_new(struct settings *set, const char *name)
+static const char *parse_setting(const char *key, const char *value,
+				 void *context)
 {
-	struct login_settings *login;
+	struct settings_parse_ctx *ctx = context;
+	const char *error;
 
-	login = p_new(settings_pool, struct login_settings, 1);
+	/* backwards compatibility */
+	if (strcmp(key, "auth") == 0) {
+		ctx->auth = parse_new_auth(ctx->server, value, &error);
+		return ctx->auth == NULL ? error : NULL;
+	}
 
-	/* copy defaults */
-	*login = set->logins != NULL ? *set->logins :
-		default_login_settings;
+	if (strcmp(key, "login") == 0) {
+		i_warning("Ignoring deprecated 'login' section handling. "
+			  "Use protocol imap/pop3 { .. } instead. "
+			  "Some settings may have been read incorrectly.");
+		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);
+	switch (ctx->type) {
+	case SETTINGS_TYPE_ROOT:
+	case SETTINGS_TYPE_SERVER:
+		error = NULL;
+		if (ctx->protocol == MAIL_PROTOCOL_ANY ||
+		    ctx->protocol == MAIL_PROTOCOL_IMAP) {
+			error = parse_setting_from_defs(settings_pool,
+							setting_defs,
+							ctx->server->imap,
+							key, value);
+		}
+
+		if (error == NULL &&
+		    (ctx->protocol == MAIL_PROTOCOL_ANY ||
+		     ctx->protocol == MAIL_PROTOCOL_POP3)) {
+			error = parse_setting_from_defs(settings_pool,
+							setting_defs,
+							ctx->server->pop3,
+							key, value);
+		}
+
+		if (error == NULL)
+			return NULL;
+
+		/* backwards compatibility */
+		if (strncmp(key, "auth_", 5) == 0) {
+			if (ctx->auth == NULL) {
+				return "Authentication process name "
+					"not defined yet";
+			}
+
+			return parse_setting_from_defs(settings_pool,
+						       auth_setting_defs,
+						       ctx->auth,
+						       key + 5, value);
+		}
+		return error;
+	case SETTINGS_TYPE_AUTH:
+		return parse_setting_from_defs(settings_pool, auth_setting_defs,
+					       ctx->auth, key + 5, value);
 	}
 
-	login->next = set->logins;
-	set->logins = login;
+	i_unreached();
 }
 
-static const char *parse_new_login(struct settings *set, const char *name)
+static struct server_settings *
+create_new_server(const char *name,
+		  struct settings *imap_defaults,
+		  struct settings *pop3_defaults)
 {
-	struct login_settings *login;
+	struct server_settings *server;
 
-	for (login = set->logins; login != NULL; login = login->next) {
-		if (strcmp(login->name, name) == 0) {
-			return "Login process already exists "
-				"with the same name";
-		}
-	}
+	server = p_new(settings_pool, struct server_settings, 1);
+	server->name = p_strdup(settings_pool, name);
+	server->imap = p_new(settings_pool, struct settings, 1);
+	server->pop3 = p_new(settings_pool, struct settings, 1);
 
-	login_settings_new(set, name);
-	return NULL;
+	*server->imap = *imap_defaults;
+	*server->pop3 = *pop3_defaults;
+
+	server->imap->protocol = MAIL_PROTOCOL_IMAP;
+	server->imap->login_executable = PKG_LIBEXECDIR"/imap-login";
+	server->imap->mail_executable = PKG_LIBEXECDIR"/imap";
+
+	server->pop3->protocol = MAIL_PROTOCOL_POP3;
+	server->pop3->login_executable = PKG_LIBEXECDIR"/pop3-login";
+	server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3";
+
+	return server;
 }
 
-static const char *parse_setting(const char *key, const char *value,
-				 void *context)
+static int parse_section(const char *type, const char *name, void *context,
+			 const char **errormsg)
 {
-	struct settings *set = context;
-	const char *error;
+	struct settings_parse_ctx *ctx = context;
+	struct server_settings *server;
 
-	/* check defaults first, there's a few login_ settings defined in it
-	   which need to be checked before trying to feed it to login
-	   handler.. */
-	error = parse_setting_from_defs(settings_pool, setting_defs,
-					set, key, value);
-	if (error == NULL)
-		return NULL;
+	if (type == NULL) {
+		/* section closing */
+		if (ctx->level > 0) {
+			ctx->level--;
+			ctx->protocol = MAIL_PROTOCOL_ANY;
+		} else {
+			ctx->type = ctx->parent_type;
+			ctx->parent_type = SETTINGS_TYPE_ROOT;
+			ctx->server = ctx->root;
+			ctx->auth = NULL;
+		}
+		return TRUE;
+	}
 
-	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";
+	if (strcmp(type, "server") == 0) {
+		if (ctx->type != SETTINGS_TYPE_ROOT) {
+			*errormsg = "Server section not allowed here";
+			return FALSE;
+		}
 
-		return parse_setting_from_defs(settings_pool, auth_setting_defs,
-					       set->auths, key + 5, value);
+		ctx->parent_type = ctx->type;
+		ctx->type = SETTINGS_TYPE_SERVER;
+
+		ctx->server = create_new_server(name,
+						ctx->server->imap,
+						ctx->server->pop3);
+                server = ctx->root;
+		while (server->next != NULL)
+			server = server->next;
+		server->next = ctx->server;
+		return TRUE;
 	}
 
-	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";
+	if (strcmp(type, "protocol") == 0) {
+		if ((ctx->type != SETTINGS_TYPE_ROOT &&
+		     ctx->type != SETTINGS_TYPE_SERVER) ||
+		    ctx->level != 0) {
+			*errormsg = "Protocol section not allowed here";
+			return FALSE;
+		}
 
-		return parse_setting_from_defs(settings_pool,
-					       login_setting_defs,
-					       set->logins, key + 6, value);
+		if (strcmp(name, "imap") == 0)
+			ctx->protocol = MAIL_PROTOCOL_IMAP;
+		else if (strcmp(name, "pop3") == 0)
+			ctx->protocol = MAIL_PROTOCOL_POP3;
+		else {
+			*errormsg = "Unknown protocol name";
+			return FALSE;
+		}
+		ctx->level++;
+		return TRUE;
 	}
 
-	return error;
+	if (strcmp(type, "auth") == 0) {
+		if (ctx->type != SETTINGS_TYPE_ROOT &&
+		    ctx->type != SETTINGS_TYPE_SERVER) {
+			*errormsg = "Auth section not allowed here";
+			return FALSE;
+		}
+
+		ctx->type = SETTINGS_TYPE_AUTH;
+		ctx->auth = parse_new_auth(ctx->server, name, errormsg);
+		return ctx->auth != NULL;
+	}
+
+	*errormsg = "Unknown section type";
+	return FALSE;
 }
 
-void master_settings_read(const char *path)
+int master_settings_read(const char *path)
 {
+	struct settings_parse_ctx ctx;
+	struct server_settings *server, *prev;
+	struct auth_settings *auth;
+	pool_t temp;
+
+	memset(&ctx, 0, sizeof(ctx));
+
 	p_clear(settings_pool);
-	set = p_new(settings_pool, struct settings, 1);
-	*set = default_settings;
 
-	settings_read(path, parse_setting, set);
+	ctx.type = SETTINGS_TYPE_ROOT;
+	ctx.protocol = MAIL_PROTOCOL_ANY;
+	ctx.server = ctx.root =
+		create_new_server("default",
+				  &default_settings, &default_settings);
 
-        settings_verify(set);
+	if (!settings_read(path, NULL, parse_setting, parse_section, &ctx))
+		return FALSE;
+
+	if (ctx.level != 0) {
+		i_error("Missing '}'");
+		return FALSE;
+	}
+
+	/* If server sections were defined, skip the root */
+	if (ctx.root->next != NULL)
+		ctx.root = ctx.root->next;
+
+	prev = NULL;
+	for (server = ctx.root; server != NULL; server = server->next) {
+		if (!settings_is_active(server->imap))
+			server->imap = NULL;
+		else {
+			if (!settings_verify(server->imap))
+				return FALSE;
+			server->defaults = server->imap;
+		}
+
+		if (!settings_is_active(server->pop3))
+			server->pop3 = NULL;
+		else {
+			if (!settings_verify(server->pop3))
+				return FALSE;
+			if (server->defaults == NULL)
+				server->defaults = server->pop3;
+		}
+
+		if (server->defaults == NULL) {
+			if (prev == NULL)
+				ctx.root = server->next;
+			else
+				prev->next = server->next;
+		} else {
+                        auth = server->auths;
+			for (; auth != NULL; auth = auth->next) {
+				if (!auth_settings_verify(auth))
+					return FALSE;
+			}
+			prev = server;
+		}
+	}
+
+	/* settings ok, swap them */
+	temp = settings_pool;
+	settings_pool = settings2_pool;
+	settings2_pool = temp;
+
+	settings_root = ctx.root;
+	return TRUE;
 }
 
 void master_settings_init(void)
 {
-	settings_pool = pool_alloconly_create("settings", 1024);
+	settings_pool = pool_alloconly_create("settings", 2048);
+	settings2_pool = pool_alloconly_create("settings2", 2048);
 }
 
 void master_settings_deinit(void)
 {
 	pool_unref(settings_pool);
+	pool_unref(settings2_pool);
 }

Index: master-settings.h
===================================================================
RCS file: /home/cvs/dovecot/src/master/master-settings.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- master-settings.h	2 Jul 2003 01:02:27 -0000	1.13
+++ master-settings.h	10 Jul 2003 03:04:07 -0000	1.14
@@ -1,7 +1,26 @@
 #ifndef __MASTER_SETTINGS_H
 #define __MASTER_SETTINGS_H
 
+enum mail_protocol {
+        MAIL_PROTOCOL_ANY,
+        MAIL_PROTOCOL_IMAP,
+        MAIL_PROTOCOL_POP3
+};
+
+struct server_settings {
+	struct server_settings *next;
+
+	const char *name;
+	struct settings *defaults;
+	struct settings *imap;
+	struct settings *pop3;
+	struct auth_settings *auths;
+};
+
 struct settings {
+	struct server_settings *server;
+	enum mail_protocol protocol;
+
 	/* common */
 	const char *base_dir;
 	const char *log_path;
@@ -10,10 +29,8 @@
 
 	/* general */
 	const char *protocols;
-	const char *imap_listen;
-	const char *imaps_listen;
-	const char *pop3_listen;
-	const char *pop3s_listen;
+	const char *listen;
+	const char *ssl_listen;
 
 	int ssl_disable;
 	const char *ssl_cert_file;
@@ -21,11 +38,20 @@
 	const char *ssl_parameters_file;
 	unsigned int ssl_parameters_regenerate;
 	int disable_plaintext_auth;
+	int verbose_ssl;
 
 	/* login */
 	const char *login_dir;
+	const char *login_executable;
+	const char *login_user;
+
+	int login_process_per_connection;
 	int login_chroot;
-	int verbose_ssl;
+
+	unsigned int login_process_size;
+	unsigned int login_processes_count;
+	unsigned int login_max_processes_count;
+	unsigned int login_max_logging_users;
 
 	/* mail */
 	const char *valid_chroot_dirs;
@@ -47,51 +73,30 @@
 	int mail_read_mmaped;
 	int maildir_copy_with_hardlinks;
 	int maildir_check_content_changes;
-	char *mbox_locks;
+	const char *mbox_locks;
 	int mbox_read_dotlock;
 	unsigned int mbox_lock_timeout;
 	unsigned int mbox_dotlock_change_timeout;
 	unsigned int umask;
 	int mail_drop_priv_before_exec;
 
+	const char *mail_executable;
+	unsigned int mail_process_size;
+	int mail_use_modules;
+	const char *mail_modules;
+
 	/* imap */
-	const char *imap_executable;
-	unsigned int imap_process_size;
 	unsigned int imap_max_line_length;
-	int imap_use_modules;
-	const char *imap_modules;
-
-	/* pop3 */
-	const char *pop3_executable;
-	unsigned int pop3_process_size;
-	int pop3_use_modules;
-	const char *pop3_modules;
 
 	/* .. */
+	uid_t login_uid;
 	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 */
+	int listen_fd, ssl_listen_fd;
 };
 
 struct auth_settings {
+	struct server_settings *parent;
 	struct auth_settings *next;
 
 	const char *name;
@@ -112,9 +117,9 @@
 	unsigned int process_size;
 };
 
-extern struct settings *set;
+extern struct server_settings *settings_root;
 
-void master_settings_read(const char *path);
+int master_settings_read(const char *path);
 
 void master_settings_init(void);
 void master_settings_deinit(void);

Index: ssl-init.c
===================================================================
RCS file: /home/cvs/dovecot/src/master/ssl-init.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- ssl-init.c	30 Jan 2003 17:59:32 -0000	1.10
+++ ssl-init.c	10 Jul 2003 03:04:07 -0000	1.11
@@ -38,7 +38,7 @@
 		i_fatal("rename(%s, %s) failed: %m", temp_fname, fname);
 }
 
-static void start_generate_process(void)
+static void start_generate_process(struct settings *set)
 {
 	pid_t pid;
 
@@ -64,19 +64,19 @@
 	generating = FALSE;
 }
 
-static void check_parameters_file(void *context __attr_unused__)
+static int check_parameters_file_set(struct settings *set)
 {
 	struct stat st;
 	time_t regen_time;
 
-	if (set->ssl_parameters_file == NULL || set->ssl_disable || generating)
-		return;
+	if (set->ssl_parameters_file == NULL || set->ssl_disable)
+		return TRUE;
 
 	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);
-			return;
+			return TRUE;
 		}
 
 		st.st_mtime = 0;
@@ -86,8 +86,29 @@
 	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();
+	    st.st_uid != geteuid() || st.st_gid != getegid()) {
+		start_generate_process(set);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void check_parameters_file(void *context __attr_unused__)
+{
+	struct server_settings *server;
+
+	if (generating)
+		return;
+
+	for (server = settings_root; server != NULL; server = server->next) {
+		if (server->imap != NULL &&
+		    !check_parameters_file_set(server->imap))
+			break;
+		if (server->pop3 != NULL &&
+		    !check_parameters_file_set(server->pop3))
+			break;
+	}
 }
 
 void ssl_init(void)



More information about the dovecot-cvs mailing list