changeset 10179:afe52d60989c HEAD

Moved default service settings from master.conf to source code.
author Timo Sirainen <tss@iki.fi>
date Fri, 23 Oct 2009 21:47:30 -0400
parents 272bec780e26
children 2571cbc88302
files doc/example-config/conf.d/master.conf src/anvil/Makefile.am src/anvil/anvil-settings.c src/auth/auth-settings.c src/config/Makefile.am src/config/config-parser.c src/config/config-settings.c src/config/settings-get.pl src/dict/dict-settings.c src/imap-login/imap-login-settings.c src/imap/imap-settings.c src/lib-master/Makefile.am src/lib-master/service-settings.h src/lib-settings/settings-parser.c src/lib-settings/settings-parser.h src/lmtp/lmtp-settings.c src/log/Makefile.am src/log/log-settings.c src/master/master-settings.c src/master/master-settings.h src/pop3-login/pop3-login-settings.c src/pop3/pop3-settings.c src/ssl-params/ssl-params-settings.c
diffstat 23 files changed, 669 insertions(+), 234 deletions(-) [+]
line wrap: on
line diff
--- a/doc/example-config/conf.d/master.conf	Fri Oct 23 20:11:59 2009 -0400
+++ b/doc/example-config/conf.d/master.conf	Fri Oct 23 21:47:30 2009 -0400
@@ -2,70 +2,7 @@
 default_client_limit = 1000
 default_vsz_limit = 256
 
-service config {
-  type = config
-  executable = config
-
-  unix_listener config {
-    mode = 0666
-  }
-}
-
-service log {
-  type = log
-  executable = log
-
-  process_limit = 1
-}
-
-service anvil {
-  type = anvil
-  executable = anvil
-  process_limit = 1
-  user = dovecot
-  chroot = empty/
-
-  unix_listener anvil {
-  }
-}
-
-service auth {
-  executable = auth
-
-  unix_listener login/auth {
-    mode = 0666
-  }
-
-  # Postfix smtp-auth
-  #unix_listener /var/spool/postfix/private/auth {
-  #  mode = 0666
-  #}
-
-  # Dovecot LDA
-  unix_listener auth-userdb {
-    mode = 0600
-  }
-
-  unix_listener auth-master {
-    mode = 0600
-  }
-
-  process_limit = 1
-}
-
-service auth-worker {
-  executable = auth -w
-  client_limit = 1
-
-  unix_listener auth-worker {
-  }
-}
-
 service imap-login {
-  protocol = imap
-  type = login
-  executable = imap-login
-
   inet_listener {
     port = 143
   }
@@ -74,45 +11,16 @@
     ssl = yes
   }
 
-  user = dovecot
   # Number of connections to handle before starting a new process. Typically
   # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
   # is faster. <doc/wiki/LoginProcess.txt>
-  service_count = 1
-  # If you set service_count=0, you probably need to grow this.
-  vsz_limit = 64
-  # The only reason not to chroot login process is if you wish to run the
-  # whole Dovecot without roots. <doc/wiki/Rootless.txt>
-  chroot = login
-}
-
-service imap {
-  protocol = imap
+  #service_count = 1
 
-  # This would write rawlogs into user's ~/dovecot.rawlog/, if it exists:
-  #   executable = rawlog /usr/libexec/dovecot/imap
-  # <doc/wiki/Debugging/Rawlog.txt>
-  #
-  # This would attach gdb into the imap process and write backtraces into
-  # /tmp/gdbhelper.* files:
-  #   executable = gdbhelper /usr/libexec/dovecot/imap
-  executable = imap
-
-  # Most of the memory goes to mmap()ing files. You may need to increase this
-  # limit if you have huge mailboxes.
-  #vsz_limit = 256
-
-  service_count = 1
-  unix_listener login/imap {
-    mode = 0666
-  }
+  # If you set service_count=0, you probably need to grow this.
+  #vsz_limit = 64
 }
 
 service pop3-login {
-  protocol = pop3
-  type = login
-  executable = pop3-login
-
   inet_listener {
     port = 110
   }
@@ -120,45 +28,23 @@
     port = 995
     ssl = yes
   }
