summaryrefslogtreecommitdiffstats
path: root/src/config/old-set-parser.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/config/old-set-parser.c824
1 files changed, 824 insertions, 0 deletions
diff --git a/src/config/old-set-parser.c b/src/config/old-set-parser.c
new file mode 100644
index 0000000..d5302f8
--- /dev/null
+++ b/src/config/old-set-parser.c
@@ -0,0 +1,824 @@
+/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "settings-parser.h"
+#include "config-parser-private.h"
+#include "old-set-parser.h"
+#include "istream.h"
+#include "base64.h"
+
+static bool seen_ssl_parameters_dat;
+static const char *ssl_dh_parameters;
+
+#define config_apply_line (void)config_apply_line
+
+struct socket_set {
+ const char *path, *mode, *user, *group;
+ bool master;
+};
+
+struct old_set_parser {
+ const char *base_dir;
+ /* 1 when in auth {} section, >1 when inside auth { .. { .. } } */
+ unsigned int auth_section;
+ /* 1 when in socket listen {}, >1 when inside more of its sections */
+ unsigned int socket_listen_section;
+ bool seen_auth_section;
+ struct socket_set socket_set;
+};
+
+static const struct config_filter any_filter = {
+ .service = NULL
+};
+
+static const struct config_filter imap_filter = {
+ .service = "imap"
+};
+static const struct config_filter pop3_filter = {
+ .service = "pop3"
+};
+static const struct config_filter managesieve_filter = {
+ .service = "sieve"
+};
+
+static char *ssl_dh_value = NULL;
+static bool ssl_dh_loaded = FALSE;
+
+static void ATTR_FORMAT(2, 3)
+obsolete(struct config_parser_context *ctx, const char *str, ...)
+{
+ static bool seen_obsoletes = FALSE;
+ va_list args;
+
+ if (!seen_obsoletes) {
+ i_warning("NOTE: You can get a new clean config file with: "
+ "doveconf -Pn > dovecot-new.conf");
+ seen_obsoletes = TRUE;
+ }
+
+ va_start(args, str);
+ i_warning("Obsolete setting in %s:%u: %s",
+ ctx->cur_input->path, ctx->cur_input->linenum,
+ t_strdup_vprintf(str, args));
+ va_end(args);
+}
+
+static void set_rename(struct config_parser_context *ctx,
+ const char *old_key, const char *key, const char *value)
+{
+ obsolete(ctx, "%s has been renamed to %s", old_key, key);
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE, key, value);
+}
+
+static bool old_settings_ssl_dh_read(const char **value, const char **error_r)
+{
+
+ if (ssl_dh_parameters != NULL) *value = ssl_dh_parameters;
+
+ const char *fn = t_strconcat(PKG_STATEDIR, "/ssl-parameters.dat", NULL);
+ buffer_t *data = t_buffer_create(300);
+ string_t *b64_data = t_str_new(500);
+ size_t siz;
+ unsigned short keysize;
+ unsigned int off=0;
+
+ /* try read it */
+ struct istream *is = i_stream_create_file(fn, IO_BLOCK_SIZE);
+
+ if (is->stream_errno == ENOENT) {
+ /* this is given because the ssl-parameters.dat file is no more there
+ and we don't want to to make go searching for the file
+ this code is only ever reached if ssl_dh_parameters is empty anyways
+ */
+ /* check moved to correct place from here */
+ *value = NULL;
+ i_stream_unref(&is);
+ return TRUE;
+ } else if (is->stream_errno != 0) {
+ *error_r = t_strdup(i_stream_get_error(is));
+ i_stream_unref(&is);
+ return FALSE;
+ }
+
+ /* then try to read the rest of the data */
+ while(i_stream_read(is) > 0) {
+ const unsigned char *buf = i_stream_get_data(is, &siz);
+ if (siz < 88) break;
+ memcpy(&keysize, buf, 2);
+ if (keysize == 512) {
+ memcpy(&off, buf+4, 4);
+ off += 16; // skip headers
+ } else {
+ off = 8; // skip header
+ }
+ if (off > siz) break;
+ buffer_append(data, buf+off, siz);
+ break;
+ }
+
+ const void *tmp = buffer_get_data(data, &siz);
+
+ if (siz > 4) {
+ str_append(b64_data, "-----BEGIN DH PARAMETERS-----\n");
+ base64_encode(tmp, siz-4, b64_data);
+ /* need to wrap the string nicely */
+ for(size_t i = 29+65; i < str_len(b64_data); i+=64) /* start at header + first 64 */
+ {
+ str_insert(b64_data, i++, "\n");
+ }
+ str_append_c(b64_data,'\n');
+ str_append(b64_data, "-----END DH PARAMETERS-----");
+ ssl_dh_parameters = i_strdup(str_c(b64_data));
+ *value = ssl_dh_parameters;
+
+ if (!seen_ssl_parameters_dat) {
+ i_warning("please set ssl_dh=<%s", SYSCONFDIR"/dh.pem");
+ i_warning("You can generate it with: dd if=%s bs=1 skip=%u | openssl dhparam -inform der > %s", fn, off, SYSCONFDIR"/dh.pem");
+ seen_ssl_parameters_dat = TRUE;
+ }
+ } else if (is->stream_errno == ENOENT) {
+ /* check for empty ssl_dh elsewhere */
+ *value = NULL;
+ i_stream_unref(&is);
+ return TRUE;
+ } else {
+ *error_r = "ssl enabled, but ssl_dh not set";
+ i_stream_unref(&is);
+ return FALSE;
+ }
+ i_stream_unref(&is);
+
+ return TRUE;
+}
+
+bool old_settings_ssl_dh_load(const char **value, const char **error_r)
+{
+ if (ssl_dh_loaded) {
+ *value = ssl_dh_value;
+ return TRUE;
+ }
+ if (!old_settings_ssl_dh_read(value, error_r))
+ return FALSE;
+ ssl_dh_value = i_strdup(*value);
+ ssl_dh_loaded = TRUE;
+ return TRUE;
+}
+
+/* FIXME: Remove ssl_protocols_to_min_protocol() in v2.4 */
+static int ssl_protocols_to_min_protocol(const char *ssl_protocols,
+ const char **min_protocol_r,
+ const char **error_r)
+{
+ static const char *protocol_versions[] = {
+ "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2",
+ };
+ /* Array where -1 = disable, 0 = not found, 1 = enable */
+ int protos[N_ELEMENTS(protocol_versions)];
+ memset(protos, 0, sizeof(protos));
+ bool explicit_enable = FALSE;
+
+ const char *const *tmp = t_strsplit_spaces(ssl_protocols, ", ");
+ for (; *tmp != NULL; tmp++) {
+ const char *p = *tmp;
+ bool enable = TRUE;
+ if (p[0] == '!') {
+ enable = FALSE;
+ ++p;
+ }
+ for (unsigned i = 0; i < N_ELEMENTS(protocol_versions); i++) {
+ if (strcmp(p, protocol_versions[i]) == 0) {
+ if (enable) {
+ protos[i] = 1;
+ explicit_enable = TRUE;
+ } else {
+ protos[i] = -1;
+ }
+ goto found;
+ }
+ }
+ *error_r = t_strdup_printf("Unrecognized protocol '%s'", p);
+ return -1;
+
+ found:;
+ }
+
+ unsigned min = N_ELEMENTS(protocol_versions);
+ for (unsigned i = 0; i < N_ELEMENTS(protocol_versions); i++) {
+ if (explicit_enable) {
+ if (protos[i] > 0)
+ min = I_MIN(min, i);
+ } else if (protos[i] == 0)
+ min = I_MIN(min, i);
+ }
+ if (min == N_ELEMENTS(protocol_versions)) {
+ *error_r = "All protocols disabled";
+ return -1;
+ }
+
+ *min_protocol_r = protocol_versions[min];
+ return 0;
+}
+
+static bool
+old_settings_handle_root(struct config_parser_context *ctx,
+ const char *key, const char *value)
+{
+ const char *p;
+ size_t len;
+
+ if (strcmp(key, "base_dir") == 0) {
+ len = strlen(value);
+ if (len > 0 && value[len-1] == '/')
+ value = t_strndup(value, len-1);
+ ctx->old->base_dir = p_strdup(ctx->pool, value);
+ }
+ if (strcmp(key, "protocols") == 0) {
+ char **protos, **s;
+ bool have_imap = FALSE, have_imaps = FALSE;
+ bool have_pop3 = FALSE, have_pop3s = FALSE;
+
+ protos = p_strsplit_spaces(pool_datastack_create(), value, " ");
+ for (s = protos; *s != NULL; s++) {
+ if (strcmp(*s, "imap") == 0)
+ have_imap = TRUE;
+ else if (strcmp(*s, "imaps") == 0) {
+ *s = "";
+ have_imaps = TRUE;
+ } else if (strcmp(*s, "pop3") == 0)
+ have_pop3 = TRUE;
+ else if (strcmp(*s, "pop3s") == 0) {
+ *s = "";
+ have_pop3s = TRUE;
+ } else if (strcmp(*s, "managesieve") == 0) {
+ *s = "sieve";
+ obsolete(ctx, "protocols=managesieve has been renamed to protocols=sieve");
+ }
+ }
+ value = t_strarray_join((const char *const *)protos, " ");
+ /* ugly way to drop extra spaces.. */
+ protos = p_strsplit_spaces(pool_datastack_create(), value, " ");
+ value = t_strarray_join((const char *const *)protos, " ");
+
+ if (have_imaps && !have_imap) {
+ obsolete(ctx, "'imaps' protocol can no longer be specified (use protocols=imap). to disable non-ssl imap, use service imap-login { inet_listener imap { port=0 } }");
+ value = t_strconcat(value, " imap", NULL);
+ config_apply_line(ctx, "port",
+ "service/imap-login/inet_listener/imap/port=0", NULL);
+ } else if (have_imaps)
+ obsolete(ctx, "'imaps' protocol is no longer necessary, remove it");
+ if (have_pop3s && !have_pop3) {
+ obsolete(ctx, "'pop3s' protocol can no longer be specified (use protocols=pop3). to disable non-ssl pop3, use service pop3-login { inet_listener pop3 { port=0 } }");
+ value = t_strconcat(value, " pop3", NULL);
+ config_apply_line(ctx, "port",
+ "service/pop3-login/inet_listener/pop3/port=0", NULL);
+ } else if (have_pop3s)
+ obsolete(ctx, "'pop3s' protocol is no longer necessary, remove it");
+
+ if (*value == ' ') value++;
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ key, value);
+ return TRUE;
+ }
+ if (strcmp(key, "ssl_cert_file") == 0 ||
+ strcmp(key, "ssl_key_file") == 0 ||
+ strcmp(key, "ssl_ca_file") == 0) {
+ if (*value == '\0')
+ return TRUE;
+ p = t_strdup_until(key, strrchr(key, '_'));
+ obsolete(ctx, "%s has been replaced by %s = <file", key, p);
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYFILE,
+ p, value);
+ return TRUE;
+ }
+ if (strcmp(key, "ssl_disable") == 0) {
+ if (strcasecmp(value, "yes") == 0)
+ value = "no";
+ else if (strcasecmp(value, "no") == 0)
+ value = "yes";
+ set_rename(ctx, key, "ssl", value);
+ return TRUE;
+ }
+ if (strcmp(key, "ssl_parameters_regenerate") == 0 ||
+ strcmp(key, "ssl_dh_parameters_length") == 0) {
+ obsolete(ctx, "%s is no longer needed", key);
+ return TRUE;
+ }
+ if (strcmp(key, "ssl_protocols") == 0) {
+ obsolete(ctx, "%s has been replaced by ssl_min_protocol", key);
+ const char *min_protocol, *error;
+ if (ssl_protocols_to_min_protocol(value, &min_protocol, &error) < 0) {
+ i_error("Could not find a minimum ssl_min_protocol "
+ "setting from ssl_protocols = %s: %s",
+ value, error);
+ return TRUE;
+ }
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ "ssl_min_protocol", min_protocol);
+ return TRUE;
+ }
+ if (strcmp(key, "sieve") == 0 ||
+ strcmp(key, "sieve_storage") == 0) {
+ if (strcmp(key, "sieve_storage") == 0)
+ obsolete(ctx, "sieve_storage has been moved into plugin { sieve_dir }");
+ else
+ obsolete(ctx, "%s has been moved into plugin {} section", key);
+
+ config_apply_line(ctx, "", "plugin=", NULL);
+ config_apply_line(ctx, key,
+ t_strdup_printf("plugin/%s=%s", key, value), NULL);
+ return TRUE;
+ }
+ if (strcmp(key, "fsync_disable") == 0) {
+ if (strcasecmp(value, "yes") == 0)
+ value = "never";
+ else if (strcasecmp(value, "no") == 0)
+ value = "optimized";
+ set_rename(ctx, key, "mail_fsync", value);
+ return TRUE;
+ }
+ if (strcmp(key, "dbox_rotate_size") == 0) {
+ set_rename(ctx, key, "mdbox_rotate_size", value);
+ return TRUE;
+ }
+ if (str_begins(key, "mail_cache_compress_")) {
+ const char *new_key = t_strconcat("mail_cache_purge_", key+20, NULL);
+ set_rename(ctx, key, new_key, value);
+ return TRUE;
+ }
+ if (strcmp(key, "imap_client_workarounds") == 0) {
+ char **args, **arg;
+
+ args = p_strsplit_spaces(pool_datastack_create(), value, " ,");
+ for (arg = args; *arg != NULL; arg++) {
+ if (strcmp(*arg, "outlook-idle") == 0) {
+ *arg = "";
+ obsolete(ctx, "imap_client_workarounds=outlook-idle is no longer necessary");
+ } else if (strcmp(*arg, "netscape-eoh") == 0) {
+ *arg = "";
+ obsolete(ctx, "imap_client_workarounds=netscape-eoh is no longer supported");
+ }
+ }
+ value = t_strarray_join((void *)args, " ");
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ key, value);
+ return TRUE;
+ }
+
+ if (strcmp(key, "login_dir") == 0 ||
+ strcmp(key, "dbox_rotate_min_size") == 0 ||
+ strcmp(key, "dbox_rotate_days") == 0 ||
+ strcmp(key, "director_consistent_hashing") == 0 ||
+ strcmp(key, "mail_log_max_lines_per_sec") == 0 ||
+ strcmp(key, "maildir_copy_preserve_filename") == 0) {
+ obsolete(ctx, "%s has been removed", key);
+ return TRUE;
+ }
+ if (ctx->old->auth_section == 1) {
+ if (!str_begins(key, "auth_"))
+ key = t_strconcat("auth_", key, NULL);
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ key, value);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+config_apply_login_set(struct config_parser_context *ctx,
+ struct config_section_stack *old_section,
+ const char *old_key, const char *key, const char *value)
+{
+ obsolete(ctx, "%s has been replaced by service { %s }", old_key, key);
+
+ if (config_filter_match(&old_section->filter, &imap_filter)) {
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/imap-login/%s=%s", key, value), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &pop3_filter)) {
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/pop3-login/%s=%s", key, value), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &managesieve_filter)) {
+ /* if pigeonhole isn't installed, this fails.
+ just ignore it then.. */
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/managesieve-login/%s=%s", key, value), NULL);
+ ctx->error = NULL;
+ }
+}
+
+static void
+config_apply_mail_set(struct config_parser_context *ctx,
+ struct config_section_stack *old_section,
+ const char *old_key, const char *key, const char *value)
+{
+ obsolete(ctx, "%s has been replaced by service { %s }", old_key, key);
+
+ if (config_filter_match(&old_section->filter, &imap_filter)) {
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/imap/%s=%s", key,value), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &pop3_filter)) {
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/pop3/%s=%s", key,value), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &managesieve_filter)) {
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/managesieve/%s=%s", key,value), NULL);
+ ctx->error = NULL;
+ }
+}
+
+static void
+config_apply_auth_set(struct config_parser_context *ctx,
+ const char *old_key, const char *key, const char *value)
+{
+ obsolete(ctx, "%s has been replaced by service auth { %s }", old_key, key);
+ config_apply_line(ctx, key,
+ t_strdup_printf("service/auth/%s=%s", key,value), NULL);
+}
+
+static bool listen_has_port(const char *str)
+{
+ const char *const *addrs;
+
+ if (strchr(str, ':') == NULL)
+ return FALSE;
+
+ addrs = t_strsplit_spaces(str, ", ");
+ for (; *addrs != NULL; addrs++) {
+ if (strcmp(*addrs, "*") != 0 &&
+ strcmp(*addrs, "::") != 0 &&
+ strcmp(*addrs, "[::]") != 0 &&
+ !is_ipv4_address(*addrs) &&
+ !is_ipv6_address(*addrs))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static bool
+old_settings_handle_proto(struct config_parser_context *ctx,
+ const char *key, const char *value)
+{
+ struct config_section_stack *old_section = ctx->cur_section;
+ const char *p;
+ uoff_t size;
+ bool root;
+
+ while (ctx->cur_section->prev != NULL)
+ ctx->cur_section = ctx->cur_section->prev;
+
+ root = config_filter_match(&old_section->filter, &any_filter);
+
+ if (strcmp(key, "ssl_listen") == 0 ||
+ (strcmp(key, "listen") == 0 &&
+ (listen_has_port(value) || !root))) {
+ const char *ssl = strcmp(key, "ssl_listen") == 0 ? "s" : "";
+
+ if (*value == '\0') {
+ /* default */
+ return TRUE;
+ }
+ p = strrchr(value, ':');
+ if (p != NULL && listen_has_port(value)) {
+ obsolete(ctx, "%s=..:port has been replaced by service { inet_listener { port } }", key);
+ value = t_strdup_until(value, p++);
+ if (config_filter_match(&old_section->filter, &imap_filter)) {
+ config_apply_line(ctx, "port",
+ t_strdup_printf("service/imap-login/inet_listener/imap%s/port=%s", ssl, p), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &pop3_filter)) {
+ config_apply_line(ctx, "port",
+ t_strdup_printf("service/pop3-login/inet_listener/pop3%s/port=%s", ssl, p), NULL);
+ }
+ if (*ssl == '\0' &&
+ config_filter_match(&old_section->filter, &managesieve_filter)) {
+ config_apply_line(ctx, "port",
+ t_strdup_printf("service/managesieve-login/inet_listener/managesieve/port=%s", p), NULL);
+ ctx->error = NULL;
+ }
+ }
+ if (root && *ssl == '\0') {
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ key, value);
+ } else {
+ obsolete(ctx, "protocol { %s } has been replaced by service { inet_listener { address } }", key);
+ if (config_filter_match(&old_section->filter, &imap_filter)) {
+ config_apply_line(ctx, "address",
+ t_strdup_printf("service/imap-login/inet_listener/imap%s/address=%s", ssl, value), NULL);
+ }
+ if (config_filter_match(&old_section->filter, &pop3_filter)) {
+ config_apply_line(ctx, "address",
+ t_strdup_printf("service/pop3-login/inet_listener/pop3%s/address=%s", ssl, value), NULL);
+ }
+ if (*ssl == '\0' &&
+ config_filter_match(&old_section->filter, &managesieve_filter)) {
+ config_apply_line(ctx, "address",
+ t_strdup_printf("service/managesieve-login/inet_listener/managesieve/address=%s", value), NULL);
+ ctx->error = NULL;
+ }
+ }
+ return TRUE;
+ }
+ if (strcmp(key, "login_chroot") == 0) {
+ if (strcmp(value, "no") == 0)
+ value = "";
+ else
+ value = "login";
+
+ config_apply_login_set(ctx, old_section, key, "chroot", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_user") == 0) {
+ config_apply_login_set(ctx, old_section, key, "user", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_executable") == 0) {
+ config_apply_login_set(ctx, old_section, key, "executable", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_process_size") == 0) {
+ config_apply_login_set(ctx, old_section, key, "vsz_limit",
+ t_strconcat(value, " M", NULL));
+ return TRUE;
+ }
+ if (strcmp(key, "login_process_per_connection") == 0) {
+ config_apply_login_set(ctx, old_section, key, "service_count",
+ strcmp(value, "no") == 0 ? "0" : "1");
+ return TRUE;
+ }
+ if (strcmp(key, "login_processes_count") == 0) {
+ config_apply_login_set(ctx, old_section, key, "process_min_avail", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_max_processes_count") == 0) {
+ config_apply_login_set(ctx, old_section, key, "process_limit", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_max_connections") == 0) {
+ config_apply_login_set(ctx, old_section, key, "client_limit", value);
+ return TRUE;
+ }
+ if (strcmp(key, "login_process_size") == 0) {
+ config_apply_login_set(ctx, old_section, key, "vsz_limit",
+ t_strconcat(value, " M", NULL));
+ return TRUE;
+ }
+
+ if (strcmp(key, "max_mail_processes") == 0) {
+ config_apply_mail_set(ctx, old_section, key, "process_limit", value);
+ return TRUE;
+ }
+ if (strcmp(key, "mail_executable") == 0) {
+ config_apply_mail_set(ctx, old_section, key, "executable", value);
+ return TRUE;
+ }
+ if (strcmp(key, "mail_process_size") == 0) {
+ config_apply_mail_set(ctx, old_section, key, "vsz_limit",
+ t_strconcat(value, " M", NULL));
+ return TRUE;
+ }
+ if (strcmp(key, "mail_drop_priv_before_exec") == 0) {
+ config_apply_mail_set(ctx, old_section, key, "drop_priv_before_exec", value);
+ return TRUE;
+ }
+
+ if (ctx->old->auth_section == 1) {
+ if (!str_begins(key, "auth_"))
+ key = t_strconcat("auth_", key, NULL);
+ }
+
+ if (strcmp(key, "auth_executable") == 0) {
+ config_apply_auth_set(ctx, key, "executable", value);
+ return TRUE;
+ }
+ if (strcmp(key, "auth_process_size") == 0) {
+ config_apply_auth_set(ctx, key, "vsz_limit",
+ t_strconcat(value, " M", NULL));
+ return TRUE;
+ }
+ if (strcmp(key, "auth_user") == 0) {
+ config_apply_auth_set(ctx, key, "user", value);
+ return TRUE;
+ }
+ if (strcmp(key, "auth_chroot") == 0) {
+ config_apply_auth_set(ctx, key, "chroot", value);
+ return TRUE;
+ }
+ if (strcmp(key, "auth_cache_size") == 0 &&
+ str_to_uoff(value, &size) == 0 && size > 0 && size < 1024) {
+ obsolete(ctx, "auth_cache_size value no longer defaults to "
+ "megabytes. Use %sM", value);
+ config_apply_line(ctx, key,
+ t_strdup_printf("%s=%sM", key, value), NULL);
+ return TRUE;
+ }
+ if (strcmp(key, "auth_count") == 0) {
+ if (strcmp(value, "count") == 0)
+ obsolete(ctx, "auth_count has been removed");
+ else
+ obsolete(ctx, "auth_count has been removed, and its value must be 1");
+ return TRUE;
+ }
+ if (ctx->old->socket_listen_section == 2) {
+ const char **p = NULL;
+
+ if (strcmp(key, "path") == 0)
+ p = &ctx->old->socket_set.path;
+ else if (strcmp(key, "mode") == 0)
+ p = &ctx->old->socket_set.mode;
+ else if (strcmp(key, "user") == 0)
+ p = &ctx->old->socket_set.user;
+ else if (strcmp(key, "group") == 0)
+ p = &ctx->old->socket_set.group;
+
+ if (p != NULL) {
+ *p = p_strdup(ctx->pool, value);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static bool old_auth_section(struct config_parser_context *ctx,
+ const char *key, const char *value)
+{
+ if (ctx->old->auth_section == 0 && ctx->old->seen_auth_section) {
+ obsolete(ctx, "Multiple auth sections are no longer supported");
+ return FALSE;
+ }
+ ctx->old->seen_auth_section = TRUE;
+ i_zero(&ctx->old->socket_set);
+
+ ctx->old->auth_section++;
+ if ((strcmp(key, "passdb") == 0 || strcmp(key, "userdb") == 0) &&
+ ctx->old->auth_section == 2) {
+ obsolete(ctx, "%s %s {} has been replaced by %s { driver=%s }",
+ key, value, key, value);
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_SECTION_BEGIN, key, "");
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_KEYVALUE,
+ "driver", value);
+ return TRUE;
+ }
+ if (strcmp(key, "socket") == 0 && ctx->old->auth_section == 2) {
+ if (strcmp(value, "connect") == 0) {
+ obsolete(ctx, "socket connect {} is no longer supported, configure external auth server separately");
+ return FALSE;
+ }
+ if (strcmp(value, "listen") != 0)
+ return FALSE;
+
+ /* socket listen { .. } */
+ ctx->old->socket_listen_section++;
+ return TRUE;
+ }
+
+ if (ctx->old->socket_listen_section > 0)
+ ctx->old->socket_listen_section++;
+ if ((strcmp(key, "master") == 0 || strcmp(key, "client") == 0) &&
+ ctx->old->socket_listen_section == 2) {
+ ctx->old->socket_set.master = strcmp(key, "master") == 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void socket_apply(struct config_parser_context *ctx)
+{
+ const struct socket_set *set = &ctx->old->socket_set;
+ const char *path, *prefix;
+ size_t len;
+ bool master_suffix;
+
+ if (set->path == NULL) {
+ ctx->error = "socket listen {} is missing path";
+ return;
+ }
+ path = set->path;
+ len = strlen(ctx->old->base_dir);
+ if (str_begins(path, ctx->old->base_dir) &&
+ path[len] == '/')
+ path += len + 1;
+
+ len = strlen(path);
+ master_suffix = len >= 7 &&
+ (strcmp(path + len - 7, "-master") == 0 ||
+ strcmp(path + len - 7, "-userdb") == 0);
+
+ if (set->master && !master_suffix) {
+ ctx->error = "socket listen { master { path=.. } } must end with -master (or -userdb) suffix";
+ return;
+ } else if (!set->master && master_suffix) {
+ ctx->error = "socket listen { client { path=.. } } must end not with -master or -userdb suffix";
+ return;
+ }
+
+ config_apply_line(ctx, "unix_listener",
+ t_strdup_printf("service/auth/unix_listener=%s", settings_section_escape(path)), path);
+ prefix = t_strdup_printf("service/auth/unix_listener/%s", settings_section_escape(path));
+ if (set->mode != NULL) {
+ config_apply_line(ctx, "mode",
+ t_strdup_printf("%s/mode=%s", prefix, set->mode), NULL);
+ }
+ if (set->user != NULL) {
+ config_apply_line(ctx, "user",
+ t_strdup_printf("%s/user=%s", prefix, set->user), NULL);
+ }
+ if (set->group != NULL) {
+ config_apply_line(ctx, "group",
+ t_strdup_printf("%s/group=%s", prefix, set->group), NULL);
+ }
+ i_zero(&ctx->old->socket_set);
+}
+
+static bool
+old_settings_handle_path(struct config_parser_context *ctx,
+ const char *key, const char *value)
+{
+ if (strcmp(str_c(ctx->str), "plugin/0/") == 0) {
+ if (strcmp(key, "imap_zlib_compress_level") == 0) {
+ obsolete(ctx, "%s has been replaced by imap_compress_deflate_level", key);
+ config_apply_line(ctx, key,
+ t_strdup_printf("plugin/0/imap_compress_deflate_level=%s", value), NULL);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool old_settings_handle(struct config_parser_context *ctx,
+ enum config_line_type type,
+ const char *key, const char *value)
+{
+ switch (type) {
+ case CONFIG_LINE_TYPE_SKIP:
+ case CONFIG_LINE_TYPE_CONTINUE:
+ case CONFIG_LINE_TYPE_ERROR:
+ case CONFIG_LINE_TYPE_INCLUDE:
+ case CONFIG_LINE_TYPE_INCLUDE_TRY:
+ case CONFIG_LINE_TYPE_KEYFILE:
+ case CONFIG_LINE_TYPE_KEYVARIABLE:
+ break;
+ case CONFIG_LINE_TYPE_KEYVALUE:
+ if (ctx->pathlen == 0) {
+ struct config_section_stack *old_section =
+ ctx->cur_section;
+ bool ret;
+
+ ret = old_settings_handle_proto(ctx, key, value);
+ ctx->cur_section = old_section;
+ if (ret)
+ return TRUE;
+
+ return old_settings_handle_root(ctx, key, value);
+ }
+ return old_settings_handle_path(ctx, key, value);
+ case CONFIG_LINE_TYPE_SECTION_BEGIN:
+ if (ctx->old->auth_section > 0)
+ return old_auth_section(ctx, key, value);
+ else if (ctx->pathlen == 0 && strcmp(key, "auth") == 0) {
+ obsolete(ctx, "add auth_ prefix to all settings inside auth {} and remove the auth {} section completely");
+ ctx->old->auth_section = 1;
+ return TRUE;
+ } else if (ctx->pathlen == 0 && strcmp(key, "protocol") == 0 &&
+ strcmp(value, "managesieve") == 0) {
+ obsolete(ctx, "protocol managesieve {} has been replaced by protocol sieve { }");
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_SECTION_BEGIN,
+ "protocol", "sieve");
+ return TRUE;
+ } else if (ctx->pathlen == 0 && strcmp(key, "service") == 0 &&
+ strcmp(value, "dns_client") == 0) {
+ obsolete(ctx, "service dns_client {} has been replaced by service dns-client { }");
+ config_parser_apply_line(ctx, CONFIG_LINE_TYPE_SECTION_BEGIN,
+ "service", "dns-client");
+ return TRUE;
+ }
+ break;
+ case CONFIG_LINE_TYPE_SECTION_END:
+ if (ctx->old->auth_section > 0) {
+ if (--ctx->old->auth_section == 0)
+ return TRUE;
+ }
+ if (ctx->old->socket_listen_section > 0) {
+ if (ctx->old->socket_listen_section == 2)
+ socket_apply(ctx);
+ ctx->old->socket_listen_section--;
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+void old_settings_init(struct config_parser_context *ctx)
+{
+ ctx->old = p_new(ctx->pool, struct old_set_parser, 1);
+ ctx->old->base_dir = PKG_RUNDIR;
+}
+
+void old_settings_deinit_global(void)
+{
+ i_free(ssl_dh_value);
+}