-
-  # See imap-login service for description of these
-  user = dovecot
-  service_count = 1
-  vsz_limit = 64
-  chroot = login
-}
-
-service pop3 {
-  protocol = pop3
-  executable = pop3
-
-  service_count = 1
-  unix_listener login/pop3 {
-    mode = 0666
-  }
 }
 
 service lmtp {
-  protocol = lmtp
-  executable = lmtp
-
-  unix_listener lmtp {
-    mode = 0666
-  }
+  #inet_listener {
+  #  port = 
+  #}
 }
 
-service dict {
-  executable = dict
-
-  unix_listener dict {
-    mode = 0666
-  }
+service imap {
+  # Most of the memory goes to mmap()ing files. You may need to increase this
+  # limit if you have huge mailboxes.
+  #vsz_limit = 256
 }
 
-service ssl-params {
-  executable = ssl-params
-
-  unix_listener login/ssl-params {
-    mode = 0666
-  }
+service auth {
+  # Postfix smtp-auth
+  #unix_listener /var/spool/postfix/private/auth {
+  #  mode = 0666
+  #}
 }
--- a/src/anvil/Makefile.am	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/anvil/Makefile.am	Fri Oct 23 21:47:30 2009 -0400
@@ -16,6 +16,7 @@
 anvil_SOURCES = \
 	main.c \
 	anvil-connection.c \
+	anvil-settings.c \
 	connect-limit.c
 
 noinst_HEADERS = \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/anvil/anvil-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -0,0 +1,45 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "settings-parser.h"
+#include "service-settings.h"
+
+#include <stddef.h>
+
+/* <settings checks> */
+static struct file_listener_settings anvil_unix_listeners_array[] = {
+	{ "anvil", 0600, "", "" }
+};
+static struct file_listener_settings *anvil_unix_listeners[] = {
+	&anvil_unix_listeners_array[0]
+};
+static buffer_t anvil_unix_listeners_buf = {
+	anvil_unix_listeners, sizeof(anvil_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings anvil_service_settings = {
+	MEMBER(name) "anvil",
+	MEMBER(protocol) "",
+	MEMBER(type) "anvil",
+	MEMBER(executable) "anvil",
+	MEMBER(user) "dovecot",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "empty",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 1,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &anvil_unix_listeners_buf,
+				   sizeof(anvil_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
--- a/src/auth/auth-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/auth/auth-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -4,6 +4,7 @@
 #include "array.h"
 #include "settings-parser.h"
 #include "master-service-settings.h"
+#include "service-settings.h"
 #include "auth-settings.h"
 
 #include <stddef.h>
@@ -13,6 +14,84 @@
 
 static bool auth_settings_check(void *_set, pool_t pool, const char **error_r);
 
+/* <settings checks> */
+static struct file_listener_settings auth_unix_listeners_array[] = {
+	{ "login/auth", 0666, "", "" },
+	{ "auth-userdb", 0600, "", "" },
+	{ "auth-master", 0600, "", "" }
+};
+static struct file_listener_settings *auth_unix_listeners[] = {
+	&auth_unix_listeners_array[0],
+	&auth_unix_listeners_array[1],
+	&auth_unix_listeners_array[2]
+};
+static buffer_t auth_unix_listeners_buf = {
+	auth_unix_listeners, sizeof(auth_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings auth_service_settings = {
+	MEMBER(name) "auth",
+	MEMBER(protocol) "",
+	MEMBER(type) "",
+	MEMBER(executable) "auth",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 1,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &auth_unix_listeners_buf,
+				   sizeof(auth_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
+/* <settings checks> */
+static struct file_listener_settings auth_worker_unix_listeners_array[] = {
+	{ "auth-worker", 0600, "", "" }
+};
+static struct file_listener_settings *auth_worker_unix_listeners[] = {
+	&auth_worker_unix_listeners_array[0]
+};
+static buffer_t auth_worker_unix_listeners_buf = {
+	auth_worker_unix_listeners, sizeof(auth_worker_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings auth_worker_service_settings = {
+	MEMBER(name) "auth-worker",
+	MEMBER(protocol) "",
+	MEMBER(type) "",
+	MEMBER(executable) "auth -w",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 1,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &auth_worker_unix_listeners_buf,
+				   sizeof(auth_worker_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct auth_passdb_settings, name), NULL }
--- a/src/config/Makefile.am	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/config/Makefile.am	Fri Oct 23 21:47:30 2009 -0400
@@ -54,4 +54,5 @@
 	$(top_srcdir)/src/config/settings-get.pl $(SETTING_FILES) > all-settings.c || rm -f all-settings.c
 
 EXTRA_DIST = \
+	config-settings.c \
 	settings-get.pl
--- a/src/config/config-parser.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/config/config-parser.c	Fri Oct 23 21:47:30 2009 -0400
@@ -565,41 +565,6 @@
 	return 0;
 }
 
-static const char *section_name_escape(const char *name)
-{
-#define CHAR_NEED_ESCAPE(c) \
-	((c) == '=' || (c) == SETTINGS_SEPARATOR || (c) == '\\')
-	string_t *str;
-	unsigned int i;
-
-	for (i = 0; name[i] != '\0'; i++) {
-		if (CHAR_NEED_ESCAPE(name[i]))
-			break;
-	}
-	if (name[i] == '\0')
-		return name;
-
-	str = t_str_new(i + strlen(name+i) + 8);
-	str_append_n(str, name, i);
-	for (; name[i] != '\0'; i++) {
-		switch (name[i]) {
-		case '=':
-			str_append(str, "\\e");
-			break;
-		case SETTINGS_SEPARATOR:
-			str_append(str, "\\s");
-			break;
-		case '\\':
-			str_append(str, "\\\\");
-			break;
-		default:
-			str_append_c(str, name[i]);
-			break;
-		}
-	}
-	return str_c(str);
-}
-
 int config_parse_file(const char *path, bool expand_files,
 		      const char **error_r)
 {
@@ -689,7 +654,7 @@
 				/* no section name, use a counter */
 				section_name = dec2str(counter++);
 			} else {
-				section_name = section_name_escape(value);
+				section_name = settings_section_escape(value);
 			}
 			str_truncate(str, pathlen);
 			str_append(str, key);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/config/config-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -0,0 +1,45 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "settings-parser.h"
+#include "service-settings.h"
+
+#include <stddef.h>
+
+/* <settings checks> */
+static struct file_listener_settings config_unix_listeners_array[] = {
+	{ "config", 0600, "", "" }
+};
+static struct file_listener_settings *config_unix_listeners[] = {
+	&config_unix_listeners_array[0]
+};
+static buffer_t config_unix_listeners_buf = {
+	config_unix_listeners, sizeof(config_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings config_service_settings = {
+	MEMBER(name) "config",
+	MEMBER(protocol) "",
+	MEMBER(type) "config",
+	MEMBER(executable) "config",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &config_unix_listeners_buf,
+				   sizeof(config_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
--- a/src/config/settings-get.pl	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/config/settings-get.pl	Fri Oct 23 21:47:30 2009 -0400
@@ -10,7 +10,9 @@
 print '#include <stddef.h>'."\n";
 print '#include <unistd.h>'."\n";
 print '#define CONFIG_BINARY'."\n";
+print 'extern buffer_t config_all_services_buf;';
 
+my @services = ();
 my %parsers = {};
 
 foreach my $file (@ARGV) {
@@ -31,6 +33,9 @@
 	  /struct setting_define.*{/ ||
 	  /struct .*_default_settings = {/) {
 	$state++;
+      } elsif (/^struct service_settings (.*) = {/) {
+	$state++;
+	push @services, $1;
       } elsif (/^(static )?const struct setting_parser_info (.*) = {/) {
 	$cur_name = $2;
 	$state++ if ($cur_name !~ /^\*default_/);
@@ -90,6 +95,16 @@
   close $f;
 }
 
+print "static struct service_settings *config_all_services[] = {\n";
+
+foreach my $name (@services) {
+  print "\t&$name,\n";
+}
+print "};\n";
+print "buffer_t config_all_services_buf = {\n";
+print "\tconfig_all_services, sizeof(config_all_services), { 0, }\n";
+print "};\n";
+
 print "const struct setting_parser_info *all_roots[] = {\n";
 foreach my $name (keys %parsers) {
   my $module = $parsers{$name};
--- a/src/dict/dict-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/dict/dict-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -1,9 +1,48 @@
 /* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "dict-settings.h"
 
+/* <settings checks> */
+static struct file_listener_settings dict_unix_listeners_array[] = {
+	{ "dict", 0600, "", "" }
+};
+static struct file_listener_settings *dict_unix_listeners[] = {
+	&dict_unix_listeners_array[0]
+};
+static buffer_t dict_unix_listeners_buf = {
+	dict_unix_listeners, sizeof(dict_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings dict_service_settings = {
+	MEMBER(name) "dict",
+	MEMBER(protocol) "",
+	MEMBER(type) "",
+	MEMBER(executable) "dict",
+	MEMBER(user) "dovecot",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &dict_unix_listeners_buf,
+				   sizeof(dict_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct dict_settings, name), NULL }
--- a/src/imap-login/imap-login-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/imap-login/imap-login-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -2,11 +2,36 @@
 
 #include "lib.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "login-settings.h"
 #include "imap-login-settings.h"
 
 #include <stddef.h>
 
+struct service_settings imap_login_service_settings = {
+	MEMBER(name) "imap-login",
+	MEMBER(protocol) "imap",
+	MEMBER(type) "login",
+	MEMBER(executable) "imap-login",
+	MEMBER(user) "dovecot",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "login",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 1,
+	MEMBER(vsz_limit) 64,
+
+	MEMBER(unix_listeners) ARRAY_INIT,
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct imap_login_settings, name), NULL }
--- a/src/imap/imap-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/imap/imap-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -1,7 +1,9 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "mail-storage-settings.h"
 #include "imap-settings.h"
 
@@ -12,6 +14,43 @@
 static bool imap_settings_verify(void *_set, pool_t pool,
 				 const char **error_r);
 
+/* <settings checks> */
+static struct file_listener_settings imap_unix_listeners_array[] = {
+	{ "login/imap", 0666, "", "" }
+};
+static struct file_listener_settings *imap_unix_listeners[] = {
+	&imap_unix_listeners_array[0]
+};
+static buffer_t imap_unix_listeners_buf = {
+	imap_unix_listeners, sizeof(imap_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings imap_service_settings = {
+	MEMBER(name) "imap",
+	MEMBER(protocol) "imap",
+	MEMBER(type) "",
+	MEMBER(executable) "imap",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 1,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &imap_unix_listeners_buf,
+				   sizeof(imap_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #undef DEFLIST
 #define DEF(type, name) \
--- a/src/lib-master/Makefile.am	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/lib-master/Makefile.am	Fri Oct 23 21:47:30 2009 -0400
@@ -24,4 +24,5 @@
 	master-service.h \
 	master-service-private.h \
 	master-service-settings.h \
+	service-settings.h \
 	syslog-util.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-master/service-settings.h	Fri Oct 23 21:47:30 2009 -0400
@@ -0,0 +1,57 @@
+#ifndef SERVICE_SETTINGS_H
+#define SERVICE_SETTINGS_H
+
+/* <settings checks> */
+enum service_type {
+	SERVICE_TYPE_UNKNOWN,
+	SERVICE_TYPE_LOG,
+	SERVICE_TYPE_ANVIL,
+	SERVICE_TYPE_CONFIG,
+	SERVICE_TYPE_LOGIN
+};
+/* </settings checks> */
+
+struct file_listener_settings {
+	const char *path;
+	unsigned int mode;
+	const char *user;
+	const char *group;
+};
+ARRAY_DEFINE_TYPE(file_listener_settings, struct file_listener_settings *);
+
+struct inet_listener_settings {
+	const char *address;
+	unsigned int port;
+	bool ssl;
+};
+
+struct service_settings {
+	const char *name;
+	const char *protocol;
+	const char *type;
+	const char *executable;
+	const char *user;
+	const char *group;
+	const char *privileged_group;
+	const char *extra_groups;
+	const char *chroot;
+
+	bool drop_priv_before_exec;
+
+	unsigned int process_min_avail;
+	unsigned int process_limit;
+	unsigned int client_limit;
+	unsigned int service_count;
+	unsigned int vsz_limit;
+
+	ARRAY_TYPE(file_listener_settings) unix_listeners;
+	ARRAY_TYPE(file_listener_settings) fifo_listeners;
+	ARRAY_DEFINE(inet_listeners, struct inet_listener_settings *);
+
+	/* internal to master: */
+	struct master_settings *master_set;
+	enum service_type parsed_type;
+	unsigned int login_dump_core:1;
+};
+
+#endif
--- a/src/lib-settings/settings-parser.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/lib-settings/settings-parser.c	Fri Oct 23 21:47:30 2009 -0400
@@ -23,6 +23,8 @@
         struct setting_link *parent;
 	const struct setting_parser_info *info;
 
+	const char *full_key;
+
 	/* Points to array inside parent->set_struct.
 	   SET_DEFLIST : array of set_structs
 	   SET_STRLIST : array of const_strings */
@@ -61,6 +63,10 @@
 	MEMBER(parent_offset) (size_t)-1
 };
 
+static void
+setting_parser_copy_defaults(struct setting_parser_context *ctx, 
+			     const struct setting_parser_info *info,
+			     struct setting_link *link);
 static int
 settings_apply(struct setting_link *dest_link,
 	       const struct setting_link *src_link,
@@ -74,8 +80,71 @@
 }
 
 static void
-setting_parser_copy_defaults(const struct setting_parser_info *info,
-			     pool_t pool, void *dest)
+copy_unique_defaults(struct setting_parser_context *ctx, 
+		     const struct setting_define *def,
+		     struct setting_link *link)
+{
+	ARRAY_TYPE(void_array) *arr =
+		STRUCT_MEMBER_P(link->set_struct, def->offset);
+	ARRAY_TYPE(void_array) *carr = NULL;
+	struct setting_link *new_link;
+	struct setting_parser_info info;
+	const char *const *keyp, *key, *prefix;
+	void *const *children;
+	void *new_set, *new_changes = NULL;
+	char *full_key;
+	unsigned int i, count;
+
+	if (!array_is_created(arr))
+		return;
+
+	children = array_get(arr, &count);
+	if (link->change_struct != NULL) {
+		carr = STRUCT_MEMBER_P(link->change_struct, def->offset);
+		i_assert(!array_is_created(carr));
+		p_array_init(carr, ctx->set_pool, count + 4);
+	}
+	p_array_init(arr, ctx->set_pool, count + 4);
+
+	memset(&info, 0, sizeof(info));
+	info = *def->list_info;
+
+	for (i = 0; i < count; i++) {
+		new_set = p_malloc(ctx->set_pool, info.struct_size);
+		array_append(arr, &new_set, 1);
+
+		if (link->change_struct != NULL) {
+			new_changes = p_malloc(ctx->set_pool, info.struct_size);
+			array_append(carr, &new_changes, 1);
+		}
+
+		keyp = CONST_PTR_OFFSET(children[i], info.type_offset);
+		key = settings_section_escape(*keyp);
+
+		new_link = p_new(ctx->set_pool, struct setting_link, 1);
+		prefix = link->full_key == NULL ?
+			t_strconcat(def->key, SETTINGS_SEPARATOR_S, NULL) :
+			t_strconcat(link->full_key, SETTINGS_SEPARATOR_S,
+				    def->key, SETTINGS_SEPARATOR_S,NULL);
+		full_key = p_strconcat(ctx->set_pool, prefix, key, NULL);
+		new_link->full_key = full_key;
+		new_link->parent = link;
+		new_link->info = def->list_info;
+		new_link->array = arr;
+		new_link->change_array = carr;
+		new_link->set_struct = new_set;
+		new_link->change_struct = new_changes;
+		hash_table_insert(ctx->links, full_key, new_link);
+
+		info.defaults = children[i];
+		setting_parser_copy_defaults(ctx, &info, new_link);
+	}
+}
+
+static void
+setting_parser_copy_defaults(struct setting_parser_context *ctx, 
+			     const struct setting_parser_info *info,
+			     struct setting_link *link)
 {
 	const struct setting_define *def;
 	const char *p, **strp;
@@ -83,28 +152,31 @@
 	if (info->defaults == NULL)
 		return;
 
-	memcpy(dest, info->defaults, info->struct_size);
+	memcpy(link->set_struct, info->defaults, info->struct_size);
 	for (def = info->defines; def->key != NULL; def++) {
 		switch (def->type) {
 		case SET_ENUM: {
 			/* fix enums by dropping everything after the
 			   first ':' */
-			strp = STRUCT_MEMBER_P(dest, def->offset);
+			strp = STRUCT_MEMBER_P(link->set_struct, def->offset);
 			p = strchr(*strp, ':');
 			if (p != NULL)
-				*strp = p_strdup_until(pool, *strp, p);
+				*strp = p_strdup_until(ctx->set_pool, *strp, p);
 			break;
 		}
 		case SET_STR_VARS: {
 			/* insert the unexpanded-character */
-			strp = STRUCT_MEMBER_P(dest, def->offset);
+			strp = STRUCT_MEMBER_P(link->set_struct, def->offset);
 			if (*strp != NULL) {
-				*strp = p_strconcat(pool,
+				*strp = p_strconcat(ctx->set_pool,
 						    SETTING_STRVAR_UNEXPANDED,
 						    *strp, NULL);
 			}
 			break;
 		}
+		case SET_DEFLIST_UNIQUE:
+			copy_unique_defaults(ctx, def, link);
+			break;
 		default:
 			break;
 		}
@@ -127,6 +199,8 @@
 	ctx->set_pool = set_pool;
 	ctx->parser_pool = parser_pool;
 	ctx->flags = flags;
+	ctx->links = hash_table_create(default_pool, ctx->parser_pool, 0,
+				       str_hash, (hash_cmp_callback_t *)strcmp);
 
 	ctx->root_count = count;
 	ctx->roots = p_new(ctx->parser_pool, struct setting_link, count);
@@ -141,12 +215,9 @@
 			ctx->roots[i].change_struct =
 				p_malloc(ctx->set_pool, roots[i]->struct_size);
 		}
-		setting_parser_copy_defaults(roots[i], ctx->set_pool,
-					     ctx->roots[i].set_struct);
+		setting_parser_copy_defaults(ctx, roots[i], &ctx->roots[i]);
 	}
 
-	ctx->links = hash_table_create(default_pool, ctx->parser_pool, 0,
-				       str_hash, (hash_cmp_callback_t *)strcmp);
 	pool_ref(ctx->set_pool);
 	return ctx;
 }
@@ -301,6 +372,7 @@
 		}
 
 		link = p_new(ctx->parser_pool, struct setting_link, 1);
+		link->full_key = full_key;
 		link->parent = parent;
 		link->info = info;
 		link->array = result;
@@ -322,10 +394,6 @@
 	if (link->set_struct == NULL) {
 		link->set_struct =
 			p_malloc(ctx->set_pool, link->info->struct_size);
-		setting_parser_copy_defaults(link->info, ctx->set_pool,
-					     link->set_struct);
-		array_append(link->array, &link->set_struct, 1);
-
 		if ((ctx->flags & SETTINGS_PARSER_FLAG_TRACK_CHANGES) != 0) {
 			link->change_struct = p_malloc(ctx->set_pool,
 						       link->info->struct_size);
@@ -333,6 +401,9 @@
 				     &link->change_struct, 1);
 		}
 
+		setting_parser_copy_defaults(ctx, link->info, link);
+		array_append(link->array, &link->set_struct, 1);
+
 		if (link->info->parent_offset != (size_t)-1 &&
 		    link->parent != NULL) {
 			ptr = STRUCT_MEMBER_P(link->set_struct,
@@ -1488,3 +1559,39 @@
 	}
 	return 0;
 }
+
+const char *settings_section_escape(const char *name)
+{
+#define CHAR_NEED_ESCAPE(c) \
+	((c) == '=' || (c) == SETTINGS_SEPARATOR || (c) == '\\')
+	string_t *str;
+	unsigned int i;
+
+	for (i = 0; name[i] != '\0'; i++) {
+		if (CHAR_NEED_ESCAPE(name[i]))
+			break;
+	}
+	if (name[i] == '\0')
+		return name;
+
+	str = t_str_new(i + strlen(name+i) + 8);
+	str_append_n(str, name, i);
+	for (; name[i] != '\0'; i++) {
+		switch (name[i]) {
+		case '=':
+			str_append(str, "\\e");
+			break;
+		case SETTINGS_SEPARATOR:
+			str_append(str, "\\s");
+			break;
+		case '\\':
+			str_append(str, "\\\\");
+			break;
+		default:
+			str_append_c(str, name[i]);
+			break;
+		}
+	}
+	return str_c(str);
+}
+
--- a/src/lib-settings/settings-parser.h	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/lib-settings/settings-parser.h	Fri Oct 23 21:47:30 2009 -0400
@@ -183,4 +183,7 @@
 				  const struct setting_parser_context *src,
 				  pool_t pool, const char **conflict_key_r);
 
+/* Return section name escaped */
+const char *settings_section_escape(const char *name);
+
 #endif
--- a/src/lmtp/lmtp-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/lmtp/lmtp-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -1,7 +1,9 @@
 /* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "master-service-settings.h"
 #include "lda-settings.h"
 #include "lmtp-settings.h"
@@ -9,6 +11,43 @@
 #include <stddef.h>
 #include <unistd.h>
 
+/* <settings checks> */
+static struct file_listener_settings lmtp_login_unix_listeners_array[] = {
+	{ "lmtp", 0666, "", "" }
+};
+static struct file_listener_settings *lmtp_login_unix_listeners[] = {
+	&lmtp_login_unix_listeners_array[0]
+};
+static buffer_t lmtp_login_unix_listeners_buf = {
+	lmtp_login_unix_listeners, sizeof(lmtp_login_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings lmtp_login_service_settings = {
+	MEMBER(name) "lmtp",
+	MEMBER(protocol) "lmtp",
+	MEMBER(type) "",
+	MEMBER(executable) "lmtp",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) 0,
+
+	MEMBER(unix_listeners) { { &lmtp_login_unix_listeners_buf,
+				   sizeof(lmtp_login_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct lmtp_settings, name), NULL }
--- a/src/log/Makefile.am	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/log/Makefile.am	Fri Oct 23 21:47:30 2009 -0400
@@ -12,6 +12,7 @@
 
 log_SOURCES = \
 	log-connection.c \
+	log-settings.c \
 	main.c
 
 noinst_HEADERS = \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/log/log-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -0,0 +1,32 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "service-settings.h"
+
+#include <stddef.h>
+
+struct service_settings log_service_settings = {
+	MEMBER(name) "log",
+	MEMBER(protocol) "",
+	MEMBER(type) "log",
+	MEMBER(executable) "log",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 1,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) ARRAY_INIT,
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
--- a/src/master/master-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/master/master-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -124,8 +124,6 @@
 };
 
 static const struct service_settings service_default_settings = {
-	MEMBER(master_set) NULL,
-
 	MEMBER(name) "",
 	MEMBER(protocol) "",
 	MEMBER(type) "",
@@ -213,7 +211,12 @@
 	MEMBER(first_valid_gid) 1,
 	MEMBER(last_valid_gid) 0,
 
+#ifndef CONFIG_BINARY
 	MEMBER(services) ARRAY_INIT
+#else
+	MEMBER(services) { { &config_all_services_buf,
+			     sizeof(struct service_settings *) } },
+#endif
 };
 
 const struct setting_parser_info master_setting_parser_info = {
--- a/src/master/master-settings.h	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/master/master-settings.h	Fri Oct 23 21:47:30 2009 -0400
@@ -1,58 +1,7 @@
 #ifndef MASTER_SETTINGS_H
 #define MASTER_SETTINGS_H
 
-/* <settings checks> */
-enum service_type {
-	SERVICE_TYPE_UNKNOWN,
-	SERVICE_TYPE_LOG,
-	SERVICE_TYPE_ANVIL,
-	SERVICE_TYPE_CONFIG,
-	SERVICE_TYPE_LOGIN
-};
-/* </settings checks> */
-
-struct file_listener_settings {
-	const char *path;
-	unsigned int mode;
-	const char *user;
-	const char *group;
-};
-ARRAY_DEFINE_TYPE(file_listener_settings, struct file_listener_settings *);
-
-struct inet_listener_settings {
-	const char *address;
-	unsigned int port;
-	bool ssl;
-};
-
-struct service_settings {
-	struct master_settings *master_set;
-
-	const char *name;
-	const char *protocol;
-	const char *type;
-	const char *executable;
-	const char *user;
-	const char *group;
-	const char *privileged_group;
-	const char *extra_groups;
-	const char *chroot;
-
-	bool drop_priv_before_exec;
-
-	unsigned int process_min_avail;
-	unsigned int process_limit;
-	unsigned int client_limit;
-	unsigned int service_count;
-	unsigned int vsz_limit;
-
-	ARRAY_TYPE(file_listener_settings) unix_listeners;
-	ARRAY_TYPE(file_listener_settings) fifo_listeners;
-	ARRAY_DEFINE(inet_listeners, struct inet_listener_settings *);
-
-	enum service_type parsed_type;
-	unsigned int login_dump_core:1;
-};
+#include "service-settings.h"
 
 struct master_settings {
 	const char *base_dir;
--- a/src/pop3-login/pop3-login-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/pop3-login/pop3-login-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -2,11 +2,36 @@
 
 #include "lib.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "login-settings.h"
 #include "pop3-login-settings.h"
 
 #include <stddef.h>
 
+struct service_settings pop3_login_service_settings = {
+	MEMBER(name) "pop3-login",
+	MEMBER(protocol) "pop3",
+	MEMBER(type) "login",
+	MEMBER(executable) "pop3-login",
+	MEMBER(user) "dovecot",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "login",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 1,
+	MEMBER(vsz_limit) 64,
+
+	MEMBER(unix_listeners) ARRAY_INIT,
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 static const struct setting_define pop3_login_setting_defines[] = {
 	SETTING_DEFINE_LIST_END
 };
--- a/src/pop3/pop3-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/pop3/pop3-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -1,7 +1,9 @@
 /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "mail-storage-settings.h"
 #include "pop3-settings.h"
 
@@ -12,6 +14,43 @@
 static bool pop3_settings_verify(void *_set, pool_t pool,
 				 const char **error_r);
 
+/* <settings checks> */
+static struct file_listener_settings pop3_unix_listeners_array[] = {
+	{ "login/pop3", 0666, "", "" }
+};
+static struct file_listener_settings *pop3_unix_listeners[] = {
+	&pop3_unix_listeners_array[0]
+};
+static buffer_t pop3_unix_listeners_buf = {
+	pop3_unix_listeners, sizeof(pop3_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings pop3_service_settings = {
+	MEMBER(name) "pop3",
+	MEMBER(protocol) "pop3",
+	MEMBER(type) "",
+	MEMBER(executable) "pop3",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 1,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &pop3_unix_listeners_buf,
+				   sizeof(pop3_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #undef DEFLIST
 #define DEF(type, name) \
--- a/src/ssl-params/ssl-params-settings.c	Fri Oct 23 20:11:59 2009 -0400
+++ b/src/ssl-params/ssl-params-settings.c	Fri Oct 23 21:47:30 2009 -0400
@@ -1,7 +1,9 @@
 /* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "buffer.h"
 #include "settings-parser.h"
+#include "service-settings.h"
 #include "master-service-settings.h"
 #include "ssl-params-settings.h"
 
@@ -9,6 +11,43 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+/* <settings checks> */
+static struct file_listener_settings ssl_params_unix_listeners_array[] = {
+	{ "login/ssl-params", 0666, "", "" }
+};
+static struct file_listener_settings *ssl_params_unix_listeners[] = {
+	&ssl_params_unix_listeners_array[0]
+};
+static buffer_t ssl_params_unix_listeners_buf = {
+	ssl_params_unix_listeners, sizeof(ssl_params_unix_listeners), { 0, }
+};
+/* </settings checks> */
+
+struct service_settings ssl_params_service_settings = {
+	MEMBER(name) "ssl-params",
+	MEMBER(protocol) "",
+	MEMBER(type) "",
+	MEMBER(executable) "ssl-params",
+	MEMBER(user) "",
+	MEMBER(group) "",
+	MEMBER(privileged_group) "",
+	MEMBER(extra_groups) "",
+	MEMBER(chroot) "",
+
+	MEMBER(drop_priv_before_exec) FALSE,
+
+	MEMBER(process_min_avail) 0,
+	MEMBER(process_limit) 0,
+	MEMBER(client_limit) 0,
+	MEMBER(service_count) 0,
+	MEMBER(vsz_limit) -1U,
+
+	MEMBER(unix_listeners) { { &ssl_params_unix_listeners_buf,
+				   sizeof(ssl_params_unix_listeners[0]) } },
+	MEMBER(fifo_listeners) ARRAY_INIT,
+	MEMBER(inet_listeners) ARRAY_INIT
+};
+
 #undef DEF
 #define DEF(type, name) \
 	{ type, #name, offsetof(struct ssl_params_settings, name), NULL }