doc/wiki/Makefile.am
src/auth/checkpassword-reply
src/auth/dovecot-auth
+src/config/all-settings.c
+src/config/all-settings.h
+src/config/doveconf
src/deliver/deliver
src/dict/dict
src/imap-login/imap-login
+ - config rewrite
+ - deliver: plugin var expanding
+ - master: expands only known vars, not all_settings.. should it expand
+ anything after all? use the 1/0 prefix to mark which vars have been
+ expanded (config vs userdb)?
+ - go through mail-process.c. nfs test?
+ - support !include and !include_try
+ - check plugins to make sure they're using only internal getenv()s,
+ especially fix DEBUG env checks
+ - add back all setting verification code from master
+ - put plugin settings to some plugins array, not envs, var expand
- proxying: support fallbacking to local (or other?) server if the first
one is down
user_attrs {
fi
AM_CONDITIONAL(BUILD_SOLR, test "$have_solr" = "yes")
+dnl **
+dnl ** Settings
+dnl **
+
+dnl get a list of setting .[ch] files, but list .h files first
+SETTING_FILES=`find $srcdir/src -name '*settings.[[ch]]' ! -name all-settings.[[ch]] | sed -e s,$srcdir/src,./src,g -e 's,./src,$(top_srcdir)/src,g' -e 's/^\(.*\)\(.\)$/\2 \1\2/' | sort -r | sed s/^..//|tr '\n' ' '`
+AC_SUBST(SETTING_FILES)
+
dnl **
dnl ** capabilities
dnl **
src/lib-storage/index/shared/Makefile
src/lib-storage/register/Makefile
src/auth/Makefile
+src/config/Makefile
src/deliver/Makefile
src/dict/Makefile
src/imap/Makefile
lib-storage \
lib-auth \
auth \
+ config \
dict \
master \
login-common \
-I$(top_srcdir)/src/lib-otp \
-DAUTH_MODULE_DIR=\""$(auth_moduledir)"\" \
-DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+ -DPKG_RUNDIR=\""$(rundir)"\" \
$(AUTH_CFLAGS)
dovecot_auth_LDFLAGS = -export-dynamic
auth-master-listener.c \
auth-request.c \
auth-request-handler.c \
+ auth-settings.c \
auth-stream.c \
auth-worker-client.c \
auth-worker-server.c \
auth-master-listener.h \
auth-request.h \
auth-request-handler.h \
+ auth-settings.h \
auth-stream.h \
auth-worker-client.h \
auth-worker-server.h \
io_remove(&conn->io);
}
- if (conn->auth->verbose_debug) {
- i_info("client out: %s", conn->auth->verbose_debug_passwords ?
+ if (conn->auth->set->debug) {
+ i_info("client out: %s", conn->auth->set->debug_passwords ?
cmd : reply_line_hide_pass(cmd));
}
}
auth_request_handler_set(conn->request_handler, conn->connect_uid, pid);
conn->pid = pid;
- if (conn->auth->verbose_debug)
+ if (conn->auth->set->debug)
i_info("new auth connection: pid=%u", conn->pid);
return TRUE;
}
auth_client_handle_line(struct auth_client_connection *conn, const char *line)
{
if (strncmp(line, "AUTH\t", 5) == 0) {
- if (conn->auth->verbose_debug) {
+ if (conn->auth->set->debug) {
i_info("client in: %s",
- conn->auth->verbose_debug_passwords ? line :
+ conn->auth->set->debug_passwords ? line :
auth_line_hide_pass(line));
}
return auth_request_handler_auth_begin(conn->request_handler,
line + 5);
}
if (strncmp(line, "CONT\t", 5) == 0) {
- if (conn->auth->verbose_debug) {
+ if (conn->auth->set->debug) {
i_info("client in: %s",
- conn->auth->verbose_debug_passwords ? line :
+ conn->auth->set->debug_passwords ? line :
cont_line_hide_pass(line));
}
return auth_request_handler_auth_continue(conn->request_handler,
reply_str = auth_stream_reply_export(reply);
- if (conn->listener->auth->verbose_debug)
+ if (conn->listener->auth->set->debug)
i_info("master out: %s", reply_str);
iov[0].iov_base = reply_str;
break;
}
- if (conn->listener->auth->verbose_debug)
+ if (conn->listener->auth->set->debug)
i_info("master out: %s", str_c(str));
str_append_c(str, '\n');
static bool
auth_master_input_line(struct auth_master_connection *conn, const char *line)
{
- if (conn->listener->auth->verbose_debug)
+ if (conn->listener->auth->set->debug)
i_info("master in: %s", line);
if (strncmp(line, "REQUEST\t", 8) == 0)
#include <stdlib.h>
-#define DEFAULT_AUTH_FAILURE_DELAY 2
#define AUTH_FAILURE_DELAY_CHECK_MSECS 500
struct auth_request_handler {
static ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
static struct aqueue *auth_failures;
static struct timeout *to_auth_failures;
-static unsigned int auth_failure_delay;
static void auth_failure_timeout(void *context);
hash_table_insert(handler->requests, POINTER_CAST(id), request);
- if (request->auth->ssl_require_client_cert &&
+ if (request->auth->set->ssl_require_client_cert &&
!request->valid_client_cert) {
/* we fail without valid certificate */
auth_request_handler_auth_fail(handler, request,
for (i = 0; i < count; i++) {
auth_request = auth_requests[aqueue_idx(auth_failures, 0)];
+ /* FIXME: assumess that failure_delay is always the same. */
diff = ioloop_time - auth_request->last_access;
- if (diff < (time_t)auth_failure_delay && !flush_all)
+ if (diff < (time_t)auth_request->auth->set->failure_delay &&
+ !flush_all)
break;
aqueue_delete_tail(auth_failures);
void auth_request_handler_init(void)
{
- const char *env;
-
- env = getenv("FAILURE_DELAY");
- auth_failure_delay = env != NULL ? atoi(env) :
- DEFAULT_AUTH_FAILURE_DELAY;
-
i_array_init(&auth_failures_arr, 128);
auth_failures = aqueue_init(&auth_failures_arr.arr);
}
else if (strcmp(key, "original_username") == 0)
request->original_username = p_strdup(request->pool, value);
else if (strcmp(key, "cert_username") == 0) {
- if (request->auth->ssl_username_from_cert) {
+ if (request->auth->set->ssl_username_from_cert) {
/* get username from SSL certificate. it overrides
the username given by the auth mechanism. */
request->user = p_strdup(request->pool, value);
request->credentials_scheme,
request->private_callback.lookup_credentials);
} else {
- if (request->auth->verbose_debug_passwords &&
+ if (request->auth->set->debug_passwords &&
result == PASSDB_RESULT_OK) {
auth_request_log_debug(request, "password",
"Credentials: %s",
unsigned char *p;
char *user;
- if (strchr(username, '@') == NULL &&
- request->auth->default_realm != NULL) {
+ if (*request->auth->set->default_realm != '\0' &&
+ strchr(username, '@') == NULL) {
user = p_strconcat(request->pool, username, "@",
- request->auth->default_realm, NULL);
+ request->auth->set->default_realm, NULL);
} else {
user = p_strdup(request->pool, username);
}
}
}
- if (request->auth->username_format != NULL) {
+ if (*request->auth->set->username_format != '\0') {
/* username format given, put it through variable expansion.
we'll have to temporarily replace request->user to get
%u to be the wanted username */
dest = t_str_new(256);
table = auth_request_get_var_expand_table(request, NULL);
- var_expand(dest, request->auth->username_format, table);
+ var_expand(dest, request->auth->set->username_format, table);
user = p_strdup(request->pool, str_c(dest));
request->user = old_username;
bool auth_request_set_username(struct auth_request *request,
const char *username, const char **error_r)
{
+ const struct auth_settings *set = request->auth->set;
const char *p, *login_username = NULL;
- if (request->auth->master_user_separator != '\0' &&
- !request->userdb_lookup) {
+ if (*set->master_user_separator != '\0' && !request->userdb_lookup) {
/* check if the username contains a master user */
- p = strchr(username, request->auth->master_user_separator);
+ p = strchr(username, *set->master_user_separator);
if (p != NULL) {
/* it does, set it. */
login_username = t_strdup_until(username, p);
if (ret == 0) {
auth_request_log_info(request, subsystem,
"Password mismatch");
- if (request->auth->verbose_debug_passwords) {
+ if (request->auth->set->debug_passwords) {
auth_request_log_debug(request, subsystem,
"%s(%s) != '%s'", scheme,
plain_password,
{
va_list va;
- if (!auth_request->auth->verbose_debug)
+ if (!auth_request->auth->set->debug)
return;
va_start(va, format);
{
va_list va;
- if (!auth_request->auth->verbose)
+ if (!auth_request->auth->set->verbose)
return;
va_start(va, format);
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hostpid.h"
+#include "settings-parser.h"
+#include "auth-settings.h"
+
+#include <stddef.h>
+
+extern struct setting_parser_info auth_socket_setting_parser_info;
+extern struct setting_parser_info auth_setting_parser_info;
+extern struct setting_parser_info auth_root_setting_parser_info;
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_socket_unix_settings, name), NULL }
+
+static struct setting_define auth_socket_client_setting_defines[] = {
+ DEF(SET_STR, path),
+ DEF(SET_UINT, mode),
+ DEF(SET_STR, user),
+ DEF(SET_STR, group),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_unix_settings auth_socket_client_default_settings = {
+ MEMBER(path) "auth-client",
+ MEMBER(mode) 0660,
+ MEMBER(user) "",
+ MEMBER(group) ""
+};
+
+struct setting_parser_info auth_socket_client_setting_parser_info = {
+ MEMBER(defines) auth_socket_client_setting_defines,
+ MEMBER(defaults) &auth_socket_client_default_settings,
+
+ MEMBER(parent) &auth_socket_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct auth_socket_unix_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_socket_unix_settings, name), NULL }
+
+static struct setting_define auth_socket_master_setting_defines[] = {
+ DEF(SET_STR, path),
+ DEF(SET_UINT, mode),
+ DEF(SET_STR, user),
+ DEF(SET_STR, group),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_unix_settings auth_socket_master_default_settings = {
+ MEMBER(path) "auth-master",
+ MEMBER(mode) 0660,
+ MEMBER(user) "",
+ MEMBER(group) ""
+};
+
+struct setting_parser_info auth_socket_master_setting_parser_info = {
+ MEMBER(defines) auth_socket_master_setting_defines,
+ MEMBER(defaults) &auth_socket_master_default_settings,
+
+ MEMBER(parent) &auth_socket_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct auth_socket_unix_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_socket_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct auth_socket_settings, field), defines }
+
+static struct setting_define auth_socket_setting_defines[] = {
+ DEF(SET_STR, type),
+
+ DEFLIST(clients, "client", &auth_socket_client_setting_parser_info),
+ DEFLIST(masters, "master", &auth_socket_master_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct auth_socket_settings auth_socket_default_settings = {
+ MEMBER(type) "listen"
+};
+
+struct setting_parser_info auth_socket_setting_parser_info = {
+ MEMBER(defines) auth_socket_setting_defines,
+ MEMBER(defaults) &auth_socket_default_settings,
+
+ MEMBER(parent) &auth_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct auth_socket_settings, type),
+ MEMBER(struct_size) sizeof(struct auth_socket_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_passdb_settings, name), NULL }
+
+static struct setting_define auth_passdb_setting_defines[] = {
+ DEF(SET_STR, driver),
+ DEF(SET_STR, args),
+ DEF(SET_BOOL, deny),
+
+ SETTING_DEFINE_LIST_END
+};
+
+struct setting_parser_info auth_passdb_setting_parser_info = {
+ MEMBER(defines) auth_passdb_setting_defines,
+ MEMBER(defaults) NULL,
+
+ MEMBER(parent) &auth_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct auth_passdb_settings, driver),
+ MEMBER(struct_size) sizeof(struct auth_passdb_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_userdb_settings, name), NULL }
+
+static struct setting_define auth_userdb_setting_defines[] = {
+ DEF(SET_STR, driver),
+ DEF(SET_STR, args),
+
+ SETTING_DEFINE_LIST_END
+};
+
+struct setting_parser_info auth_userdb_setting_parser_info = {
+ MEMBER(defines) auth_userdb_setting_defines,
+ MEMBER(defaults) NULL,
+
+ MEMBER(parent) &auth_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct auth_userdb_settings, driver),
+ MEMBER(struct_size) sizeof(struct auth_userdb_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct auth_settings, field), defines }
+
+static struct setting_define auth_setting_defines[] = {
+ DEF(SET_STR, name),
+ DEF(SET_STR, mechanisms),
+ DEF(SET_STR, realms),
+ DEF(SET_STR, default_realm),
+ DEF(SET_UINT, cache_size),
+ DEF(SET_UINT, cache_ttl),
+ DEF(SET_UINT, cache_negative_ttl),
+ DEF(SET_STR, username_chars),
+ DEF(SET_STR, username_translation),
+ DEF(SET_STR, username_format),
+ DEF(SET_STR, master_user_separator),
+ DEF(SET_STR, anonymous_username),
+ DEF(SET_STR, krb5_keytab),
+ DEF(SET_STR, gssapi_hostname),
+ DEF(SET_STR, winbind_helper_path),
+ DEF(SET_UINT, failure_delay),
+
+ DEF(SET_BOOL, verbose),
+ DEF(SET_BOOL, debug),
+ DEF(SET_BOOL, debug_passwords),
+ DEF(SET_BOOL, ssl_require_client_cert),
+ DEF(SET_BOOL, ssl_username_from_cert),
+ DEF(SET_BOOL, use_winbind),
+
+ DEF(SET_UINT, worker_max_count),
+
+ DEFLIST(sockets, "socket", &auth_socket_setting_parser_info),
+ DEFLIST(passdbs, "passdb", &auth_passdb_setting_parser_info),
+ DEFLIST(userdbs, "userdb", &auth_userdb_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct auth_settings auth_default_settings = {
+ MEMBER(name) NULL,
+ MEMBER(root) NULL,
+
+ MEMBER(mechanisms) "plain",
+ MEMBER(realms) "",
+ MEMBER(default_realm) "",
+ MEMBER(cache_size) 0,
+ MEMBER(cache_ttl) 3600,
+ MEMBER(cache_negative_ttl) 0,
+ MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@",
+ MEMBER(username_translation) "",
+ MEMBER(username_format) "",
+ MEMBER(master_user_separator) "",
+ MEMBER(anonymous_username) "anonymous",
+ MEMBER(krb5_keytab) "",
+ MEMBER(gssapi_hostname) "",
+ MEMBER(winbind_helper_path) "/usr/bin/ntlm_auth",
+ MEMBER(failure_delay) 2,
+
+ MEMBER(verbose) FALSE,
+ MEMBER(debug) FALSE,
+ MEMBER(debug_passwords) FALSE,
+ MEMBER(ssl_require_client_cert) FALSE,
+ MEMBER(ssl_username_from_cert) FALSE,
+ MEMBER(use_winbind) FALSE,
+
+ MEMBER(worker_max_count) 30,
+
+ MEMBER(sockets) ARRAY_INIT,
+ MEMBER(passdbs) ARRAY_INIT,
+ MEMBER(userdbs) ARRAY_INIT
+};
+
+struct setting_parser_info auth_setting_parser_info = {
+ MEMBER(defines) auth_setting_defines,
+ MEMBER(defaults) &auth_default_settings,
+
+ MEMBER(parent) &auth_root_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) offsetof(struct auth_settings, root),
+ MEMBER(type_offset) offsetof(struct auth_settings, name),
+ MEMBER(struct_size) sizeof(struct auth_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct auth_root_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct auth_root_settings, field), defines }
+
+static struct setting_define auth_root_setting_defines[] = {
+ DEF(SET_STR, base_dir),
+ DEFLIST(auths, "auth", &auth_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct auth_root_settings auth_root_default_settings = {
+ MEMBER(base_dir) PKG_RUNDIR,
+ MEMBER(auths) ARRAY_INIT
+};
+
+struct setting_parser_info auth_root_setting_parser_info = {
+ MEMBER(defines) auth_root_setting_defines,
+ MEMBER(defaults) &auth_root_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct auth_root_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static void fix_base_path(struct auth_settings *set, const char **str)
+{
+ if (*str != NULL && **str != '\0' && **str != '/') {
+ *str = p_strconcat(settings_pool,
+ set->root->base_dir, "/", *str, NULL);
+ }
+}
+
+static void auth_settings_check(struct auth_settings *set)
+{
+ struct auth_socket_unix_settings *const *u;
+ struct auth_socket_settings *const *sockets;
+ unsigned int i, j, count, count2;
+
+ if (!array_is_created(&set->sockets))
+ return;
+
+ sockets = array_get(&set->sockets, &count);
+ for (i = 0; i < count; i++) {
+ if (array_is_created(&sockets[i]->masters)) {
+ u = array_get(&sockets[i]->masters, &count2);
+ for (j = 0; j < count2; j++)
+ fix_base_path(set, &u[j]->path);
+ }
+ if (array_is_created(&sockets[i]->clients)) {
+ u = array_get(&sockets[i]->clients, &count2);
+ for (j = 0; j < count2; j++)
+ fix_base_path(set, &u[j]->path);
+ }
+ }
+}
+
+struct auth_settings *auth_settings_read(const char *name)
+{
+ struct setting_parser_context *parser;
+ struct auth_root_settings *set;
+ struct auth_settings *const *auths;
+ unsigned int i, count;
+
+ if (settings_pool == NULL)
+ settings_pool = pool_alloconly_create("auth settings", 1024);
+ else
+ p_clear(settings_pool);
+
+ parser = settings_parser_init(settings_pool,
+ &auth_root_setting_parser_info,
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+ auth_default_settings.gssapi_hostname = my_hostname;
+
+ if (settings_parse_environ(parser) < 0) {
+ i_fatal("Error reading configuration: %s",
+ settings_parser_get_error(parser));
+ }
+
+ set = settings_parser_get(parser);
+ settings_parser_deinit(&parser);
+
+ if (array_is_created(&set->auths)) {
+ auths = array_get(&set->auths, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(auths[i]->name, name) == 0) {
+ auth_settings_check(auths[i]);
+ return auths[i];
+ }
+ }
+ }
+ i_fatal("Error reading configuration: No auth section: %s", name);
+ return NULL;
+}
--- /dev/null
+#ifndef AUTH_SETTINGS_H
+#define AUTH_SETTINGS_H
+
+struct auth_socket_unix_settings {
+ const char *path;
+ unsigned int mode;
+ const char *user;
+ const char *group;
+};
+
+struct auth_socket_settings {
+ const char *type;
+
+ ARRAY_DEFINE(clients, struct auth_socket_unix_settings *);
+ ARRAY_DEFINE(masters, struct auth_socket_unix_settings *);
+};
+
+struct auth_passdb_settings {
+ const char *driver;
+ const char *args;
+ bool deny;
+ bool pass;
+ bool master;
+};
+
+struct auth_userdb_settings {
+ const char *driver;
+ const char *args;
+};
+
+struct auth_settings {
+ const char *name;
+ struct auth_root_settings *root;
+
+ const char *mechanisms;
+ const char *realms;
+ const char *default_realm;
+ unsigned int cache_size;
+ unsigned int cache_ttl;
+ unsigned int cache_negative_ttl;
+ const char *username_chars;
+ const char *username_translation;
+ const char *username_format;
+ const char *master_user_separator;
+ const char *anonymous_username;
+ const char *krb5_keytab;
+ const char *gssapi_hostname;
+ const char *winbind_helper_path;
+ unsigned int failure_delay;
+
+ bool verbose, debug, debug_passwords;
+ bool ssl_require_client_cert;
+ bool ssl_username_from_cert;
+ bool use_winbind;
+
+ unsigned int worker_max_count;
+
+ ARRAY_DEFINE(sockets, struct auth_socket_settings *);
+ ARRAY_DEFINE(passdbs, struct auth_passdb_settings *);
+ ARRAY_DEFINE(userdbs, struct auth_userdb_settings *);
+};
+
+struct auth_root_settings {
+ const char *base_dir;
+
+ ARRAY_DEFINE(auths, struct auth_settings *);
+};
+
+struct auth_settings *auth_settings_read(const char *name);
+
+#endif
};
struct auth_worker_connection {
+ struct auth *auth;
int fd;
struct io *io;
static ARRAY_DEFINE(connections, struct auth_worker_connection *) = ARRAY_INIT;
static unsigned int idle_count;
-static unsigned int auth_workers_max;
-
static ARRAY_DEFINE(worker_request_array, struct auth_worker_request *);
static struct aqueue *worker_request_queue;
static time_t auth_worker_last_warn;
auth_worker_request_send(conn, request);
}
-static struct auth_worker_connection *auth_worker_create(void)
+static struct auth_worker_connection *auth_worker_create(struct auth *auth)
{
struct auth_worker_connection *conn;
int fd, try;
- if (array_count(&connections) >= auth_workers_max)
+ if (array_count(&connections) >= auth->set->worker_max_count)
return NULL;
for (try = 0;; try++) {
}
conn = i_new(struct auth_worker_connection, 1);
+ conn->auth = auth;
conn->fd = fd;
conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
FALSE);
const char *reason, bool restart)
{
struct auth_worker_connection *conn = *_conn;
+ struct auth *auth = conn->auth;
struct auth_worker_connection **connp;
unsigned int i, count;
i_free(conn);
if (idle_count == 0 && restart) {
- conn = auth_worker_create();
+ conn = auth_worker_create(auth);
if (conn != NULL)
auth_worker_request_send_next(conn);
}
conn = auth_worker_find_free();
if (conn == NULL) {
/* no free connections, create a new one */
- conn = auth_worker_create();
+ conn = auth_worker_create(auth_request->auth);
}
}
if (conn != NULL)
}
}
-void auth_worker_server_init(void)
+void auth_worker_server_init(struct auth *auth)
{
const char *env;
i_fatal("AUTH_WORKER_PATH environment not set");
worker_socket_path = i_strdup(env);
- env = getenv("AUTH_WORKER_MAX_COUNT");
- if (env == NULL)
- i_fatal("AUTH_WORKER_MAX_COUNT environment not set");
- auth_workers_max = atoi(env);
-
i_array_init(&worker_request_array, 128);
worker_request_queue = aqueue_init(&worker_request_array.arr);
i_array_init(&connections, 16);
- (void)auth_worker_create();
+ (void)auth_worker_create(auth);
}
void auth_worker_server_deinit(void)
struct auth_stream_reply *data,
auth_worker_callback_t *callback);
-void auth_worker_server_init(void);
+void auth_worker_server_init(struct auth *auth);
void auth_worker_server_deinit(void);
#endif
#include "common.h"
#include "network.h"
-#include "buffer.h"
+#include "array.h"
#include "str.h"
-#include "hostpid.h"
+#include "env-util.h"
#include "mech.h"
#include "userdb.h"
#include "passdb.h"
#include <stdlib.h>
#include <unistd.h>
-struct auth *auth_preinit(void)
+struct auth_userdb_settings userdb_dummy_set = {
+ MEMBER(driver) "static",
+ MEMBER(args) ""
+};
+
+struct auth *auth_preinit(struct auth_settings *set)
{
+ struct auth_passdb_settings *const *passdbs;
+ struct auth_userdb_settings *const *userdbs;
struct auth *auth;
- struct auth_passdb *auth_passdb, **passdb_p, **masterdb_p;
- const char *driver, *args;
pool_t pool;
- unsigned int i;
+ unsigned int i, count, db_count, passdb_count, last_passdb = 0;
pool = pool_alloconly_create("auth", 2048);
auth = p_new(pool, struct auth, 1);
auth->pool = pool;
+ auth->set = set;
- auth->verbose_debug_passwords =
- getenv("VERBOSE_DEBUG_PASSWORDS") != NULL;
- auth->verbose_debug = getenv("VERBOSE_DEBUG") != NULL ||
- auth->verbose_debug_passwords;
- auth->verbose = getenv("VERBOSE") != NULL || auth->verbose_debug;
-
- passdb_p = &auth->passdbs;
- masterdb_p = &auth->masterdbs;
- auth_passdb = NULL;
- for (i = 1; ; i++) {
- driver = getenv(t_strdup_printf("PASSDB_%u_DRIVER", i));
- if (driver == NULL)
- break;
+ if (array_is_created(&set->passdbs))
+ passdbs = array_get(&set->passdbs, &db_count);
+ else {
+ passdbs = NULL;
+ db_count = 0;
+ }
- args = getenv(t_strdup_printf("PASSDB_%u_ARGS", i));
- auth_passdb = passdb_preinit(auth, driver, args, i);
+ /* initialize passdbs first and count them */
+ for (passdb_count = 0, i = 0; i < db_count; i++) {
+ if (passdbs[i]->master)
+ continue;
- auth_passdb->deny =
- getenv(t_strdup_printf("PASSDB_%u_DENY", i)) != NULL;
- auth_passdb->pass =
- getenv(t_strdup_printf("PASSDB_%u_PASS", i)) != NULL;
+ passdb_preinit(auth, passdbs[i]);
+ passdb_count++;
+ last_passdb = i;
+ }
+ if (passdb_count != 0 && passdbs[last_passdb]->pass)
+ i_fatal("Last passdb can't have pass=yes");
- if (getenv(t_strdup_printf("PASSDB_%u_MASTER", i)) == NULL) {
- *passdb_p = auth_passdb;
- passdb_p = &auth_passdb->next;
- } else {
- if (auth_passdb->deny)
- i_fatal("Master passdb can't have deny=yes");
+ for (passdb_count = 0, i = 0; i < db_count; i++) {
+ if (!passdbs[i]->master)
+ continue;
- *masterdb_p = auth_passdb;
- masterdb_p = &auth_passdb->next;
- }
- }
- if (auth_passdb != NULL && auth_passdb->pass) {
- if (masterdb_p != &auth_passdb->next)
- i_fatal("Last passdb can't have pass=yes");
- else if (auth->passdbs == NULL) {
+ if (passdbs[i]->deny)
+ i_fatal("Master passdb can't have deny=yes");
+ if (passdbs[i]->pass && passdb_count == 0) {
i_fatal("Master passdb can't have pass=yes "
"if there are no passdbs");
}
+ passdb_preinit(auth, passdbs[i]);
}
- for (i = 1; ; i++) {
- driver = getenv(t_strdup_printf("USERDB_%u_DRIVER", i));
- if (driver == NULL)
- break;
-
- args = getenv(t_strdup_printf("USERDB_%u_ARGS", i));
- userdb_preinit(auth, driver, args);
+ if (array_is_created(&set->userdbs)) {
+ userdbs = array_get(&set->userdbs, &count);
+ for (i = 0; i < count; i++)
+ userdb_preinit(auth, userdbs[i]);
}
if (auth->userdbs == NULL) {
/* use a dummy userdb static. */
- userdb_preinit(auth, "static", "");
+ userdb_preinit(auth, &userdb_dummy_set);
}
return auth;
}
struct auth_userdb *userdb;
const struct mech_module *mech;
const char *const *mechanisms;
- const char *env;
+ const char *p;
for (passdb = auth->masterdbs; passdb != NULL; passdb = passdb->next)
passdb_init(passdb);
userdb_init(userdb);
/* caching is handled only by the main auth process */
if (!worker)
- passdb_cache_init();
+ passdb_cache_init(auth->set);
auth->mech_handshake = str_new(auth->pool, 512);
- auth->anonymous_username = getenv("ANONYMOUS_USERNAME");
- if (auth->anonymous_username != NULL &&
- *auth->anonymous_username == '\0')
- auth->anonymous_username = NULL;
-
/* register wanted mechanisms */
- env = getenv("MECHANISMS");
- if (env == NULL)
- i_fatal("MECHANISMS environment is unset");
-
- mechanisms = t_strsplit_spaces(env, " ");
+ mechanisms = t_strsplit_spaces(auth->set->mechanisms, " ");
while (*mechanisms != NULL) {
if (strcasecmp(*mechanisms, "ANONYMOUS") == 0) {
- if (auth->anonymous_username == NULL) {
+ if (*auth->set->anonymous_username == '\0') {
i_fatal("ANONYMOUS listed in mechanisms, "
- "but anonymous_username not given");
+ "but anonymous_username not set");
}
}
mech = mech_module_find(*mechanisms);
i_fatal("No authentication mechanisms configured");
auth_mech_list_verify_passdb(auth);
- env = getenv("REALMS");
- if (env == NULL)
- env = "";
- auth->auth_realms = p_strsplit_spaces(auth->pool, env, " ");
+ auth->auth_realms = (const char *const *)
+ p_strsplit_spaces(auth->pool, auth->set->realms, " ");
- env = getenv("DEFAULT_REALM");
- if (env != NULL && *env != '\0')
- auth->default_realm = env;
-
- env = getenv("USERNAME_CHARS");
- if (env == NULL || *env == '\0') {
+ if (*auth->set->username_chars == '\0') {
/* all chars are allowed */
memset(auth->username_chars, 1, sizeof(auth->username_chars));
} else {
- for (; *env != '\0'; env++)
- auth->username_chars[(int)(uint8_t)*env] = 1;
+ for (p = auth->set->username_chars; *p != '\0'; p++)
+ auth->username_chars[(int)(uint8_t)*p] = 1;
}
- env = getenv("USERNAME_TRANSLATION");
- if (env != NULL) {
- for (; *env != '\0' && env[1] != '\0'; env += 2)
- auth->username_translation[(int)(uint8_t)*env] = env[1];
+ if (*auth->set->username_translation != '\0') {
+ p = auth->set->username_translation;
+ for (; *p != '\0' && p[1] != '\0'; p += 2)
+ auth->username_translation[(int)(uint8_t)*p] = p[1];
}
-
- env = getenv("USERNAME_FORMAT");
- if (env != NULL && *env != '\0')
- auth->username_format = env;
-
- env = getenv("GSSAPI_HOSTNAME");
- if (env != NULL && *env != '\0')
- auth->gssapi_hostname = env;
- else
- auth->gssapi_hostname = my_hostname;
-
- env = getenv("MASTER_USER_SEPARATOR");
- if (env != NULL)
- auth->master_user_separator = env[0];
-
- auth->ssl_require_client_cert =
- getenv("SSL_REQUIRE_CLIENT_CERT") != NULL;
- auth->ssl_username_from_cert =
- getenv("SSL_USERNAME_FROM_CERT") != NULL;
}
void auth_deinit(struct auth **_auth)
#ifndef AUTH_H
#define AUTH_H
+#include "auth-settings.h"
+
#define PASSWORD_HIDDEN_STR "<hidden>"
struct auth_passdb {
struct auth {
pool_t pool;
+ const struct auth_settings *set;
struct mech_module_list *mech_modules;
buffer_t *mech_handshake;
struct auth_passdb *passdbs;
struct auth_userdb *userdbs;
- char *const *auth_realms;
- const char *default_realm;
- const char *anonymous_username;
- const char *username_format;
- const char *gssapi_hostname;
+ const char *const *auth_realms;
char username_chars[256];
char username_translation[256];
- char master_user_separator;
- bool ssl_require_client_cert;
- bool ssl_username_from_cert;
-
- bool verbose, verbose_debug, verbose_debug_passwords;
};
const string_t *auth_mechanisms_get_list(struct auth *auth);
-struct auth *auth_preinit(void);
+struct auth *auth_preinit(struct auth_settings *set);
void auth_init(struct auth *auth);
void auth_deinit(struct auth **auth);
ctx->static_attrs = t_strsplit(str_c(str), ",");
}
- if (auth_request->auth->verbose_debug)
+ if (auth_request->auth->set->debug)
ctx->debug = t_str_new(256);
ctx->attr = ldap_first_attribute(conn->ld, entry, &ctx->ber);
if (ctx->debug != NULL) {
if (!first)
str_append_c(ctx->debug, '/');
- if (ctx->auth_request->auth->verbose_debug_passwords ||
+ if (ctx->auth_request->auth->set->debug_passwords ||
strcmp(ctx->name, "password") != 0)
str_append(ctx->debug, ctx->value);
else
static void drop_privileges(void)
{
- const char *version;
+ const char *version, *name;
version = getenv("DOVECOT_VERSION");
if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
"it standalone, you'll need to set AUTH_* "
"environment variables (AUTH_1 isn't set).");
}
+ name = getenv("AUTH_NAME");
+ if (name == NULL)
+ i_fatal("Missing AUTH_NAME environment");
open_logfile();
userdbs_init();
modules = module_dir_load(AUTH_MODULE_DIR, NULL, TRUE, version);
module_dir_init(modules);
- auth = auth_preinit();
+ auth = auth_preinit(auth_settings_read(name));
auth_master_listeners_init();
if (!worker)
add_extra_listeners();
lib_signals_ignore(SIGUSR2, TRUE);
child_wait_init();
- mech_init();
+ mech_init(auth->set);
password_schemes_init();
auth_init(auth);
auth_request_handler_init();
auth_worker_server_deinit();
auth_master_listeners_deinit();
- auth_deinit(&auth);
module_dir_unload(&modules);
userdbs_deinit();
passdbs_deinit();
- mech_deinit();
+ mech_deinit(auth->set);
+ auth_deinit(&auth);
password_schemes_deinit();
sql_drivers_deinit();
mech_anonymous_auth_continue(struct auth_request *request,
const unsigned char *data, size_t data_size)
{
- i_assert(request->auth->anonymous_username != NULL);
+ i_assert(*request->auth->set->anonymous_username != '\0');
- if (request->auth->verbose) {
+ if (request->auth->set->verbose) {
/* temporarily set the user to the one that was given,
so that the log message goes right */
request->user =
}
request->user = p_strdup(request->pool,
- request->auth->anonymous_username);
+ request->auth->set->anonymous_username);
auth_request_success(request, NULL, 0);
}
struct auth *auth = request->auth_request.auth;
buffer_t *buf;
string_t *str;
- char *const *tmp;
+ const char *const *tmp;
unsigned char nonce[16];
int i;
bool first_qop;
static bool verify_realm(struct digest_auth_request *request, const char *realm)
{
- char *const *tmp;
+ const char *const *tmp;
if (*realm == '\0')
return TRUE;
*/
#include "common.h"
-#include "mech.h"
-#include "passdb.h"
+#include "env-util.h"
#include "str.h"
#include "str-sanitize.h"
-#include "buffer.h"
#include "hex-binary.h"
#include "safe-memset.h"
+#include "mech.h"
+#include "passdb.h"
#include <stdlib.h>
} while (message_context != 0);
}
-static void mech_gssapi_initialize(void)
+static void mech_gssapi_initialize(struct auth *auth)
{
- const char *path;
+ const char *path = auth->set->krb5_keytab;
- path = getenv("KRB5_KTNAME");
- if (path != NULL) {
+ if (*path != '\0') {
+ /* environment may be used by Kerberos 5 library directly */
+ env_put(t_strconcat("KRB5_KTNAME=", path, NULL));
#ifdef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY
gsskrb5_register_acceptor_identity(path);
#elif defined (HAVE_KRB5_GSS_REGISTER_ACCEPTOR_IDENTITY)
struct gssapi_auth_request *request;
pool_t pool;
- if (!gssapi_initialized) {
- gssapi_initialized = TRUE;
- mech_gssapi_initialize();
- }
-
pool = pool_alloconly_create("gssapi_auth_request", 1024);
request = p_new(pool, struct gssapi_auth_request, 1);
request->pool = pool;
gss_name_t gss_principal;
const char *service_name;
- if (strcmp(request->auth->gssapi_hostname, "$ALL") == 0) {
+ if (!gssapi_initialized) {
+ gssapi_initialized = TRUE;
+ mech_gssapi_initialize(request->auth);
+ }
+
+ if (strcmp(request->auth->set->gssapi_hostname, "$ALL") == 0) {
auth_request_log_info(request, "gssapi",
"Using all keytab entries");
*ret = GSS_C_NO_CREDENTIAL;
principal_name = t_str_new(128);
str_append(principal_name, service_name);
str_append_c(principal_name, '@');
- str_append(principal_name, request->auth->gssapi_hostname);
+ str_append(principal_name, request->auth->set->gssapi_hostname);
auth_request_log_info(request, "gssapi",
"Obtaining credentials for %s", str_c(principal_name));
static bool
rpa_verify_realm(struct rpa_auth_request *request, const char *realm)
{
+ const struct auth *auth = request->auth_request.auth;
const char *default_realm;
- char *const *tmp;
+ const char *const *tmp;
- tmp = request->auth_request.auth->auth_realms;
- for (; *tmp != NULL; tmp++) {
+ for (tmp = auth->auth_realms; *tmp != NULL; tmp++) {
if (strcasecmp(realm, *tmp) == 0)
return TRUE;
}
- default_realm = request->auth_request.auth->default_realm != NULL ?
- request->auth_request.auth->default_realm :
- my_hostname;
+ default_realm = *auth->set->default_realm != '\0' ?
+ auth->set->default_realm : my_hostname;
return strcasecmp(realm, default_realm) == 0;
}
string_t *realms;
buffer_t *buf;
unsigned char timestamp[RPA_TIMESTAMP_LEN / 2];
- char *const *tmp;
+ const char *const *tmp;
realms = t_str_new(64);
for (tmp = auth->auth_realms; *tmp != NULL; tmp++) {
}
if (str_len(realms) == 0) {
- rpa_add_realm(realms, auth->default_realm != NULL ?
- auth->default_realm : my_hostname,
+ rpa_add_realm(realms, *auth->set->default_realm != '\0' ?
+ auth->set->default_realm : my_hostname,
request->auth_request.service);
}
winbind_wait_pid(&winbind_spnego_context);
}
-static void winbind_helper_connect(struct winbind_helper *winbind)
+static void
+winbind_helper_connect(struct auth *auth, struct winbind_helper *winbind)
{
int infd[2], outfd[2];
pid_t pid;
if (pid == 0) {
/* child */
- const char *helper_path, *args[3];
+ const char *args[3];
(void)close(infd[0]);
(void)close(outfd[1]);
dup2(infd[1], STDOUT_FILENO) < 0)
i_fatal("dup2() failed: %m");
- helper_path = getenv("WINBIND_HELPER_PATH");
- if (helper_path == NULL)
- helper_path = DEFAULT_WINBIND_HELPER_PATH;
-
- args[0] = helper_path;
+ args[0] = auth->set->winbind_helper_path;
args[1] = winbind->param;
args[2] = NULL;
execv(args[0], (void *)args);
}
}
+static void
+mech_winbind_auth_initial(struct auth_request *auth_request,
+ const unsigned char *data, size_t data_size)
+{
+ struct winbind_auth_request *request =
+ (struct winbind_auth_request *)auth_request;
+
+ winbind_helper_connect(auth_request->auth, request->winbind);
+ mech_generic_auth_initial(auth_request, data, data_size);
+}
+
static void
mech_winbind_auth_continue(struct auth_request *auth_request,
const unsigned char *data, size_t data_size)
request->auth_request.pool = pool;
request->winbind = winbind;
- winbind_helper_connect(request->winbind);
return &request->auth_request;
}
MEMBER(passdb_need) MECH_PASSDB_NEED_NOTHING,
mech_winbind_spnego_auth_new,
- mech_generic_auth_initial,
+ mech_winbind_auth_initial,
mech_winbind_auth_continue,
mech_generic_auth_free
};
extern const struct mech_module mech_winbind_ntlm;
extern const struct mech_module mech_winbind_spnego;
-void mech_init(void)
+void mech_init(const struct auth_settings *set)
{
mech_register_module(&mech_plain);
mech_register_module(&mech_login);
mech_register_module(&mech_apop);
mech_register_module(&mech_cram_md5);
mech_register_module(&mech_digest_md5);
- if (getenv("USE_WINBIND") != NULL) {
+ if (set->use_winbind) {
mech_register_module(&mech_winbind_ntlm);
mech_register_module(&mech_winbind_spnego);
} else {
#endif
}
-void mech_deinit(void)
+void mech_deinit(const struct auth_settings *set)
{
mech_unregister_module(&mech_plain);
mech_unregister_module(&mech_login);
mech_unregister_module(&mech_apop);
mech_unregister_module(&mech_cram_md5);
mech_unregister_module(&mech_digest_md5);
- if (getenv("NTLM_USE_WINBIND") != NULL) {
+ if (set->use_winbind) {
mech_unregister_module(&mech_winbind_ntlm);
mech_unregister_module(&mech_winbind_spnego);
} else {
const unsigned char *data, size_t data_size);
void mech_generic_auth_free(struct auth_request *request);
-void mech_init(void);
-void mech_deinit(void);
+void mech_init(const struct auth_settings *set);
+void mech_deinit(const struct auth_settings *set);
#endif
{
const char *p;
- if (!request->auth->verbose_debug_passwords &&
+ if (!request->auth->set->debug_passwords &&
*value != '\0' && *value != '\t') {
/* hide the password */
p = strchr(value, '\t');
return TRUE;
}
-void passdb_cache_init(void)
+void passdb_cache_init(const struct auth_settings *set)
{
- const char *env;
- size_t max_size;
- unsigned int cache_ttl, neg_cache_ttl;
-
- env = getenv("CACHE_SIZE");
- if (env == NULL)
- return;
-
- max_size = (size_t)strtoul(env, NULL, 10) * 1024;
- if (max_size == 0)
- return;
-
- env = getenv("CACHE_TTL");
- if (env == NULL)
- return;
-
- cache_ttl = (unsigned int)strtoul(env, NULL, 10);
- if (cache_ttl == 0)
+ if (set->cache_size == 0 || set->cache_ttl == 0)
return;
- env = getenv("CACHE_NEGATIVE_TTL");
- neg_cache_ttl = env == NULL ? 0 : (unsigned int)strtoul(env, NULL, 10);
- passdb_cache = auth_cache_new(max_size, cache_ttl, neg_cache_ttl);
+ passdb_cache = auth_cache_new(set->cache_size * 1024UL, set->cache_ttl,
+ set->cache_negative_ttl);
}
void passdb_cache_deinit(void)
enum passdb_result *result_r,
bool use_expired);
-void passdb_cache_init(void);
+void passdb_cache_init(const struct auth_settings *set);
void passdb_cache_deinit(void);
#endif
struct passwd_file_passdb_module, 1);
module->auth = auth_passdb->auth;
module->pwf = db_passwd_file_init(args, format, FALSE,
- module->auth->verbose_debug);
+ module->auth->set->debug);
if (!module->pwf->vars)
module->module.cache_key = format;
const char *error = t_strdup_printf(
"Requested %s scheme, but we have only %s",
wanted_scheme, input_scheme);
- if (auth_request->auth->verbose_debug_passwords) {
+ if (auth_request->auth->set->debug_passwords) {
error = t_strdup_printf("%s (input: %s)",
error, input);
}
/* we can generate anything out of plaintext passwords */
plaintext = t_strndup(*credentials_r, *size_r);
- if (auth_request->auth->verbose_debug_passwords) {
+ if (auth_request->auth->set->debug_passwords) {
auth_request_log_info(auth_request, "password",
"Generating %s from user %s password %s",
wanted_scheme, auth_request->original_username,
callback(result, credentials, size, auth_request);
}
-struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
- const char *args, unsigned int id)
+struct auth_passdb *
+passdb_preinit(struct auth *auth, struct auth_passdb_settings *set)
{
struct passdb_module_interface *iface;
- struct auth_passdb *auth_passdb;
-
- if (args == NULL) args = "";
+ struct auth_passdb *auth_passdb, **dest;
auth_passdb = p_new(auth->pool, struct auth_passdb, 1);
auth_passdb->auth = auth;
- auth_passdb->args = p_strdup(auth->pool, args);
- auth_passdb->id = id;
+ auth_passdb->args = set->args == NULL ? "" :
+ p_strdup(auth->pool, set->args);
+ auth_passdb->deny = set->deny;
+
+ for (dest = &auth->passdbs; *dest != NULL; dest = &(*dest)->next)
+ auth_passdb->id++;
+ *dest = auth_passdb;
- iface = passdb_interface_find(driver);
+ iface = passdb_interface_find(set->driver);
if (iface == NULL)
- i_fatal("Unknown passdb driver '%s'", driver);
+ i_fatal("Unknown passdb driver '%s'", set->driver);
if (iface->verify_plain == NULL) {
i_fatal("Support not compiled in for passdb driver '%s'",
- driver);
+ set->driver);
}
if (iface->preinit == NULL && iface->init == NULL &&
*auth_passdb->args != '\0') {
i_fatal("passdb %s: No args are supported: %s",
- driver, auth_passdb->args);
+ set->driver, auth_passdb->args);
}
if (iface->preinit == NULL) {
if (passdb->passdb->blocking && !worker) {
/* blocking passdb - we need an auth server */
- auth_worker_server_init();
+ auth_worker_server_init(passdb->auth);
}
}
lookup_credentials_callback_t *callback,
struct auth_request *auth_request);
-struct auth_passdb *passdb_preinit(struct auth *auth, const char *driver,
- const char *args, unsigned int id);
+struct auth_passdb *
+ passdb_preinit(struct auth *auth, struct auth_passdb_settings *set);
+
void passdb_init(struct auth_passdb *passdb);
void passdb_deinit(struct auth_passdb *passdb);
struct passwd_file_userdb_module, 1);
module->auth = auth_userdb->auth;
module->pwf = db_passwd_file_init(args, format, TRUE,
- module->auth->verbose_debug);
+ module->auth->set->debug);
if (!module->pwf->vars)
module->module.cache_key = PASSWD_FILE_CACHE_KEY;
"passdb didn't return userdb entries");
}
} else if (!auth_request->userdb_lookup ||
- auth_request->auth->verbose_debug) {
+ auth_request->auth->set->debug) {
/* more userdbs, they may know the user */
auth_request_log_info(auth_request, "prefetch",
"passdb didn't return userdb entries, "
return gr->gr_gid;
}
-void userdb_preinit(struct auth *auth, const char *driver, const char *args)
+void userdb_preinit(struct auth *auth, struct auth_userdb_settings *set)
{
struct userdb_module_interface *iface;
struct auth_userdb *auth_userdb, **dest;
- if (args == NULL) args = "";
-
auth_userdb = p_new(auth->pool, struct auth_userdb, 1);
auth_userdb->auth = auth;
- auth_userdb->args = p_strdup(auth->pool, args);
+ auth_userdb->args = set->args == NULL ? "" :
+ p_strdup(auth->pool, set->args);
for (dest = &auth->userdbs; *dest != NULL; dest = &(*dest)->next)
auth_userdb->num++;
*dest = auth_userdb;
- iface = userdb_interface_find(driver);
+ iface = userdb_interface_find(set->driver);
if (iface == NULL)
- i_fatal("Unknown userdb driver '%s'", driver);
+ i_fatal("Unknown userdb driver '%s'", set->driver);
if (iface->lookup == NULL) {
i_fatal("Support not compiled in for userdb driver '%s'",
- driver);
+ set->driver);
}
if (iface->preinit == NULL && iface->init == NULL &&
*auth_userdb->args != '\0') {
i_fatal("userdb %s: No args are supported: %s",
- driver, auth_userdb->args);
+ set->driver, auth_userdb->args);
}
if (iface->preinit == NULL) {
if (userdb->userdb->blocking && !worker) {
/* blocking userdb - we need an auth server */
- auth_worker_server_init();
+ auth_worker_server_init(userdb->auth);
}
}
uid_t userdb_parse_uid(struct auth_request *request, const char *str);
gid_t userdb_parse_gid(struct auth_request *request, const char *str);
-void userdb_preinit(struct auth *auth, const char *driver, const char *args);
+void userdb_preinit(struct auth *auth, struct auth_userdb_settings *set);
void userdb_init(struct auth_userdb *userdb);
void userdb_deinit(struct auth_userdb *userdb);
--- /dev/null
+bin_PROGRAMS = doveconf
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DPKG_RUNDIR=\""$(rundir)"\" \
+ -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+ -DMODULEDIR=\""$(moduledir)"\" \
+ -DSSLDIR=\""$(ssldir)\""
+
+doveconf_LDADD = \
+ ../lib-settings/libsettings.a \
+ ../lib/liblib.a \
+ $(RAND_LIBS)
+
+doveconf_SOURCES = \
+ all-settings.c \
+ config-connection.c \
+ config-parser.c \
+ main.c
+
+noinst_HEADERS = \
+ all-settings.h \
+ common.h \
+ config-connection.h \
+ config-parser.h
+
+all-settings.c: $(SETTING_FILES) $(top_srcdir)/src/config/settings-get.pl
+ $(top_srcdir)/src/config/settings-get.pl $(SETTING_FILES) > all-settings.c || rm -f all-settings.c
+
+EXTRA_DIST = \
+ settings-get.pl
--- /dev/null
+#ifndef __COMMON_H
+#define __COMMON_H
+
+#include "lib.h"
+
+extern struct master_service *service;
+extern string_t *config_string;
+
+#endif
--- /dev/null
+/* Copyright (C) 2005 Timo Sirainen */
+
+#include "common.h"
+#include "str.h"
+#include "ioloop.h"
+#include "network.h"
+#include "istream.h"
+#include "ostream.h"
+#include "config-connection.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define MAX_INBUF_SIZE 1024
+
+#define CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION 1
+#define CONFIG_CLIENT_PROTOCOL_MINOR_VERSION 0
+
+struct config_connection {
+ int fd;
+ struct istream *input;
+ struct ostream *output;
+ struct io *io;
+
+ unsigned int version_received:1;
+ unsigned int handshaked:1;
+};
+
+static const char *const *
+config_connection_next_line(struct config_connection *conn)
+{
+ const char *line;
+
+ line = i_stream_next_line(conn->input);
+ if (line == NULL)
+ return NULL;
+
+ return t_strsplit(line, "\t");
+}
+
+static void config_connection_request(struct config_connection *conn,
+ const char *const *args)
+{
+ /* <process> [<args>] */
+ // FIXME
+ o_stream_send(conn->output, str_data(config_string),
+ str_len(config_string));
+ o_stream_flush(conn->output);
+}
+
+static void config_connection_input(void *context)
+{
+ struct config_connection *conn = context;
+ const char *const *args, *line;
+
+ switch (i_stream_read(conn->input)) {
+ case -2:
+ i_error("BUG: Config client connection sent too much data");
+ config_connection_destroy(conn);
+ return;
+ case -1:
+ config_connection_destroy(conn);
+ return;
+ }
+
+ if (!conn->version_received) {
+ line = i_stream_next_line(conn->input);
+ if (line == NULL)
+ return;
+
+ if (strncmp(line, "VERSION\t", 8) != 0 ||
+ atoi(t_strcut(line + 8, '\t')) !=
+ CONFIG_CLIENT_PROTOCOL_MAJOR_VERSION) {
+ i_error("Config client not compatible with this server "
+ "(mixed old and new binaries?)");
+ config_connection_destroy(conn);
+ return;
+ }
+ conn->version_received = TRUE;
+ }
+
+ t_push();
+ while ((args = config_connection_next_line(conn)) != NULL) {
+ if (args[0] == NULL)
+ continue;
+ if (strcmp(args[0], "REQ") == 0)
+ config_connection_request(conn, args + 1);
+ }
+ t_pop();
+}
+
+struct config_connection *config_connection_create(int fd)
+{
+ struct config_connection *conn;
+
+ conn = i_new(struct config_connection, 1);
+ conn->fd = fd;
+ conn->input = i_stream_create_fd(fd, MAX_INBUF_SIZE, FALSE);
+ conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
+ conn->io = io_add(fd, IO_READ, config_connection_input, conn);
+ return conn;
+}
+
+void config_connection_destroy(struct config_connection *conn)
+{
+ io_remove(&conn->io);
+ i_stream_destroy(&conn->input);
+ o_stream_destroy(&conn->output);
+ if (close(conn->fd) < 0)
+ i_error("close(config conn) failed: %m");
+ i_free(conn);
+}
+
+void config_connection_dump_request(int fd, const char *service)
+{
+ struct config_connection *conn;
+ const char *args[2] = { service, NULL };
+
+ conn = config_connection_create(fd);
+ config_connection_request(conn, args);
+ config_connection_destroy(conn);
+}
--- /dev/null
+#ifndef __CONFIG_CONNECTION_H
+#define __CONFIG_CONNECTION_H
+
+struct config_connection *config_connection_create(int fd);
+void config_connection_destroy(struct config_connection *conn);
+
+void config_connection_dump_request(int fd, const char *service);
+
+#endif
--- /dev/null
+/* Copyright (C) 2005 Timo Sirainen */
+
+#include "lib.h"
+#include "array.h"
+#include "str.h"
+#include "hash.h"
+#include "strescape.h"
+#include "istream.h"
+#include "settings-parser.h"
+#include "all-settings.h"
+#include "config-parser.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
+
+void config_parsers_fix_parents(pool_t pool)
+{
+#if 0
+ struct config_setting_parser_list *l;
+ const struct setting_define *d;
+ ARRAY_DEFINE(parents, ARRAY_TYPE(dynamic_settings_parsers));
+ ARRAY_TYPE(dynamic_settings_parsers) *parsers;
+ struct dynamic_settings_parsers *parser;
+ unsigned int i, count;
+
+ /* FIXME: currently we assume everyone are under a single parent */
+ t_push();
+ t_array_init(&parents, 4);
+ for (l = config_setting_parsers; l->module_name != NULL; l++) {
+ if (l->root->parent == NULL)
+ continue;
+
+ for (d = l->root->parent->defines; d->key != NULL; d++) {
+ if (d->list_info == l->root)
+ break;
+ }
+
+ if (d->key == NULL) {
+ parsers = array_get_modifiable(&parents, &count);
+ for (i = 0; i < count; i++) {
+ parser = array_idx_modifiable(&parsers[i], 0);
+ if (parser->info->parent == l->root->parent)
+ break;
+ }
+ if (i == count) {
+ parsers = array_append_space(&parents);
+ t_array_init(parsers, 16);
+ }
+
+ parser = array_append_space(parsers);
+ parser->name = l->module_name;
+ parser->info = l->root;
+ }
+ }
+
+ parsers = array_get_modifiable(&parents, &count);
+ for (i = 0; i < count; i++) {
+ (void)array_append_space(&parsers[i]); /* NULL-terminate */
+ parser = array_idx_modifiable(&parsers[i], 0);
+
+ settings_parser_info_update(pool, parser->info->parent, parser);
+ }
+
+ t_pop();
+#endif
+}
+
+static const char *
+config_parse_line(pool_t pool, const char *key, const char *line,
+ const struct setting_parser_info **info_r)
+{
+ enum settings_parser_flags parser_flags =
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS;
+ struct config_setting_parser_list *l;
+ bool found = FALSE;
+ int ret;
+
+ *info_r = NULL;
+ for (l = config_setting_parsers; l->module_name != NULL; l++) {
+ if (l->parser == NULL) {
+ l->parser = settings_parser_init(pool, l->root,
+ parser_flags);
+ }
+
+ ret = settings_parse_line(l->parser, line);
+ if (ret > 0) {
+ found = TRUE;
+ *info_r = settings_parse_get_prev_info(l->parser);
+ } else if (ret < 0)
+ return settings_parser_get_error(l->parser);
+ }
+
+ return found ? NULL : t_strconcat("Unknown setting: ", key, NULL);
+}
+
+struct settings_export_context {
+ string_t *dest;
+ string_t *value;
+ string_t *prefix;
+ struct hash_table *keys;
+ pool_t pool;
+ bool export_defaults;
+};
+
+static void settings_export(struct settings_export_context *ctx,
+ const struct setting_parser_info *info,
+ const void *set)
+{
+ const struct setting_define *def;
+ const void *value, *default_value;
+ void *const *children = NULL;
+ unsigned int i, count, prefix_len;
+ char *key;
+
+ for (def = info->defines; def->key != NULL; def++) {
+ value = CONST_PTR_OFFSET(set, def->offset);
+ default_value = info->defaults == NULL ? NULL :
+ CONST_PTR_OFFSET(info->defaults, def->offset);
+
+ count = 0;
+ str_truncate(ctx->value, 0);
+ switch (def->type) {
+ case SET_INTERNAL:
+ break;
+ case SET_BOOL: {
+ const bool *val = value, *dval = default_value;
+ if (ctx->export_defaults ||
+ dval == NULL || *val != *dval) {
+ str_append(ctx->value,
+ *val ? "yes" : "no");
+ }
+ break;
+ }
+ case SET_UINT: {
+ const unsigned int *val = value, *dval = default_value;
+ if (ctx->export_defaults ||
+ dval == NULL || *val != *dval)
+ str_printfa(ctx->value, "%u", *val);
+ break;
+ }
+ case SET_STR_VARS: {
+ const char *const *val = value, *sval;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+
+ i_assert(*val == NULL ||
+ **val == SETTING_STRVAR_UNEXPANDED[0]);
+
+ sval = *val == NULL ? NULL : (*val + 1);
+ if ((ctx->export_defaults ||
+ null_strcmp(sval, dval) != 0) && sval != NULL)
+ str_append(ctx->value, sval);
+ break;
+ }
+ case SET_STR: {
+ const char *const *val = value;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+
+ if ((ctx->export_defaults ||
+ null_strcmp(*val, dval) != 0) && *val != NULL)
+ str_append(ctx->value, *val);
+ break;
+ }
+ case SET_ENUM: {
+ const char *const *val = value;
+ const char *const *_dval = default_value;
+ const char *dval = _dval == NULL ? NULL : *_dval;
+ unsigned int len = strlen(*val);
+
+ if (ctx->export_defaults ||
+ strncmp(*val, dval, len) != 0 ||
+ ((*val)[len] != ':' && (*val)[len] != '\0'))
+ str_append(ctx->value, *val);
+ break;
+ }
+ case SET_DEFLIST: {
+ const ARRAY_TYPE(void_array) *val = value;
+
+ if (!array_is_created(val))
+ break;
+
+ children = array_get(val, &count);
+ for (i = 0; i < count; i++) {
+ if (i > 0)
+ str_append_c(ctx->value, ' ');
+ str_printfa(ctx->value, "%u", i);
+ }
+ break;
+ }
+ case SET_STRLIST: {
+ const ARRAY_TYPE(const_string) *val = value;
+ unsigned int pos = str_len(ctx->dest);
+ const char *const *strings;
+
+ if (!array_is_created(val))
+ break;
+
+ str_append_str(ctx->dest, ctx->prefix);
+ str_append(ctx->dest, def->key);
+ str_append(ctx->dest, "=0\n");
+
+ if (hash_table_lookup(ctx->keys,
+ str_c(ctx->dest) + pos) != NULL) {
+ /* already added all of these */
+ str_truncate(ctx->dest, pos);
+ break;
+ }
+ key = p_strdup(ctx->pool, str_c(ctx->dest) + pos);
+ hash_table_insert(ctx->keys, key, key);
+
+ strings = array_get(val, &count);
+ i_assert(count % 2 == 0);
+ for (i = 0; i < count; i += 2) {
+ str_append_str(ctx->dest, ctx->prefix);
+ str_append(ctx->dest, def->key);
+ str_append_c(ctx->dest, SETTINGS_SEPARATOR);
+ str_append_c(ctx->dest, '0');
+ str_append_c(ctx->dest, SETTINGS_SEPARATOR);
+ str_append(ctx->dest, strings[i+0]);
+ str_append_c(ctx->dest, '=');
+ str_append(ctx->dest, strings[i+1]);
+ str_append_c(ctx->dest, '\n');
+ }
+ count = 0;
+ break;
+ }
+ }
+ if (str_len(ctx->value) > 0) {
+ unsigned int pos = str_len(ctx->dest);
+ str_append_str(ctx->dest, ctx->prefix);
+ str_append(ctx->dest, def->key);
+
+ if (hash_table_lookup(ctx->keys,
+ str_c(ctx->dest) + pos) != NULL) {
+ /* already exists */
+ str_truncate(ctx->dest, pos);
+ } else {
+ str_append_c(ctx->dest, '=');
+ str_append_str(ctx->dest, ctx->value);
+ str_append_c(ctx->dest, '\n');
+ key = p_strconcat(ctx->pool, str_c(ctx->prefix),
+ def->key, NULL);
+ hash_table_insert(ctx->keys, key, key);
+ }
+ }
+
+ prefix_len = str_len(ctx->prefix);
+ for (i = 0; i < count; i++) {
+ str_append(ctx->prefix, def->key);
+ str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
+ str_printfa(ctx->prefix, "%u", i);
+ str_append_c(ctx->prefix, SETTINGS_SEPARATOR);
+ settings_export(ctx, def->list_info, children[i]);
+
+ str_truncate(ctx->prefix, prefix_len);
+ }
+ }
+}
+
+static void config_export(string_t *dest)
+{
+ struct config_setting_parser_list *l;
+ struct settings_export_context ctx;
+ const void *set;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.dest = dest;
+ ctx.export_defaults = FALSE;
+ ctx.value = t_str_new(256);
+ ctx.prefix = t_str_new(64);
+ ctx.pool = pool_alloconly_create("config keys", 10240);
+ ctx.keys = hash_table_create(default_pool, ctx.pool, 0,
+ str_hash, (hash_cmp_callback_t *)strcmp);
+
+ for (l = config_setting_parsers; l->module_name != NULL; l++) {
+ if (l->parser != NULL) {
+ set = settings_parser_get(l->parser);
+ settings_export(&ctx, l->root, set);
+ }
+ }
+ hash_table_destroy(&ctx.keys);
+ pool_unref(&ctx.pool);
+}
+
+static const char *info_type_name_find(const struct setting_parser_info *info)
+{
+ unsigned int i;
+
+ for (i = 0; info->defines[i].key != NULL; i++) {
+ if (info->defines[i].offset == info->type_offset)
+ return info->defines[i].key;
+ }
+ i_panic("setting parser: Invalid type_offset value");
+ return NULL;
+}
+
+void config_parse_file(string_t *dest, const char *path, const char *service)
+{
+ ARRAY_DEFINE(pathlen_stack, unsigned int);
+ ARRAY_TYPE(const_string) auth_defaults;
+ const struct setting_parser_info *info;
+ unsigned int pathlen = 0;
+ unsigned int counter = 0, auth_counter = 0, cur_counter;
+ struct istream *input;
+ const char *errormsg, *name, *type_name;
+ char *line, *key, *p;
+ int fd, linenum, ret, ignore;
+ string_t *str, *full_line;
+ size_t len;
+ pool_t pool;
+ bool asis;
+
+ pool = pool_alloconly_create("config file parser", 10240);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ i_fatal("open(%s) failed: %m", path);
+
+ t_array_init(&pathlen_stack, 10);
+ t_array_init(&auth_defaults, 32);
+
+ errormsg = config_parse_line(pool, "0", "auth=0", &info);
+ i_assert(errormsg == NULL);
+
+ str = t_str_new(256);
+ full_line = t_str_new(512);
+ linenum = 0; errormsg = NULL; ignore = 0; asis = FALSE;
+ input = i_stream_create_fd(fd, (size_t)-1, FALSE);
+ while ((line = i_stream_read_next_line(input)) != NULL) {
+ linenum++;
+
+ /* @UNSAFE: line is modified */
+
+ /* skip whitespace */
+ while (IS_WHITE(*line))
+ line++;
+
+ /* ignore comments or empty lines */
+ if (*line == '#' || *line == '\0')
+ continue;
+
+ /* strip away comments. pretty kludgy way really.. */
+ for (p = line; *p != '\0'; p++) {
+ if (*p == '\'' || *p == '"') {
+ char quote = *p;
+ for (p++; *p != quote && *p != '\0'; p++) {
+ if (*p == '\\' && p[1] != '\0')
+ p++;
+ }
+ if (*p == '\0')
+ break;
+ } else if (*p == '#') {
+ *p = '\0';
+ break;
+ }
+ }
+
+ /* remove whitespace from end of line */
+ len = strlen(line);
+ while (IS_WHITE(line[len-1]))
+ len--;
+ line[len] = '\0';
+
+ if (len > 0 && line[len-1] == '\\') {
+ /* continues in next line */
+ line[len-1] = '\0';
+ str_append(full_line, line);
+ continue;
+ }
+ if (str_len(full_line) > 0) {
+ str_append(full_line, line);
+ line = str_c_modifiable(full_line);
+ }
+
+ /* a) key = value
+ b) section_type [section_name] {
+ c) } */
+ key = line;
+ while (!IS_WHITE(*line) && *line != '\0' && *line != '=')
+ line++;
+ if (IS_WHITE(*line)) {
+ *line++ = '\0';
+ while (IS_WHITE(*line)) line++;
+ }
+
+ ret = 1;
+ if (*line == '=') {
+ /* a) */
+ *line++ = '\0';
+ while (IS_WHITE(*line)) line++;
+
+ len = strlen(line);
+ if (len > 0 &&
+ ((*line == '"' && line[len-1] == '"') ||
+ (*line == '\'' && line[len-1] == '\''))) {
+ line[len-1] = '\0';
+ line = str_unescape(line+1);
+ }
+
+ str_truncate(str, pathlen);
+ str_append(str, key);
+ str_append_c(str, '=');
+ str_append(str, line);
+ if (ignore > 0) {
+ /* ignore this setting */
+ } else if (pathlen == 0 &&
+ strncmp(str_c(str), "auth_", 5) == 0) {
+ /* verify that the setting is valid,
+ but delay actually adding it */
+ const char *s = t_strdup(str_c(str) + 5);
+
+ str_truncate(str, 0);
+ str_printfa(str, "auth/0/%s=%s", key + 5, line);
+ errormsg = config_parse_line(pool, key + 5, str_c(str), &info);
+ array_append(&auth_defaults, &s, 1);
+ } else if (asis) {
+ /* don't do any parsing, just add it */
+ str_append(dest, str_c(str));
+ str_append_c(dest, '\n');
+ } else {
+ errormsg = config_parse_line(pool, key, str_c(str), &info);
+ }
+ } else if (strcmp(key, "}") != 0 || *line != '\0') {
+ /* b) + errors */
+ line[-1] = '\0';
+
+ if (*line == '{')
+ name = "";
+ else {
+ name = line;
+ while (!IS_WHITE(*line) && *line != '\0')
+ line++;
+
+ if (*line != '\0') {
+ *line++ = '\0';
+ while (IS_WHITE(*line))
+ line++;
+ }
+ }
+
+ if (*line != '{')
+ errormsg = "Expecting '='";
+ else if (ignore > 0) {
+ ignore++;
+ } else if (strcmp(key, "protocol") == 0) {
+ array_append(&pathlen_stack, &pathlen, 1);
+ ignore = strcmp(name, service) != 0;
+ } else {
+ array_append(&pathlen_stack, &pathlen, 1);
+
+ str_truncate(str, pathlen);
+ str_append(str, key);
+ pathlen = str_len(str);
+
+ if (strcmp(key, "auth") == 0)
+ cur_counter = auth_counter++;
+ else
+ cur_counter = counter++;
+
+ str_append_c(str, '=');
+ str_printfa(str, "%u", cur_counter);
+ if (cur_counter == 0 && strcmp(key, "auth") == 0) {
+ /* already added this */
+ } else {
+ errormsg = config_parse_line(pool, key,
+ str_c(str), &info);
+ }
+
+ str_truncate(str, pathlen);
+ str_append_c(str, SETTINGS_SEPARATOR);
+ str_printfa(str, "%u", cur_counter);
+ str_append_c(str, SETTINGS_SEPARATOR);
+ pathlen = str_len(str);
+
+ if (errormsg == NULL && info->type_offset != (size_t)-1) {
+ type_name = info_type_name_find(info);
+ str_append(str, type_name);
+ str_append_c(str, '=');
+ str_append(str, name);
+ errormsg = config_parse_line(pool, type_name,
+ str_c(str), &info);
+
+ str_truncate(str, pathlen);
+ }
+
+ if (strcmp(key, "auth") == 0 && errormsg == NULL) {
+ /* add auth default settings */
+ const char *const *lines;
+ unsigned int i, count;
+
+ lines = array_get(&auth_defaults, &count);
+ for (i = 0; i < count; i++) {
+ str_truncate(str, pathlen);
+
+ p = strchr(lines[i], '=');
+ str_append(str, lines[i]);
+
+ errormsg = config_parse_line(pool, t_strdup_until(lines[i], p), str_c(str), &info);
+ i_assert(errormsg == NULL);
+ }
+ }
+ }
+ } else {
+ /* c) */
+ unsigned int pathlen_count;
+ const unsigned int *arr;
+
+ if (ignore > 0)
+ ignore--;
+ asis = FALSE;
+
+ arr = array_get(&pathlen_stack, &pathlen_count);
+ if (pathlen_count == 0)
+ errormsg = "Unexpected '}'";
+ else {
+ pathlen = arr[pathlen_count - 1];
+ array_delete(&pathlen_stack,
+ pathlen_count - 1, 1);
+ }
+ }
+
+ if (errormsg != NULL) {
+ i_fatal("Error in configuration file %s line %d: %s",
+ path, linenum, errormsg);
+ break;
+ }
+ str_truncate(full_line, 0);
+ }
+ i_stream_unref(&input);
+ config_export(dest);
+}
--- /dev/null
+#ifndef __CONFIG_PARSER_H
+#define __CONFIG_PARSER_H
+
+void config_parsers_fix_parents(pool_t pool);
+
+void config_parse_file(string_t *dest, const char *path, const char *service);
+
+#endif
--- /dev/null
+/* Copyright (C) 2005-2008 Timo Sirainen */
+
+#include "common.h"
+#include "lib-signals.h"
+#include "ioloop.h"
+#include "str.h"
+#include "config-connection.h"
+#include "config-parser.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+string_t *config_string;
+pool_t parsers_pool;
+
+static const char *config_path = SYSCONFDIR "/" PACKAGE ".conf";
+
+static void main_init(const char *service)
+{
+ i_set_failure_internal();
+
+ parsers_pool = pool_alloconly_create("parent parsers", 2048);
+ config_parsers_fix_parents(parsers_pool);
+
+ config_string = str_new(default_pool, 10240);
+ config_parse_file(config_string, config_path, service);
+ str_append_c(config_string, '\n');
+}
+
+int main(int argc, char *argv[])
+{
+ struct ioloop *ioloop;
+ const char *path, *service = "";
+ bool dump_nondefaults = FALSE, human_readable = FALSE;
+ int c;
+
+ lib_init();
+
+ path = getenv("CONFIG_FILE_PATH");
+ if (path != NULL)
+ config_path = path;
+
+ while ((c = getopt(argc, argv, "c:s:na")) > 0) {
+ switch (c) {
+ case 'c':
+ config_path = optarg;
+ break;
+ case 's':
+ service = optarg;
+ break;
+ case 'n':
+ dump_nondefaults = TRUE;
+ /* fall through */
+ case 'a':
+ /* FIXME: make it work */
+ human_readable = TRUE;
+ break;
+ default:
+ i_fatal("Unknown parameter: %c", c);
+ }
+ }
+
+ main_init(service);
+ ioloop = io_loop_create();
+ config_connection_dump_request(STDOUT_FILENO, "master");
+ io_loop_destroy(&ioloop);
+ lib_deinit();
+ return 0;
+}
--- /dev/null
+#!/usr/bin/env perl
+use strict;
+
+print '#include "lib.h"'."\n";
+print '#include "settings-parser.h"'."\n";
+print '#include "all-settings.h"'."\n";
+print '#include <stddef.h>'."\n";
+print '#define CONFIG_BINARY'."\n";
+
+my %parsers = {};
+
+foreach my $file (@ARGV) {
+ my $f;
+ open($f, $file) || die "Can't open $file: $@";
+
+ my $state = 0;
+ my $file_contents = "";
+ my $externs = "";
+
+ while (<$f>) {
+ my $write = 0;
+ if ($state == 0) {
+ if (/struct .*_settings {/ ||
+ /struct setting_define.*{/ ||
+ /struct .*_default_settings = {/) {
+ $state++;
+ } elsif (/^(static )?struct setting_parser_info (.*) = {/) {
+ $state++;
+ $parsers{$2} = 1;
+ } elsif (/^extern struct setting_parser_info (.*);/) {
+ $externs .= "extern struct setting_parser_info $1;\n";
+ }
+
+ if (/#define.*DEF/ || /^#undef.*DEF/) {
+ $write = 1;
+ $state = 2 if (/\\$/);
+ }
+ } elsif ($state == 2) {
+ $write = 1;
+ $state = 0 if (!/\\$/);
+ }
+
+ if ($state == 1 || $state == 3) {
+ if ($state == 1) {
+ if (/DEFLIST.*".*",(.*)$/) {
+ my $value = $1;
+ if ($value =~ /.*&(.*)\)/) {
+ $parsers{$1} = 0;
+ $externs .= "extern struct setting_parser_info $1;\n";
+ } else {
+ $state = 3;
+ }
+ }
+ } elsif ($state == 3) {
+ if (/.*&(.*)\)/) {
+ $parsers{$1} = 0;
+ }
+ }
+
+ $write = 1;
+ if (/};/) {
+ $state = 0;
+ }
+ }
+
+ $file_contents .= $_ if ($write);
+ }
+
+ print "/* $file */\n";
+ print $externs;
+ print $file_contents;
+
+ close $f;
+}
+
+print "struct config_setting_parser_list config_setting_parsers[] = {\n";
+foreach my $name (keys %parsers) {
+ next if (!$parsers{$name});
+
+ my $module = "";
+ if ($name =~ /^([^_]*)/) {
+ $module = $1;
+ }
+ print " { \"$module\", &".$name.", NULL, NULL }, \n";
+}
+print " { NULL, NULL, NULL, NULL }\n";
+print "};\n";
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-auth \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-storage \
-I$(top_srcdir)/src/lib-storage/index \
-I$(top_srcdir)/src/lib-storage/index/raw \
+ -DBINDIR=\""$(bindir)"\" \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DPKG_RUNDIR=\""$(rundir)"\" \
-DMODULEDIR=\""$(moduledir)"\"
libs = \
$(STORAGE_LIBS) \
../lib-dict/libdict.a \
+ ../lib-settings/libsettings.a \
$(unused_objects)
deliver_LDADD = \
deliver_SOURCES = \
auth-client.c \
deliver.c \
+ deliver-settings.c \
duplicate.c \
mail-send.c \
smtp-client.c
headers = \
auth-client.h \
deliver.h \
+ deliver-settings.h \
duplicate.h \
mail-send.h \
smtp-client.h
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "deliver.h"
+#include "array.h"
+#include "hostpid.h"
+#include "istream.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "deliver-settings.h"
+
+#include <stddef.h>
+
+#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct deliver_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct deliver_settings, field), defines }
+
+static struct setting_define deliver_setting_defines[] = {
+ DEF(SET_STR, base_dir),
+ DEF(SET_STR, log_path),
+ DEF(SET_STR, info_log_path),
+ DEF(SET_STR, log_timestamp),
+ DEF(SET_STR, syslog_facility),
+ DEF(SET_BOOL, version_ignore),
+ DEF(SET_UINT, umask),
+
+ DEF(SET_STR, mail_plugins),
+ DEF(SET_STR, mail_plugin_dir),
+ DEF(SET_STR_VARS, mail_log_prefix),
+
+ DEF(SET_STR, postmaster_address),
+ DEF(SET_STR, hostname),
+ DEF(SET_STR, sendmail_path),
+ DEF(SET_STR, rejection_subject),
+ DEF(SET_STR, rejection_reason),
+ DEF(SET_STR, auth_socket_path),
+ DEF(SET_STR, deliver_log_format),
+ DEF(SET_BOOL, quota_full_tempfail),
+
+ { SET_STRLIST, "plugin", offsetof(struct deliver_settings, plugin_envs), NULL },
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct deliver_settings deliver_default_settings = {
+ MEMBER(base_dir) PKG_RUNDIR,
+ MEMBER(log_path) "",
+ MEMBER(info_log_path) "",
+ MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT,
+ MEMBER(syslog_facility) "mail",
+ MEMBER(version_ignore) FALSE,
+ MEMBER(umask) 0077,
+
+ MEMBER(mail_plugins) "",
+ MEMBER(mail_plugin_dir) MODULEDIR"/lda",
+ MEMBER(mail_log_prefix) "%Us(%u): ",
+
+ MEMBER(postmaster_address) "",
+ MEMBER(hostname) "",
+ MEMBER(sendmail_path) "/usr/lib/sendmail",
+ MEMBER(rejection_subject) "Rejected: %s",
+ MEMBER(rejection_reason)
+ "Your message to <%t> was automatically rejected:%n%r",
+ MEMBER(auth_socket_path) "auth-master",
+ MEMBER(deliver_log_format) "msgid=%m: %$",
+ MEMBER(quota_full_tempfail) FALSE
+};
+
+struct setting_parser_info deliver_setting_parser_info = {
+ MEMBER(defines) deliver_setting_defines,
+ MEMBER(defaults) &deliver_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct deliver_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static void fix_base_path(struct deliver_settings *set, const char **str)
+{
+ if (*str != NULL && **str != '\0' && **str != '/') {
+ *str = p_strconcat(settings_pool,
+ set->base_dir, "/", *str, NULL);
+ }
+}
+
+struct setting_parser_context *
+deliver_settings_read(const char *path,
+ struct deliver_settings **set_r,
+ struct mail_user_settings **user_set_r)
+{
+ static const struct setting_parser_info *roots[] = {
+ &deliver_setting_parser_info,
+ &mail_user_setting_parser_info
+ };
+ void **sets;
+ struct deliver_settings *deliver_set;
+ struct setting_parser_context *parser;
+
+ if (settings_pool == NULL)
+ settings_pool = pool_alloconly_create("deliver settings", 1024);
+ else
+ p_clear(settings_pool);
+
+ mail_storage_namespace_defines_init(settings_pool);
+
+ parser = settings_parser_init_list(settings_pool,
+ roots, N_ELEMENTS(roots),
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+ if (settings_parse_exec(parser, DOVECOT_CONFIG_BIN_PATH,
+ path, "lda") < 0) {
+ i_fatal_status(EX_CONFIG, "Error reading configuration: %s",
+ settings_parser_get_error(parser));
+ }
+
+ sets = settings_parser_get_list(parser);
+
+ deliver_set = sets[0];
+ if (*deliver_set->hostname == '\0')
+ deliver_set->hostname = my_hostname;
+ fix_base_path(deliver_set, &deliver_set->auth_socket_path);
+
+ if (*deliver_set->postmaster_address == '\0') {
+ i_fatal_status(EX_CONFIG,
+ "postmaster_address setting not given");
+ }
+
+ *set_r = deliver_set;
+ *user_set_r = sets[1];
+ return parser;
+}
+
+void deliver_settings_add(struct setting_parser_context *parser,
+ const ARRAY_TYPE(const_string) *extra_fields)
+{
+ const char *const *str, *p, *line;
+ unsigned int i, count;
+
+ str = array_get(extra_fields, &count);
+ for (i = 0; i < count; i++) T_BEGIN {
+ p = strchr(str[i], '=');
+ if (p != NULL)
+ line = str[i];
+ else
+ line = t_strconcat(str[i], "=yes", NULL);
+ if (settings_parse_line(parser, str[i]) < 0) {
+ i_fatal_status(EX_CONFIG,
+ "Invalid userdb input '%s': %s", str[i],
+ settings_parser_get_error(parser));
+ }
+ } T_END;
+
+}
--- /dev/null
+#ifndef DELIVER_SETTINGS_H
+#define DELIVER_SETTINGS_H
+
+struct mail_user_settings;
+
+struct deliver_settings {
+ const char *base_dir;
+ const char *log_path;
+ const char *info_log_path;
+ const char *log_timestamp;
+ const char *syslog_facility;
+ bool version_ignore;
+ unsigned int umask;
+
+ const char *mail_plugins;
+ const char *mail_plugin_dir;
+ const char *mail_log_prefix;
+
+ /* deliver: */
+ const char *postmaster_address;
+ const char *hostname;
+ const char *sendmail_path;
+ const char *rejection_subject;
+ const char *rejection_reason;
+ const char *auth_socket_path;
+ const char *deliver_log_format;
+ bool quota_full_tempfail;
+
+ ARRAY_DEFINE(plugin_envs, const char *);
+};
+
+struct setting_parser_context *
+deliver_settings_read(const char *path,
+ struct deliver_settings **set_r,
+ struct mail_user_settings **user_set_r);
+void deliver_settings_add(struct setting_parser_context *parser,
+ const ARRAY_TYPE(const_string) *extra_fields);
+
+#endif
#include "mail-namespace.h"
#include "raw-storage.h"
#include "imap-utf7.h"
+#include "settings-parser.h"
#include "dict.h"
#include "auth-client.h"
#include "mail-send.h"
struct deliver_settings *deliver_set;
deliver_mail_func_t *deliver_mail = NULL;
+bool mailbox_autosubscribe;
+bool mailbox_autocreate;
bool tried_default_save = FALSE;
/* FIXME: these two should be in some context struct instead of as globals.. */
static struct module *modules;
static struct ioloop *ioloop;
-static pool_t plugin_pool;
-static ARRAY_DEFINE(lda_envs, const char *);
-static ARRAY_DEFINE(plugin_envs, const char *);
-
static void sig_die(int signo, void *context ATTR_UNUSED)
{
/* warn about being killed because of some signal, except SIGINT (^C)
msg = t_strdup_vprintf(fmt, args);
str = t_str_new(256);
- var_expand(str, deliver_set->log_format,
+ var_expand(str, deliver_set->deliver_log_format,
get_log_var_expand_table(mail, msg));
i_info("%s", str_c(str));
va_end(args);
}
box = mailbox_open(storage_r, name, NULL, open_flags);
- if (box != NULL || !deliver_set->mailbox_autocreate)
+ if (box != NULL || !mailbox_autocreate)
return box;
(void)mail_storage_get_last_error(*storage_r, &error);
/* try creating it. */
if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0)
return NULL;
- if (deliver_set->mailbox_autosubscribe) {
+ if (mailbox_autosubscribe) {
/* (try to) subscribe to it */
(void)mailbox_list_set_subscribed(ns->list, name, TRUE);
}
count++, deliver_set->hostname);
}
-#include "settings.h"
-#include "../master/master-settings.h"
-#include "../master/master-settings-defs.c"
-
-#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
-
-static bool setting_is_bool(const char *name)
-{
- const struct setting_def *def;
-
- for (def = setting_defs; def->name != NULL; def++) {
- if (strcmp(def->name, name) == 0)
- return def->type == SET_BOOL;
- }
- if (strncmp(name, "NAMESPACE_", 10) == 0) {
- return strstr(name, "_list") != NULL ||
- strstr(name, "_inbox") != NULL ||
- strstr(name, "_hidden") != NULL ||
- strstr(name, "_subscriptions") != NULL;
- }
- if (strcmp(name, "quota_full_tempfail") == 0)
- return TRUE;
- return FALSE;
-}
-
-/* more ugly kludging because we have our own config parsing code.
- hopefully this goes away in v1.2. */
-static struct {
- const char *name;
- bool set;
-} default_yes_settings[] = {
- { "dotlock_use_excl", TRUE },
- { "maildir_copy_with_hardlinks", TRUE },
- { "mbox_dirty_syncs", TRUE },
- { "mbox_lazy_writes", TRUE }
-};
-
-static void config_file_init(const char *path)
-{
- struct istream *input;
- const char *key, *value, *str, *ukey;
- char *line, *p, quote;
- int fd, sections = 0;
- bool lda_section = FALSE, pop3_section = FALSE, plugin_section = FALSE;
- bool ns_section = FALSE, ns_location = FALSE, ns_list = FALSE;
- bool ns_subscriptions = FALSE;
- unsigned int i, ns_idx = 0;
- size_t len;
-
- plugin_pool = pool_alloconly_create("Plugin strings", 512);
- i_array_init(&lda_envs, 16);
- i_array_init(&plugin_envs, 16);
-
- fd = open(path, O_RDONLY);
- if (fd < 0)
- i_fatal_status(EX_CONFIG, "open(%s) failed: %m", path);
-
- input = i_stream_create_fd(fd, 1024, TRUE);
- i_stream_set_return_partial_line(input, TRUE);
- while ((line = i_stream_read_next_line(input)) != NULL) {
- /* @UNSAFE: line is modified */
-
- /* skip whitespace */
- while (IS_WHITE(*line))
- line++;
-
- /* ignore comments or empty lines */
- if (*line == '#' || *line == '\0')
- continue;
-
- /* strip away comments. pretty kludgy way really.. */
- for (p = line; *p != '\0'; p++) {
- if (*p == '\'' || *p == '"') {
- quote = *p;
- for (p++; *p != quote && *p != '\0'; p++) {
- if (*p == '\\' && p[1] != '\0')
- p++;
- }
- if (*p == '\0')
- break;
- } else if (*p == '#') {
- *p = '\0';
- break;
- }
- }
-
- /* remove whitespace from end of line */
- len = strlen(line);
- while (IS_WHITE(line[len-1]))
- len--;
- line[len] = '\0';
-
- if (strncmp(line, "!include_try ", 13) == 0)
- continue;
- if (strncmp(line, "!include ", 9) == 0) {
- i_fatal_status(EX_CONFIG, "Error in config file %s: "
- "deliver doesn't support !include directive", path);
- }
-
- value = p = strchr(line, '=');
- if (value == NULL) {
- if (strchr(line, '{') != NULL) {
- if (strcmp(line, "protocol lda {") == 0)
- lda_section = TRUE;
- else if (strcmp(line, "plugin {") == 0)
- plugin_section = TRUE;
- else if (strcmp(line, "protocol pop3 {") == 0)
- pop3_section = TRUE;
- else if (strncmp(line, "namespace ", 10) == 0) {
- ns_section = TRUE;
- ns_idx++;
- line += 10;
- env_put(t_strdup_printf(
- "NAMESPACE_%u_TYPE=%s", ns_idx,
- t_strcut(line, ' ')));
- }
- sections++;
- }
- if (*line == '}') {
- sections--;
- lda_section = FALSE;
- plugin_section = FALSE;
- pop3_section = FALSE;
- if (ns_section) {
- ns_section = FALSE;
- if (ns_location)
- ns_location = FALSE;
- else {
- env_put(t_strdup_printf(
- "NAMESPACE_%u=", ns_idx));
- }
- if (ns_list)
- ns_list = FALSE;
- else {
- env_put(t_strdup_printf(
- "NAMESPACE_%u_LIST=1", ns_idx));
- }
- if (ns_subscriptions)
- ns_subscriptions = FALSE;
- else {
- env_put(t_strdup_printf(
- "NAMESPACE_%u_SUBSCRIPTIONS=1",
- ns_idx));
- }
- }
- }
- continue;
- }
-
- while (p > line && IS_WHITE(p[-1])) p--;
- key = t_strdup_until(line, p);
-
- if (sections > 0 && !lda_section && !plugin_section) {
- if (pop3_section) {
- if (strcmp(key, "pop3_uidl_format") != 0)
- continue;
- } else if (ns_section) {
- if (strcmp(key, "separator") == 0) {
- key = t_strdup_printf(
- "NAMESPACE_%u_SEP", ns_idx);
- } else if (strcmp(key, "location") == 0) {
- ns_location = TRUE;
- key = t_strdup_printf("NAMESPACE_%u",
- ns_idx);
- } else {
- if (strcmp(key, "list") == 0)
- ns_list = TRUE;
- if (strcmp(key, "subscriptions") == 0)
- ns_subscriptions = TRUE;
- key = t_strdup_printf("NAMESPACE_%u_%s",
- ns_idx, key);
- }
- } else {
- /* unwanted section */
- continue;
- }
- }
-
- do {
- value++;
- } while (IS_WHITE(*value));
-
- len = strlen(value);
- if (len > 0 &&
- ((*value == '"' && value[len-1] == '"') ||
- (*value == '\'' && value[len-1] == '\''))) {
- value = str_unescape(p_strndup(unsafe_data_stack_pool,
- value+1, len - 2));
- }
- ukey = t_str_ucase(key);
- if (setting_is_bool(key) && strcasecmp(value, "yes") != 0) {
- for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
- if (strcmp(default_yes_settings[i].name,
- key) == 0)
- default_yes_settings[i].set = FALSE;
- }
- env_remove(ukey);
- continue;
- }
-
- if (lda_section) {
- str = p_strconcat(plugin_pool, ukey, "=", value, NULL);
- array_append(&lda_envs, &str, 1);
- }
- if (!plugin_section) {
- env_put(t_strconcat(ukey, "=", value, NULL));
- } else {
- /* %variables need to be expanded.
- store these for later. */
- value = p_strconcat(plugin_pool,
- ukey, "=", value, NULL);
- array_append(&plugin_envs, &value, 1);
- }
- }
- i_stream_unref(&input);
-
- for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
- if (default_yes_settings[i].set) {
- key = default_yes_settings[i].name;
- env_put(t_strconcat(t_str_ucase(key), "=1", NULL));
- }
- }
-}
-
-static const struct var_expand_table *
-get_var_expand_table(const char *user, const char *home)
-{
- static struct var_expand_table static_tab[] = {
- { 'u', NULL, "user" },
- { 'n', NULL, "username" },
- { 'd', NULL, "domain" },
- { 's', NULL, "service" },
- { 'h', NULL, "home" },
- { 'l', NULL, "lip" },
- { 'r', NULL, "rip" },
- { 'p', NULL, "pid" },
- { 'i', NULL, "uid" },
- { '\0', NULL, NULL }
- };
- struct var_expand_table *tab;
-
- tab = t_malloc(sizeof(static_tab));
- memcpy(tab, static_tab, sizeof(static_tab));
-
- tab[0].value = user;
- tab[1].value = t_strcut(user, '@');
- tab[2].value = strchr(user, '@');
- if (tab[2].value != NULL) tab[2].value++;
- tab[3].value = "DELIVER";
- tab[4].value = home != NULL ? home :
- "/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
- tab[5].value = NULL;
- tab[6].value = NULL;
- tab[7].value = my_pid;
- tab[8].value = dec2str(geteuid());
-
- return tab;
-}
-
-static const char *
-expand_mail_env(const char *env, const struct var_expand_table *table)
-{
- string_t *str;
- const char *p;
-
- str = t_str_new(256);
-
- /* it's either type:data or just data */
- p = strchr(env, ':');
- if (p != NULL) {
- while (env != p) {
- str_append_c(str, *env);
- env++;
- }
-
- str_append_c(str, *env++);
- }
-
- if (env[0] == '~' && env[1] == '/') {
- /* expand home */
- env = t_strconcat("%h", env+1, NULL);
- }
-
- /* expand %vars */
- var_expand(str, env, table);
- return str_c(str);
-}
-
static const char *escape_local_part(const char *local_part)
{
const char *p;
static void open_logfile(const char *username)
{
- const char *prefix, *log_path, *stamp;
+ const char *prefix, *log_path;
prefix = t_strdup_printf("deliver(%s): ", username);
- log_path = home_expand(getenv("LOG_PATH"));
- if (log_path == NULL || *log_path == '\0') {
- const char *env = getenv("SYSLOG_FACILITY");
+ log_path = home_expand(deliver_set->log_path);
+ if (*log_path == '\0') {
int facility;
- if (env == NULL || !syslog_facility_find(env, &facility))
+ if (!syslog_facility_find(deliver_set->syslog_facility,
+ &facility))
facility = LOG_MAIL;
i_set_failure_prefix(prefix);
i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
i_set_failure_file(log_path, prefix);
}
- log_path = home_expand(getenv("INFO_LOG_PATH"));
- if (log_path != NULL && *log_path != '\0')
+ log_path = home_expand(deliver_set->info_log_path);
+ if (*log_path != '\0')
i_set_info_file(log_path);
- stamp = getenv("LOG_TIMESTAMP");
- if (stamp == NULL)
- stamp = DEFAULT_FAILURE_STAMP_FORMAT;
- i_set_failure_timestamp_format(stamp);
+ i_set_failure_timestamp_format(deliver_set->log_timestamp);
}
static void print_help(void)
if (home != NULL) env_put(home);
}
-static void expand_envs(const char *user)
-{
- const struct var_expand_table *table;
- const char *value, *const *envs, *home, *env_name;
- unsigned int i, count;
- string_t *str;
-
- home = getenv("HOME");
-
- str = t_str_new(256);
- table = get_var_expand_table(user, home);
- envs = array_get(&plugin_envs, &count);
- for (i = 0; i < count; i++) {
- str_truncate(str, 0);
- var_expand(str, envs[i], table);
- env_put(str_c(str));
- }
- /* add LDA envs again to make sure they override plugin settings */
- envs = array_get(&lda_envs, &count);
- for (i = 0; i < count; i++)
- env_put(envs[i]);
-
- /* get the table again in case plugin envs provided the home
- directory (yea, kludgy) */
- if (home == NULL)
- home = getenv("HOME");
- table = get_var_expand_table(user, home);
-
- value = getenv("MAIL_LOCATION");
- if (value != NULL)
- value = expand_mail_env(value, table);
- env_put(t_strconcat("MAIL=", value, NULL));
-
- for (i = 1;; i++) {
- env_name = t_strdup_printf("NAMESPACE_%u", i);
- value = getenv(env_name);
- if (value == NULL)
- break;
-
- value = expand_mail_env(value, table);
- env_put(t_strconcat(env_name, "=", value, NULL));
-
- env_name = t_strdup_printf("NAMESPACE_%u_PREFIX", i);
- value = getenv(env_name);
- if (value != NULL) {
- str_truncate(str, 0);
- var_expand(str, value, table);
- env_put(t_strconcat(env_name, "=", str_c(str), NULL));
- }
- }
-}
-
-static void putenv_extra_fields(const ARRAY_TYPE(const_string) *extra_fields)
+static void plugin_get_home(void)
{
- const char *const *fields;
- const char *key, *p;
+ const char *const *envs;
unsigned int i, count;
- fields = array_get(extra_fields, &count);
- for (i = 0; i < count; i++) {
- p = strchr(fields[i], '=');
- if (p == NULL)
- env_put(t_strconcat(fields[i], "=1", NULL));
- else {
- key = t_str_ucase(t_strdup_until(fields[i], p));
- env_put(t_strconcat(key, p, NULL));
+ /* kludgy. this should be removed some day, but for now don't break
+ existing setups that rely on it. */
+ if (array_is_created(&deliver_set->plugin_envs)) {
+ envs = array_get(&deliver_set->plugin_envs, &count);
+ for (i = 0; i < count; i++) {
+ if (strncmp(envs[i], "home=", 5) == 0) {
+ env_put(t_strconcat("HOME=", envs[i]+5, NULL));
+ break;
+ }
}
}
}
{
const char *config_path = DEFAULT_CONFIG_FILE;
const char *mailbox = "INBOX";
- const char *auth_socket;
- const char *home, *destaddr, *user, *value, *errstr, *path, *orig_user;
+ const char *home, *destaddr, *user, *error, *path, *orig_user;
ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT;
+ struct setting_parser_context *parser;
struct mail_user *mail_user, *raw_mail_user;
struct mail_namespace *raw_ns;
+ struct mail_namespace_settings raw_ns_set;
struct mail_storage *storage;
struct mailbox *box;
struct raw_mailbox *raw_box;
struct istream *input;
struct mailbox_transaction_context *t;
struct mailbox_header_lookup_ctx *headers_ctx;
+ struct mail_user_settings *user_set;
+ const struct mail_storage_settings *mail_set;
struct mail *mail;
uid_t process_euid;
bool stderr_rejection = FALSE;
#endif
deliver_set = i_new(struct deliver_settings, 1);
- deliver_set->mailbox_autocreate = TRUE;
+ mailbox_autocreate = TRUE;
destaddr = user = path = NULL;
for (i = 1; i < argc; i++) {
mailbox = str_c(str);
}
} else if (strcmp(argv[i], "-n") == 0) {
- deliver_set->mailbox_autocreate = FALSE;
+ mailbox_autocreate = FALSE;
} else if (strcmp(argv[i], "-s") == 0) {
- deliver_set->mailbox_autosubscribe = TRUE;
+ mailbox_autosubscribe = TRUE;
} else if (strcmp(argv[i], "-f") == 0) {
/* envelope sender address */
i++;
"destination user parameter (-d user) not given");
}
- T_BEGIN {
- config_file_init(config_path);
- } T_END;
- open_logfile(user);
+ mail_storage_init();
+ mail_storage_register_all();
+ mailbox_list_register_all();
- if (getenv("MAIL_DEBUG") != NULL)
- env_put("DEBUG=1");
+ parser = deliver_settings_read(config_path, &deliver_set, &user_set);
+ open_logfile(user);
- if (getenv("MAIL_PLUGINS") == NULL)
+ mail_set = mail_user_set_get_driver_settings(user_set, "MAIL");
+ if (deliver_set->mail_plugins == '\0')
modules = NULL;
else {
- const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
const char *version;
- if (plugin_dir == NULL)
- plugin_dir = MODULEDIR"/lda";
-
- version = getenv("VERSION_IGNORE") != NULL ?
- NULL : PACKAGE_VERSION;
- modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
+ version = deliver_set->version_ignore ? NULL : PACKAGE_VERSION;
+ modules = module_dir_load(deliver_set->mail_plugin_dir,
+ deliver_set->mail_plugins,
TRUE, version);
}
if (user_auth) {
- auth_socket = getenv("AUTH_SOCKET_PATH");
- if (auth_socket == NULL) {
- const char *base_dir = getenv("BASE_DIR");
- if (base_dir == NULL)
- base_dir = PKG_RUNDIR;
- auth_socket = t_strconcat(base_dir, "/auth-master",
- NULL);
- }
-
userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
orig_user = user;
- ret = auth_client_lookup_and_restrict(auth_socket,
+ ret = auth_client_lookup_and_restrict(deliver_set->auth_socket_path,
&user, process_euid,
userdb_pool,
&extra_fields);
if (strcmp(user, orig_user) != 0) {
/* auth lookup changed the user. */
- if (getenv("DEBUG") != NULL)
+ if (mail_set->mail_debug)
i_info("userdb changed username to %s", user);
i_set_failure_prefix(t_strdup_printf("deliver(%s): ",
user));
user = t_strdup(user);
}
- expand_envs(user);
if (userdb_pool != NULL) {
- putenv_extra_fields(&extra_fields);
+ settings_parse_set_expanded(parser, TRUE);
+ deliver_settings_add(parser, &extra_fields);
pool_unref(&userdb_pool);
}
- /* Fix namespaces with empty locations */
- for (i = 1;; i++) {
- value = getenv(t_strdup_printf("NAMESPACE_%u", i));
- if (value == NULL)
- break;
-
- if (*value == '\0') {
- env_put(t_strdup_printf("NAMESPACE_%u=%s", i,
- getenv("MAIL")));
- }
+ home = getenv("HOME");
+ if (home == NULL) {
+ plugin_get_home();
+ home = getenv("HOME");
}
/* If possible chdir to home directory, so that core file
could be written in case we crash. */
- home = getenv("HOME");
if (home != NULL) {
if (chdir(home) < 0) {
if (errno != ENOENT)
i_error("chdir(%s) failed: %m", home);
- else if (getenv("DEBUG") != NULL)
+ else if (mail_set->mail_debug)
i_info("Home dir not found: %s", home);
}
}
env_put(t_strconcat("USER=", user, NULL));
-
- value = getenv("UMASK");
- if (value == NULL || sscanf(value, "%i", &i) != 1 || i < 0)
- i = 0077;
- (void)umask(i);
-
- deliver_set->hostname = getenv("HOSTNAME");
- if (deliver_set->hostname == NULL)
- deliver_set->hostname = my_hostname;
- deliver_set->postmaster_address = getenv("POSTMASTER_ADDRESS");
- if (deliver_set->postmaster_address == NULL) {
- i_fatal_status(EX_CONFIG,
- "postmaster_address setting not given");
- }
- deliver_set->sendmail_path = getenv("SENDMAIL_PATH");
- if (deliver_set->sendmail_path == NULL)
- deliver_set->sendmail_path = DEFAULT_SENDMAIL_PATH;
- deliver_set->rejection_subject = getenv("REJECTION_SUBJECT");
- if (deliver_set->rejection_subject == NULL)
- deliver_set->rejection_subject = DEFAULT_MAIL_REJECTION_SUBJECT;
- deliver_set->rejection_reason = getenv("REJECTION_REASON");
- if (deliver_set->rejection_reason == NULL) {
- deliver_set->rejection_reason =
- DEFAULT_MAIL_REJECTION_HUMAN_REASON;
- }
- deliver_set->log_format = getenv("DELIVER_LOG_FORMAT");
- if (deliver_set->log_format == NULL)
- deliver_set->log_format = DEFAULT_LOG_FORMAT;
+ (void)umask(deliver_set->umask);
dict_drivers_register_builtin();
duplicate_init();
- mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
- mail_storage_init();
- mail_storage_register_all();
- mailbox_list_register_all();
+ mail_users_init(deliver_set->auth_socket_path, mail_set->mail_debug);
module_dir_init(modules);
- mail_user = mail_user_init(user);
+ mail_user = mail_user_alloc(user, user_set);
mail_user_set_home(mail_user, home);
- if (mail_namespaces_init(mail_user) < 0)
- i_fatal("Namespace initialization failed");
+ mail_user_set_vars(mail_user, geteuid(), "deliver", NULL, NULL);
+ if (mail_user_init(mail_user, &error) < 0)
+ i_fatal("Mail user initialization failed: %s", error);
+ if (mail_namespaces_init(mail_user, &error) < 0)
+ i_fatal("Namespace initialization failed: %s", error);
/* create a separate mail user for the internal namespace */
- raw_mail_user = mail_user_init(user);
- mail_user_set_home(raw_mail_user, NULL);
+ raw_mail_user = mail_user_alloc(user, user_set);
+ mail_user_set_home(raw_mail_user, "/");
+ if (mail_user_init(raw_mail_user, &error) < 0)
+ i_fatal("Raw user initialization failed: %s", error);
+
+ settings_parser_deinit(&parser);
+
+ memset(&raw_ns_set, 0, sizeof(raw_ns_set));
+ raw_ns_set.location = "/tmp";
+
raw_ns = mail_namespaces_init_empty(raw_mail_user);
raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
-
- if (mail_storage_create(raw_ns, "raw", "/tmp",
- MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
- FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
- i_fatal("Couldn't create internal raw storage: %s", errstr);
+ raw_ns->set = &raw_ns_set;
+ if (mail_storage_create(raw_ns, "raw", 0, &error) < 0)
+ i_fatal("Couldn't create internal raw storage: %s", error);
if (path == NULL) {
input = create_raw_stream(0, &mtime);
box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail",
}
if (error != MAIL_ERROR_NOSPACE ||
- getenv("QUOTA_FULL_TEMPFAIL") != NULL) {
+ deliver_set->quota_full_tempfail) {
/* Saving to INBOX should always work unless
we're over quota. If it didn't, it's probably a
configuration problem. */
#include "lib.h"
#include "mail-storage.h"
-
-#define DEFAULT_MAIL_REJECTION_SUBJECT \
- "Rejected: %s"
-#define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
- "Your message to <%t> was automatically rejected:%n%r"
-#define DEFAULT_LOG_FORMAT "msgid=%m: %$"
-
-struct deliver_settings {
- const char *hostname;
- const char *postmaster_address;
- const char *sendmail_path;
- const char *rejection_subject;
- const char *rejection_reason;
- const char *log_format;
- bool mailbox_autosubscribe;
- bool mailbox_autocreate;
-};
+#include "deliver-settings.h"
extern struct deliver_settings *deliver_set;
+extern bool mailbox_autosubscribe;
+extern bool mailbox_autocreate;
extern bool tried_default_save;
typedef int deliver_mail_func_t(struct mail_namespace *namespaces,
../login-common/liblogin-common.a \
../lib-imap/libimap.a \
../lib-auth/libauth.a \
+ ../lib-settings/libsettings.a \
../lib/liblib.a \
$(SSL_LIBS)
c) we allow insecure authentication
*/
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
- (secured || !disable_plaintext_auth ||
+ (secured || !login_settings->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
str_append_c(str, ' ');
str_append(str, "AUTH=");
master_user = *args + 7;
else if (strncmp(*args, "user=", 5) == 0) {
/* already handled in login-common */
- } else if (auth_debug) {
+ } else if (login_settings->auth_debug) {
i_info("Ignoring unknown passdb extra field: %s",
*args);
}
init_resp = IMAP_ARG_STR(&args[1]);
}
- if (!client->common.secured && ssl_required) {
- if (verbose_auth) {
+ if (!client->common.secured &&
+ strcmp(login_settings->ssl, "required") == 0) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"SSL required for authentication");
}
user = IMAP_ARG_STR(&args[0]);
pass = IMAP_ARG_STR(&args[1]);
- if (!client->common.secured && disable_plaintext_auth) {
- if (verbose_auth) {
+ if (!client->common.secured && login_settings->disable_plaintext_auth) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
{
const char *addr;
- if (!verbose_proctitle || !process_per_connection)
+ if (!login_settings->verbose_proctitle ||
+ !login_settings->login_process_per_connection)
return;
addr = net_ip2addr(&client->common.ip);
return t_strconcat(full ? capability_string : CAPABILITY_BANNER_STRING,
(ssl_initialized && !client->common.tls) ?
" STARTTLS" : "",
- disable_plaintext_auth && !client->common.secured ?
+ login_settings->disable_plaintext_auth &&
+ !client->common.secured ?
" LOGINDISABLED" : "", auths, NULL);
}
void client_destroy_oldest(void)
{
+ unsigned int max_connections = login_settings->login_max_connections;
struct client *client;
struct imap_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
unsigned int i, destroy_count;
greet = t_str_new(128);
str_append(greet, "* OK ");
str_printfa(greet, "[CAPABILITY %s] ", get_capability(client, FALSE));
- str_append(greet, greeting);
+ str_append(greet, login_settings->login_greeting);
client_send_line(client, str_c(greet));
client->greeting_sent = TRUE;
be using only Dovecot as their backend :) */
client_send_tagline(client, line + 2);
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
str = t_str_new(128);
str_printfa(str, "proxy(%s): Login failed to %s:%u",
client->common.virtual_user,
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
libs = \
$(STORAGE_LIBS) \
../lib-dict/libdict.a \
+ ../lib-settings/libsettings.a \
$(unused_objects)
imap_LDADD = \
imap-fetch.c \
imap-fetch-body.c \
imap-search.c \
+ imap-settings.c \
imap-sort.c \
imap-status.c \
imap-sync.c \
imap-expunge.h \
imap-fetch.h \
imap-search.h \
+ imap-settings.h \
imap-sort.h \
imap-status.h \
imap-sync.h
client_destroy(client, "Disconnected for inactivity");
}
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+ const struct imap_settings *set)
{
struct client *client;
struct mail_namespace *ns;
net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
+ client->set = set;
client->fd_in = fd_in;
client->fd_out = fd_out;
- client->input = i_stream_create_fd(fd_in, imap_max_line_length, FALSE);
+ client->input = i_stream_create_fd(fd_in,
+ set->imap_max_line_length, FALSE);
client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
o_stream_set_flush_callback(client->output, client_output, client);
&mail_storage_callbacks, client);
}
+ client->capability_string =
+ str_new(default_pool, sizeof(CAPABILITY_STRING)+32);
+ str_append(client->capability_string, *set->imap_capability != '\0' ?
+ set->imap_capability : CAPABILITY_STRING);
+
i_assert(my_client == NULL);
my_client = client;
tab[1].value = dec2str(client->output->offset);
str = t_str_new(128);
- var_expand(str, logout_format, tab);
+ var_expand(str, client->set->imap_logout_format, tab);
return str_c(str);
}
array_free(&client->search_saved_uidset);
if (array_is_created(&client->search_updates))
array_free(&client->search_updates);
+ str_free(&client->capability_string);
pool_unref(&client->command_pool);
i_free(client);
cmd->parser = client->free_parser;
client->free_parser = NULL;
} else {
- cmd->parser = imap_parser_create(client->input, client->output,
- imap_max_line_length);
+ cmd->parser =
+ imap_parser_create(client->input, client->output,
+ client->set->imap_max_line_length);
}
DLLIST_PREPEND(&client->command_queue, cmd);
struct ostream *output;
struct timeout *to_idle, *to_idle_output;
- struct mail_user *user;
+ const struct imap_settings *set;
+ enum client_workarounds workarounds;
+ string_t *capability_string;
+
+ struct mail_user *user;
struct mailbox *mailbox;
struct mailbox_keywords keywords;
unsigned int select_counter; /* increased when mailbox is changed */
/* Create new client with specified input/output handles. socket specifies
if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+ const struct imap_settings *set);
void client_destroy(struct client *client, const char *reason);
/* Disconnect client connection */
o_stream_unset_flush_callback(client->output);
ctx->save_parser = imap_parser_create(client->input, client->output,
- imap_max_line_length);
+ client->set->imap_max_line_length);
cmd->func = cmd_append_continue_parsing;
cmd->context = ctx;
bool cmd_capability(struct client_command_context *cmd)
{
- client_send_line(cmd->client,
- t_strconcat("* CAPABILITY ",
- str_c(capability_string), NULL));
+ client_send_line(cmd->client, t_strconcat(
+ "* CAPABILITY ", str_c(cmd->client->capability_string), NULL));
client_send_tagline(cmd, "OK Capability completed.");
return TRUE;
return TRUE;
}
- if ((client_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
+ if ((client->workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
*name != '\0' &&
name[strlen(name)-1] == mail_storage_get_hierarchy_sep(storage)) {
/* drop the extra trailing hierarchy separator */
bool cmd_id(struct client_command_context *cmd)
{
+ const struct imap_settings *set = cmd->client->set;
const struct imap_arg *args;
const char *value;
if (!cmd->client->id_logged) {
cmd->client->id_logged = TRUE;
- value = imap_id_args_get_log_reply(args, imap_id_log);
+ value = imap_id_args_get_log_reply(args, set->imap_id_log);
if (value != NULL)
i_info("ID sent: %s", value);
}
client_send_line(cmd->client, t_strdup_printf(
- "* ID %s", imap_id_reply_generate(imap_id_send)));
+ "* ID %s", imap_id_reply_generate(set->imap_id_send)));
client_send_tagline(cmd, "OK ID completed.");
return TRUE;
}
#include "ioloop.h"
#include "istream.h"
#include "ostream.h"
+#include "mail-storage-settings.h"
#include "commands.h"
#include "imap-sync.h"
#include <stdlib.h>
-#define DEFAULT_IDLE_CHECK_INTERVAL 30
/* Send some noice to client every few minutes to avoid NATs and stateful
firewalls from closing the connection */
#define KEEPALIVE_TIMEOUT (2*60)
{
struct client *client = cmd->client;
struct cmd_idle_context *ctx;
- const char *str;
- unsigned int interval;
ctx = p_new(cmd->pool, struct cmd_idle_context, 1);
ctx->cmd = cmd;
ctx->keepalive_to = timeout_add(KEEPALIVE_TIMEOUT * 1000,
keepalive_timeout, ctx);
- str = getenv("MAILBOX_IDLE_CHECK_INTERVAL");
- interval = str == NULL ? 0 : (unsigned int)strtoul(str, NULL, 10);
- if (interval == 0)
- interval = DEFAULT_IDLE_CHECK_INTERVAL;
-
if (client->mailbox != NULL) {
- mailbox_notify_changes(client->mailbox, interval,
+ const struct mail_storage_settings *set;
+
+ set = mailbox_get_settings(client->mailbox);
+ mailbox_notify_changes(client->mailbox,
+ set->mailbox_idle_check_interval,
idle_callback, ctx);
}
client_send_line(client, "+ idling");
mailbox += strlen(ns->prefix);
}
- if ((client_workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
+ if ((cmd->client->workarounds & WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
*mailbox != '\0' && mailbox[strlen(mailbox)-1] ==
mail_storage_get_hierarchy_sep(ns->storage)) {
/* verify the validity without the trailing '/' */
#ifndef COMMON_H
#define COMMON_H
-#include "lib.h"
-#include "client.h"
-
/* Disconnect client after idling this many milliseconds */
#define CLIENT_IDLE_TIMEOUT_MSECS (60*30*1000)
/* Disconnect client when it sends too many bad commands in a row */
#define CLIENT_MAX_BAD_COMMANDS 20
-/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
- break large message sets to multiple commands, so we're pretty liberal
- by default. */
-#define DEFAULT_IMAP_MAX_LINE_LENGTH 65536
-
enum client_workarounds {
WORKAROUND_DELAY_NEWMAIL = 0x01,
WORKAROUND_NETSCAPE_EOH = 0x04,
WORKAROUND_TB_EXTRA_MAILBOX_SEP = 0x08
};
-extern struct ioloop *ioloop;
-extern unsigned int imap_max_line_length;
-extern enum client_workarounds client_workarounds;
-extern const char *logout_format;
-extern const char *imap_id_send, *imap_id_log;
+#include "lib.h"
+#include "client.h"
+#include "imap-settings.h"
-extern string_t *capability_string;
+extern struct ioloop *ioloop;
extern void (*hook_client_created)(struct client **client);
i_stream_seek(ctx->cur_input, old_offset);
if (!ctx->cur_have_eoh &&
- (client_workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
+ (ctx->client->workarounds & WORKAROUND_NETSCAPE_EOH) != 0) {
/* Netscape 4.x doesn't like if end of headers line is
missing. */
msg_size.virtual_size += 2;
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "imap-settings.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct imap_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct imap_settings, field), defines }
+
+static struct setting_define imap_setting_defines[] = {
+ DEF(SET_BOOL, mail_debug),
+ DEF(SET_BOOL, shutdown_clients),
+ DEF(SET_BOOL, verbose_proctitle),
+
+ DEF(SET_STR, mail_plugins),
+ DEF(SET_STR, mail_plugin_dir),
+ DEF(SET_STR_VARS, mail_log_prefix),
+
+ DEF(SET_UINT, imap_max_line_length),
+ DEF(SET_STR, imap_capability),
+ DEF(SET_STR, imap_client_workarounds),
+ DEF(SET_STR, imap_logout_format),
+ DEF(SET_STR, imap_id_send),
+ DEF(SET_STR, imap_id_log),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct imap_settings imap_default_settings = {
+ MEMBER(mail_debug) FALSE,
+ MEMBER(shutdown_clients) FALSE,
+ MEMBER(verbose_proctitle) FALSE,
+
+ MEMBER(mail_plugins) "",
+ MEMBER(mail_plugin_dir) MODULEDIR"/imap",
+ MEMBER(mail_log_prefix) "%Us(%u): ",
+
+ /* RFC-2683 recommends at least 8000 bytes. Some clients however don't
+ break large message sets to multiple commands, so we're pretty
+ liberal by default. */
+ MEMBER(imap_max_line_length) 65536,
+ MEMBER(imap_capability) "",
+ MEMBER(imap_client_workarounds) "outlook-idle",
+ MEMBER(imap_logout_format) "bytes=%i/%o",
+ MEMBER(imap_id_send) "",
+ MEMBER(imap_id_log) ""
+};
+
+struct setting_parser_info imap_setting_parser_info = {
+ MEMBER(defines) imap_setting_defines,
+ MEMBER(defaults) &imap_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct imap_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+void imap_settings_read(const struct imap_settings **set_r,
+ const struct mail_user_settings **user_set_r)
+{
+ static const struct setting_parser_info *roots[] = {
+ &imap_setting_parser_info,
+ &mail_user_setting_parser_info
+ };
+ struct setting_parser_context *parser;
+ void **sets;
+
+ if (settings_pool == NULL)
+ settings_pool = pool_alloconly_create("imap settings", 2048);
+ else
+ p_clear(settings_pool);
+
+ mail_storage_namespace_defines_init(settings_pool);
+
+ parser = settings_parser_init_list(settings_pool,
+ roots, N_ELEMENTS(roots),
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+ settings_parse_set_expanded(parser, TRUE);
+ if (settings_parse_environ(parser) < 0) {
+ i_fatal("Error reading configuration: %s",
+ settings_parser_get_error(parser));
+ }
+
+ sets = settings_parser_get_list(parser);
+ *set_r = sets[0];
+ *user_set_r = sets[1];
+ settings_parser_deinit(&parser);
+}
--- /dev/null
+#ifndef IMAP_SETTINGS_H
+#define IMAP_SETTINGS_H
+
+struct mail_user_settings;
+
+struct imap_settings {
+ bool mail_debug;
+ bool shutdown_clients;
+ bool verbose_proctitle;
+
+ const char *mail_plugins;
+ const char *mail_plugin_dir;
+ const char *mail_log_prefix;
+
+ /* imap: */
+ unsigned int imap_max_line_length;
+ const char *imap_capability;
+ const char *imap_client_workarounds;
+ const char *imap_logout_format;
+ const char *imap_id_send;
+ const char *imap_id_log;
+};
+
+void imap_settings_read(const struct imap_settings **set_r,
+ const struct mail_user_settings **user_set_r);
+
+#endif
get_common_sync_flags(client, &flags, &imap_flags);
client->sync_counter++;
- no_newmail = (client_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
+ no_newmail = (client->workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
(imap_flags & IMAP_SYNC_FLAG_SAFE) == 0;
if (no_newmail) {
/* expunges might break the client just as badly as new mail
};
struct ioloop *ioloop;
-unsigned int imap_max_line_length;
-enum client_workarounds client_workarounds = 0;
-const char *logout_format;
-const char *imap_id_send, *imap_id_log;
static struct io *log_io = NULL;
static struct module *modules = NULL;
void (*hook_client_created)(struct client **client) = NULL;
-string_t *capability_string;
-
static void sig_die(int signo, void *context ATTR_UNUSED)
{
/* warn about being killed because of some signal, except SIGINT (^C)
io_loop_stop(ioloop);
}
-static void parse_workarounds(void)
+static enum client_workarounds
+parse_workarounds(const struct imap_settings *set)
{
+ enum client_workarounds client_workarounds = 0;
struct client_workaround_list *list;
- const char *env, *const *str;
-
- env = getenv("IMAP_CLIENT_WORKAROUNDS");
- if (env == NULL)
- return;
+ const char *const *str;
- for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
+ str = t_strsplit_spaces(set->imap_client_workarounds, " ,");
+ for (; *str != NULL; str++) {
list = client_workaround_list;
for (; list->name != NULL; list++) {
if (strcasecmp(*str, list->name) == 0) {
if (list->name == NULL)
i_fatal("Unknown client workaround: %s", *str);
}
+
+ return client_workarounds;
}
static void open_logfile(void)
i_set_failure_timestamp_format(getenv("LOGSTAMP"));
}
-static void drop_privileges(void)
+static void main_preinit(const struct imap_settings **set_r,
+ const struct mail_user_settings **user_set_r)
{
const char *version;
/* Log file or syslog opening probably requires roots */
open_logfile();
- /* Load the plugins before chrooting. Their init() is called later. */
- if (getenv("MAIL_PLUGINS") != NULL) {
- const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
+ mail_storage_init();
+ mail_storage_register_all();
+ mailbox_list_register_all();
- if (plugin_dir == NULL)
- plugin_dir = MODULEDIR"/imap";
- modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
- TRUE, version);
- }
+ /* read settings after registering storages so they can have their
+ own setting definitions too */
+ imap_settings_read(set_r, user_set_r);
+
+ /* Load the plugins before chrooting. Their init() is called later. */
+ modules = *(*set_r)->mail_plugins == '\0' ? NULL :
+ module_dir_load((*set_r)->mail_plugin_dir,
+ (*set_r)->mail_plugins, TRUE, version);
restrict_access_by_env(!IS_STANDALONE());
}
-static void main_init(void)
+static void main_init(const struct imap_settings *set,
+ const struct mail_user_settings *user_set)
{
struct client *client;
struct ostream *output;
struct mail_user *user;
- const char *username, *home, *str, *tag;
+ const char *username, *home, *str, *tag, *error;
+ bool dump_capability;
lib_signals_init();
lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
lib_signals_ignore(SIGPIPE, TRUE);
lib_signals_ignore(SIGALRM, FALSE);
+ dump_capability = getenv("DUMP_CAPABILITY") != NULL;
+
username = getenv("USER");
if (username == NULL) {
if (IS_STANDALONE())
}
home = getenv("HOME");
- if (getenv("DEBUG") != NULL) {
+ if (set->mail_debug) {
+ home = getenv("HOME");
i_info("Effective uid=%s, gid=%s, home=%s",
dec2str(geteuid()), dec2str(getegid()),
home != NULL ? home : "(none)");
}
- if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
+ if (set->shutdown_clients && !dump_capability) {
/* If master dies, the log fd gets closed and we'll quit */
log_io = io_add(STDERR_FILENO, IO_ERROR,
log_error_callback, NULL);
}
- capability_string = str_new(default_pool, sizeof(CAPABILITY_STRING)+32);
- str_append(capability_string, CAPABILITY_STRING);
-
dict_drivers_register_builtin();
mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
- mail_storage_init();
- mail_storage_register_all();
- mailbox_list_register_all();
clients_init();
commands_init();
module_dir_init(modules);
- if (getenv("DUMP_CAPABILITY") != NULL) {
- printf("%s\n", str_c(capability_string));
+ user = mail_user_alloc(username, user_set);
+ mail_user_set_home(user, home);
+ if (mail_user_init(user, &error) < 0)
+ i_fatal("Mail user initialization failed: %s", error);
+ if (mail_namespaces_init(user, &error) < 0)
+ i_fatal("Namespace initialization failed: %s", error);
+ client = client_create(0, 1, user, set);
+ client->workarounds = parse_workarounds(set);
+
+ if (dump_capability) {
+ printf("%s\n", str_c(client->capability_string));
exit(0);
}
- str = getenv("IMAP_CAPABILITY");
- if (str != NULL && *str != '\0') {
- /* Overrides all capabilities */
- str_truncate(capability_string, 0);
- str_append(capability_string, str);
- }
-
- str = getenv("IMAP_MAX_LINE_LENGTH");
- imap_max_line_length = str != NULL ?
- (unsigned int)strtoul(str, NULL, 10) :
- DEFAULT_IMAP_MAX_LINE_LENGTH;
-
- logout_format = getenv("IMAP_LOGOUT_FORMAT");
- if (logout_format == NULL)
- logout_format = "bytes=%i/%o";
-
- imap_id_send = getenv("IMAP_ID_SEND");
- imap_id_log = getenv("IMAP_ID_LOG");
-
- parse_workarounds();
-
- user = mail_user_init(username);
- mail_user_set_home(user, home);
- if (mail_namespaces_init(user) < 0)
- i_fatal("Namespace initialization failed");
- client = client_create(0, 1, user);
-
output = client->output;
o_stream_ref(output);
o_stream_cork(output);
if (tag == NULL) {
client_send_line(client, t_strconcat(
"* PREAUTH [CAPABILITY ",
- str_c(capability_string), "] "
+ str_c(client->capability_string), "] "
"Logged in as ", user->username, NULL));
} else {
client_send_line(client, t_strconcat(
tag, " OK [CAPABILITY ",
- str_c(capability_string), "] Logged in", NULL));
+ str_c(client->capability_string), "] Logged in", NULL));
}
str = getenv("CLIENT_INPUT");
if (str != NULL) T_BEGIN {
mail_users_deinit();
dict_drivers_unregister_builtin();
- str_free(&capability_string);
-
lib_signals_deinit();
closelog();
}
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
{
+ const struct imap_settings *set;
+ const struct mail_user_settings *user_set;
+
#ifdef DEBUG
if (!IS_STANDALONE() && getenv("GDB") == NULL)
fd_debug_verify_leaks(3, 1024);
/* NOTE: we start rooted, so keep the code minimal until
restrict_access_by_env() is called */
lib_init();
- drop_privileges();
+ main_preinit(&set, &user_set);
process_title_init(argv, envp);
ioloop = io_loop_create();
/* fake that we're running, so we know if client was destroyed
while initializing */
io_loop_set_running(ioloop);
- main_init();
+ main_init(set, user_set);
if (io_loop_is_running(ioloop))
io_loop_run(ioloop);
main_deinit();
-I$(top_srcdir)/src/lib
libsettings_a_SOURCES = \
- settings.c
+ settings.c \
+ settings-parser.c
headers = \
- settings.h
+ settings.h \
+ settings-parser.h
if INSTALL_HEADERS
pkginc_libdir=$(pkgincludedir)/src/lib-settings
--- /dev/null
+/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hash.h"
+#include "network.h"
+#include "istream.h"
+#include "str.h"
+#include "strescape.h"
+#include "var-expand.h"
+#include "settings-parser.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
+
+struct setting_link {
+ struct setting_link *parent;
+ const struct setting_parser_info *info;
+
+ ARRAY_TYPE(void_array) *array;
+ void *set_struct;
+};
+
+struct setting_parser_context {
+ pool_t set_pool, parser_pool;
+ enum settings_parser_flags flags;
+ bool str_vars_are_expanded;
+
+ struct setting_link *roots;
+ unsigned int root_count;
+ struct hash_table *links;
+ string_t *save_input_str;
+
+ unsigned int linenum;
+ const char *error;
+ const struct setting_parser_info *prev_info;
+};
+
+static const struct setting_parser_info strlist_info = {
+ MEMBER(defines) NULL,
+ MEMBER(defaults) NULL,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) 0
+};
+
+struct setting_parser_context *
+settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
+ enum settings_parser_flags flags)
+{
+ return settings_parser_init_list(set_pool, &root, 1, flags);
+}
+
+static void
+setting_parser_copy_defaults(const struct setting_parser_info *info,
+ pool_t pool, void *dest)
+{
+ const struct setting_define *def;
+ const char *p, **strp;
+
+ if (info->defaults == NULL)
+ return;
+
+ memcpy(dest, 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);
+ p = strchr(*strp, ':');
+ if (p != NULL)
+ *strp = p_strdup_until(pool, *strp, p);
+ break;
+ }
+ case SET_STR_VARS: {
+ /* insert the unexpanded-character */
+ strp = STRUCT_MEMBER_P(dest, def->offset);
+ if (*strp != NULL) {
+ *strp = p_strconcat(pool,
+ SETTING_STRVAR_UNEXPANDED,
+ *strp, NULL);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+struct setting_parser_context *
+settings_parser_init_list(pool_t set_pool,
+ const struct setting_parser_info *const *roots,
+ unsigned int count, enum settings_parser_flags flags)
+{
+ struct setting_parser_context *ctx;
+ unsigned int i;
+ pool_t parser_pool;
+
+ i_assert(count > 0);
+
+ parser_pool = pool_alloconly_create("settings parser", 8192);
+ ctx = p_new(parser_pool, struct setting_parser_context, 1);
+ ctx->set_pool = set_pool;
+ ctx->parser_pool = parser_pool;
+ ctx->flags = flags;
+
+ ctx->root_count = count;
+ ctx->roots = p_new(ctx->set_pool, struct setting_link, count);
+ for (i = 0; i < count; i++) {
+ ctx->roots[i].info = roots[i];
+ ctx->roots[i].set_struct =
+ p_malloc(ctx->set_pool, roots[i]->struct_size);
+ setting_parser_copy_defaults(roots[i], ctx->set_pool,
+ ctx->roots[i].set_struct);
+ }
+
+ 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;
+}
+
+void settings_parser_deinit(struct setting_parser_context **_ctx)
+{
+ struct setting_parser_context *ctx = *_ctx;
+
+ *_ctx = NULL;
+ hash_table_destroy(&ctx->links);
+ pool_unref(&ctx->set_pool);
+ pool_unref(&ctx->parser_pool);
+}
+
+void *settings_parser_get(struct setting_parser_context *ctx)
+{
+ i_assert(ctx->root_count == 1);
+
+ return ctx->roots[0].set_struct;
+}
+
+void **settings_parser_get_list(struct setting_parser_context *ctx)
+{
+ unsigned int i;
+ void **sets;
+
+ sets = t_new(void *, ctx->root_count);
+ for (i = 0; i < ctx->root_count; i++)
+ sets[i] = ctx->roots[i].set_struct;
+ return sets;
+}
+
+const char *settings_parser_get_error(struct setting_parser_context *ctx)
+{
+ return ctx->error;
+}
+
+static const struct setting_define *
+setting_define_find(const struct setting_parser_info *info, const char *key)
+{
+ const struct setting_define *list;
+
+ for (list = info->defines; list->key != NULL; list++) {
+ if (strcmp(list->key, key) == 0 && list->type != SET_INTERNAL)
+ return list;
+ }
+ return NULL;
+}
+
+static int
+get_bool(struct setting_parser_context *ctx, const char *value, bool *result_r)
+{
+ /* FIXME: eventually we'd want to support only yes/no */
+ if (strcasecmp(value, "yes") == 0 ||
+ strcasecmp(value, "y") == 0 || strcmp(value, "1") == 0)
+ *result_r = TRUE;
+ else if (strcasecmp(value, "no") == 0)
+ *result_r = FALSE;
+ else {
+ ctx->error = p_strconcat(ctx->parser_pool, "Invalid boolean: ",
+ value, NULL);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+get_uint(struct setting_parser_context *ctx, const char *value,
+ unsigned int *result_r)
+{
+ int num;
+
+ /* use %i so we can handle eg. 0600 as octal value with umasks */
+ if (!sscanf(value, "%i", &num) || num < 0) {
+ ctx->error = p_strconcat(ctx->parser_pool, "Invalid number: ",
+ value, NULL);
+ return -1;
+ }
+ *result_r = num;
+ return 0;
+}
+
+static int get_enum(struct setting_parser_context *ctx, const char *value,
+ char **result_r, const char *allowed_values)
+{
+ const char *p;
+
+ while (allowed_values != NULL) {
+ p = strchr(allowed_values, ':');
+ if (p == NULL) {
+ if (strcmp(allowed_values, value) == 0)
+ break;
+
+ ctx->error = p_strconcat(ctx->parser_pool,
+ "Invalid value: ",
+ value, NULL);
+ return -1;
+ }
+
+ if (strncmp(allowed_values, value, p - allowed_values) == 0 &&
+ value[p - allowed_values] == '\0')
+ break;
+
+ allowed_values = p + 1;
+ }
+
+ *result_r = p_strdup(ctx->set_pool, value);
+ return 0;
+}
+
+static int
+get_deflist(struct setting_parser_context *ctx, struct setting_link *parent,
+ const struct setting_parser_info *info,
+ const char *key, const char *value, ARRAY_TYPE(void_array) *result)
+{
+ struct setting_link *link;
+ const char *const *list;
+ char *full_key;
+
+ i_assert(info->defines != NULL || info == &strlist_info);
+
+ if (!array_is_created(result))
+ p_array_init(result, ctx->set_pool, 5);
+
+ list = t_strsplit(value, "\t ");
+ for (; *list != NULL; list++) {
+ if (**list == '\0')
+ continue;
+
+ full_key = p_strconcat(ctx->parser_pool, key,
+ SETTINGS_SEPARATOR_S, *list, NULL);
+ if (hash_table_lookup(ctx->links, full_key) != NULL) {
+ ctx->error = p_strconcat(ctx->parser_pool, full_key,
+ " already exists", NULL);
+ return -1;
+ }
+
+ link = p_new(ctx->parser_pool, struct setting_link, 1);
+ link->parent = parent;
+ link->info = info;
+ link->array = result;
+ hash_table_insert(ctx->links, full_key, link);
+ }
+ return 0;
+}
+
+static int
+settings_parse(struct setting_parser_context *ctx, struct setting_link *link,
+ const struct setting_define *def,
+ const char *key, const char *value)
+{
+ void *ptr, *ptr2;
+
+ ctx->prev_info = link->info;
+
+ 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 (link->info->parent_offset != (size_t)-1 &&
+ link->parent != NULL) {
+ ptr = STRUCT_MEMBER_P(link->set_struct,
+ link->info->parent_offset);
+ *((void **)ptr) = link->parent->set_struct;
+ }
+ }
+
+ ptr = STRUCT_MEMBER_P(link->set_struct, def->offset);
+ switch (def->type) {
+ case SET_INTERNAL:
+ i_unreached();
+ case SET_BOOL:
+ return get_bool(ctx, value, (bool *)ptr);
+ case SET_UINT:
+ return get_uint(ctx, value, (unsigned int *)ptr);
+ case SET_STR:
+ *((char **)ptr) = p_strdup(ctx->set_pool, value);
+ return 0;
+ case SET_STR_VARS:
+ *((char **)ptr) = p_strconcat(ctx->set_pool,
+ ctx->str_vars_are_expanded ?
+ SETTING_STRVAR_EXPANDED :
+ SETTING_STRVAR_UNEXPANDED,
+ value, NULL);
+ return 0;
+ case SET_ENUM:
+ /* get the available values from default string */
+ i_assert(link->info->defaults != NULL);
+ ptr2 = STRUCT_MEMBER_P(link->info->defaults, def->offset);
+ return get_enum(ctx, value, (char **)ptr, *(const char **)ptr2);
+ case SET_DEFLIST:
+ ctx->prev_info = def->list_info;
+ return get_deflist(ctx, link, def->list_info,
+ key, value, (ARRAY_TYPE(void_array) *)ptr);
+ case SET_STRLIST: {
+ ctx->prev_info = &strlist_info;
+ return get_deflist(ctx, link, &strlist_info,
+ key, value, (ARRAY_TYPE(void_array) *)ptr);
+ }
+ }
+
+ i_unreached();
+ return -1;
+}
+
+static int settings_parse_keyvalue(struct setting_parser_context *ctx,
+ const char *key, const char *value)
+{
+ const struct setting_define *def = NULL;
+ unsigned int i;
+ int ret = 1;
+
+ /* try to find from roots */
+ for (i = 0; i < ctx->root_count; i++) {
+ def = setting_define_find(ctx->roots[i].info, key);
+ if (def != NULL)
+ break;
+ }
+ if (def != NULL) {
+ if (settings_parse(ctx, &ctx->roots[i], def, key, value) < 0)
+ ret = -1;
+ } else {
+ /* try to find from links */
+ const char *end = strrchr(key, SETTINGS_SEPARATOR);
+ struct setting_link *link;
+
+ link = end == NULL ? NULL :
+ hash_table_lookup(ctx->links, t_strdup_until(key, end));
+ if (link == NULL)
+ def = NULL;
+ else if (link->info == &strlist_info) {
+ void *vkey, *vvalue;
+
+ vkey = p_strdup(ctx->set_pool, end + 1);
+ vvalue = p_strdup(ctx->set_pool, value);
+ array_append(link->array, &vkey, 1);
+ array_append(link->array, &vvalue, 1);
+ return 1;
+ } else {
+ def = setting_define_find(link->info, end + 1);
+ }
+ if (def != NULL) {
+ if (settings_parse(ctx, link, def, key, value) < 0)
+ ret = -1;
+ } else {
+ ctx->error = p_strconcat(ctx->parser_pool,
+ "Unknown setting: ", key, NULL);
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+int settings_parse_line(struct setting_parser_context *ctx, const char *line)
+{
+ const char *key, *value;
+ int ret;
+
+ ctx->error = NULL;
+ ctx->prev_info = NULL;
+
+ key = line;
+ value = strchr(line, '=');
+ if (value == NULL) {
+ ctx->error = "Missing '='";
+ return -1;
+ }
+
+ if (key == value) {
+ ctx->error = "Missing key name ('=' at the beginning of line)";
+ return -1;
+ }
+
+ T_BEGIN {
+ key = t_strdup_until(key, value);
+ ret = settings_parse_keyvalue(ctx, key, value + 1);
+ } T_END;
+ return ret;
+}
+
+const struct setting_parser_info *
+settings_parse_get_prev_info(struct setting_parser_context *ctx)
+{
+ return ctx->prev_info;
+}
+
+int settings_parse_stream(struct setting_parser_context *ctx,
+ struct istream *input)
+{
+ const char *line;
+ string_t *full_line;
+ size_t len;
+ int ret = 1;
+
+ full_line = str_new(default_pool, 512);
+ while ((line = i_stream_next_line(input)) != NULL) {
+ if (*line == '\0') {
+ /* empty line finishes it */
+ ret = 0;
+ break;
+ }
+
+ ctx->linenum++;
+ while (IS_WHITE(*line == ' '))
+ line++;
+ if (*line == '\0' || *line == '#')
+ continue;
+
+ len = strlen(line);
+ while (len > 0 && IS_WHITE(line[len-1]))
+ len--;
+ if (line[len] == '\\') {
+ /* line continues */
+ str_append_n(full_line, line, len - 1);
+ } else {
+ /* full line */
+ if (str_len(full_line) > 0) {
+ str_append_n(full_line, line, len);
+ line = str_c(full_line);
+ }
+
+ ret = settings_parse_line(ctx, line);
+ if (ret == 0 &&
+ (ctx->flags &
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS) == 0)
+ ret = -1;
+
+ if (ret < 0) {
+ ctx->error = p_strdup_printf(ctx->parser_pool,
+ "Line %u: %s",
+ ctx->linenum,
+ ctx->error);
+ ret = -1;
+ break;
+ }
+ str_truncate(full_line, 0);
+ }
+ }
+ str_free(&full_line);
+ return ret;
+}
+
+int settings_parse_stream_read(struct setting_parser_context *ctx,
+ struct istream *input)
+{
+ const unsigned char *data;
+ size_t size;
+ int ret;
+
+ while ((ret = i_stream_read(input)) > 0) {
+ if (ctx->save_input_str != NULL) {
+ data = i_stream_get_data(input, &size);
+ str_append_n(ctx->save_input_str, data, size);
+ }
+ if ((ret = settings_parse_stream(ctx, input)) < 0)
+ return -1;
+ if (ret == 0) {
+ /* empty line read */
+ return 0;
+ }
+ }
+
+ switch (ret) {
+ case -1:
+ if (input->stream_errno != 0) {
+ ctx->error = p_strdup_printf(ctx->parser_pool,
+ "read() failed: %m");
+ } else {
+ ctx->error = "input is missing end-of-settings line";
+ }
+ break;
+ case -2:
+ ctx->error = p_strdup_printf(ctx->parser_pool,
+ "Line %u: line too long",
+ ctx->linenum);
+ break;
+ case 0:
+ /* blocks */
+ return 1;
+ default:
+ i_unreached();
+ }
+ return -1;
+}
+
+int settings_parse_file(struct setting_parser_context *ctx,
+ const char *path, size_t max_line_length)
+{
+ struct istream *input;
+ int fd, ret;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ctx->error = p_strdup_printf(ctx->parser_pool,
+ "open(%s) failed: %m", path);
+ return -1;
+ }
+
+ input = i_stream_create_fd(fd, max_line_length, TRUE);
+ ret = settings_parse_stream_read(ctx, input);
+ i_stream_unref(&input);
+
+ return ret;
+}
+
+int settings_parse_environ(struct setting_parser_context *ctx)
+{
+ extern char **environ;
+ const char *key, *value;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; environ[i] != NULL && ret == 0; i++) {
+ value = strchr(environ[i], '=');
+ if (value != NULL) T_BEGIN {
+ key = t_strdup_until(environ[i], value++);
+ key = t_str_lcase(key);
+ if (settings_parse_keyvalue(ctx, key, value) < 0) {
+ ctx->error = p_strdup_printf(ctx->parser_pool,
+ "Invalid setting %s: %s",
+ key, ctx->error);
+ ret = -1;
+ }
+ } T_END;
+ }
+ return ret;
+}
+
+int settings_parse_exec(struct setting_parser_context *ctx,
+ const char *bin_path, const char *config_path,
+ const char *service)
+{
+ struct istream *input;
+ pid_t pid;
+ int ret, fd[2], status;
+
+ if (pipe(fd) < 0) {
+ i_error("pipe() failed: %m");
+ return -1;
+ }
+
+ pid = fork();
+ if (pid == (pid_t)-1) {
+ i_error("fork() failed: %m");
+ (void)close(fd[0]);
+ (void)close(fd[1]);
+ return -1;
+ }
+ if (pid == 0) {
+ /* child */
+ static const char *argv[] = {
+ NULL,
+ "-c", NULL,
+ "-s", NULL,
+ NULL
+ };
+ argv[0] = bin_path;
+ argv[2] = config_path;
+ argv[4] = service;
+ (void)close(fd[0]);
+ if (dup2(fd[1], STDOUT_FILENO) < 0)
+ i_fatal("dup2() failed: %m");
+
+ execv(argv[0], (void *)argv);
+ i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", bin_path);
+ return -1;
+ }
+ (void)close(fd[1]);
+
+ input = i_stream_create_fd(fd[0], (size_t)-1, TRUE);
+ ret = settings_parse_stream_read(ctx, input);
+ i_stream_destroy(&input);
+
+ if (waitpid(pid, &status, 0) < 0) {
+ i_error("waitpid() failed: %m");
+ ret = -1;
+ } else if (status != 0) {
+ i_error("%s returned failure: %d", bin_path, status);
+ ret = -1;
+ }
+ return ret;
+}
+
+void settings_parse_set_expanded(struct setting_parser_context *ctx,
+ bool is_expanded)
+{
+ ctx->str_vars_are_expanded = is_expanded;
+}
+
+static void
+settings_var_expand_info(const struct setting_parser_info *info,
+ pool_t pool, void *set,
+ const struct var_expand_table *table, string_t *str)
+{
+ const struct setting_define *def;
+ void *value, *const *children;
+ unsigned int i, count;
+
+ for (def = info->defines; def->key != NULL; def++) {
+ value = PTR_OFFSET(set, def->offset);
+ switch (def->type) {
+ case SET_STR_VARS: {
+ const char **val = value;
+
+ if (*val == NULL)
+ break;
+
+ if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
+ str_truncate(str, 0);
+ var_expand(str, *val + 1, table);
+ *val = p_strdup(pool, str_c(str));
+ } else {
+ i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
+ *val += 1;
+ }
+ break;
+ }
+ case SET_DEFLIST: {
+ const ARRAY_TYPE(void_array) *val = value;
+
+ if (!array_is_created(val))
+ break;
+
+ children = array_get(val, &count);
+ for (i = 0; i < count; i++) {
+ settings_var_expand_info(def->list_info,
+ pool, children[i],
+ table, str);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+void settings_var_expand(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table)
+{
+ string_t *str;
+
+ T_BEGIN {
+ str = t_str_new(256);
+ settings_var_expand_info(info, pool, set, table, str);
+ } T_END;
+}
+
+bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
+ char var_key, const char *long_var_key,
+ const char **key_r, const char **value_r)
+{
+ const struct setting_define *def;
+ const void *value;
+ void *const *children;
+ unsigned int i, count;
+
+ for (def = info->defines; def->key != NULL; def++) {
+ value = CONST_PTR_OFFSET(set, def->offset);
+ switch (def->type) {
+ case SET_STR_VARS: {
+ const char *const *val = value;
+
+ if (*val == NULL)
+ break;
+
+ if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
+ if (var_has_key(*val + 1, var_key,
+ long_var_key)) {
+ *key_r = def->key;
+ *value_r = *val + 1;
+ return TRUE;
+ }
+ } else {
+ i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
+ }
+ break;
+ }
+ case SET_DEFLIST: {
+ const ARRAY_TYPE(void_array) *val = value;
+
+ if (!array_is_created(val))
+ break;
+
+ children = array_get(val, &count);
+ for (i = 0; i < count; i++) {
+ if (settings_vars_have_key(def->list_info,
+ children[i], var_key,
+ long_var_key,
+ key_r, value_r))
+ return TRUE;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return FALSE;
+}
+
+void *settings_dup(const struct setting_parser_info *info,
+ const void *set, pool_t pool)
+{
+ const struct setting_define *def;
+ const void *src;
+ void *dest_set, *dest, *const *children;
+ unsigned int i, count;
+
+ dest_set = p_malloc(pool, info->struct_size);
+ memcpy(dest_set, set, info->struct_size);
+ for (def = info->defines; def->key != NULL; def++) {
+ src = CONST_PTR_OFFSET(set, def->offset);
+ dest = PTR_OFFSET(dest_set, def->offset);
+
+ switch (def->type) {
+ case SET_INTERNAL:
+ case SET_BOOL:
+ case SET_UINT:
+ break;
+ case SET_STR_VARS:
+ case SET_STR:
+ case SET_ENUM: {
+ const char *const *src_str = src;
+ const char **dest_str = dest;
+
+ *dest_str = p_strdup(pool, *src_str);
+ break;
+ }
+ case SET_DEFLIST: {
+ const ARRAY_TYPE(void_array) *src_arr = src;
+ ARRAY_TYPE(void_array) *dest_arr = dest;
+ void *child_set;
+
+ if (!array_is_created(src_arr))
+ break;
+
+ children = array_get(src_arr, &count);
+ p_array_init(dest_arr, pool, count);
+ for (i = 0; i < count; i++) {
+ child_set = settings_dup(def->list_info,
+ children[i], pool);
+ array_append(dest_arr, &child_set, 1);
+ }
+ break;
+ }
+ case SET_STRLIST: {
+ const ARRAY_TYPE(const_string) *src_arr = src;
+ ARRAY_TYPE(const_string) *dest_arr = dest;
+ const char *const *strings, *dup;
+
+ if (!array_is_created(src_arr))
+ break;
+
+ strings = array_get(src_arr, &count);
+ p_array_init(dest_arr, pool, count);
+ for (i = 0; i < count; i += 2)
+ dup = p_strdup(pool, strings[i]);
+ break;
+ }
+ }
+ }
+ return dest_set;
+}
+
+void settings_parse_save_input(struct setting_parser_context *ctx,
+ string_t *dest)
+{
+ ctx->save_input_str = dest;
+}
+
+static void
+info_update_real(pool_t pool, struct setting_parser_info *parent,
+ const struct dynamic_settings_parser *parsers)
+{
+ /* @UNSAFE */
+ ARRAY_DEFINE(defines, struct setting_define);
+ ARRAY_TYPE(dynamic_settings_parser) dynamic_parsers;
+ struct dynamic_settings_parser new_parser;
+ const struct setting_define *cur_defines;
+ struct setting_define *new_defines, new_define;
+ void *parent_defaults;
+ unsigned int i, j;
+ size_t offset, new_struct_size;
+
+ t_array_init(&defines, 128);
+ /* add existing defines */
+ for (j = 0; parent->defines[j].key != NULL; j++)
+ array_append(&defines, &parent->defines[j], 1);
+ new_struct_size = parent->struct_size;
+
+ /* add new dynamic defines */
+ for (i = 0; parsers[i].name != NULL; i++) {
+ i_assert(parsers[i].info->parent == parent);
+ cur_defines = parsers[i].info->defines;
+ for (j = 0; cur_defines[j].key != NULL; j++) {
+ new_define = cur_defines[j];
+ new_define.offset += new_struct_size;
+ array_append(&defines, &new_define, 1);
+ }
+ new_struct_size += MEM_ALIGN(parsers[i].info->struct_size);
+ }
+ new_defines = p_new(pool, struct setting_define,
+ array_count(&defines) + 1);
+ memcpy(new_defines, array_idx(&defines, 0),
+ sizeof(*parent->defines) * array_count(&defines));
+ parent->defines = new_defines;
+
+ /* update defaults */
+ parent_defaults = p_malloc(pool, new_struct_size);
+ memcpy(parent_defaults, parent->defaults, parent->struct_size);
+ offset = parent->struct_size;
+ for (i = 0; parsers[i].name != NULL; i++) {
+ memcpy(PTR_OFFSET(parent_defaults, offset),
+ parsers[i].info->defaults, parsers[i].info->struct_size);
+ offset += MEM_ALIGN(parsers[i].info->struct_size);
+ }
+ parent->defaults = parent_defaults;
+
+ /* update dynamic parsers list */
+ t_array_init(&dynamic_parsers, 32);
+ if (parent->dynamic_parsers != NULL) {
+ for (i = 0; parent->dynamic_parsers[i].name != NULL; i++) {
+ array_append(&dynamic_parsers,
+ &parent->dynamic_parsers[i], 1);
+ }
+ }
+ offset = parent->struct_size;
+ for (i = 0; parsers[i].name != NULL; i++) {
+ new_parser = parsers[i];
+ new_parser.name = p_strdup(pool, new_parser.name);
+ new_parser.struct_offset = offset;
+ array_append(&dynamic_parsers, &new_parser, 1);
+ offset += MEM_ALIGN(parsers[i].info->struct_size);
+ }
+ parent->dynamic_parsers =
+ p_new(pool, struct dynamic_settings_parser,
+ array_count(&dynamic_parsers) + 1);
+ memcpy(parent->dynamic_parsers, array_idx(&dynamic_parsers, 0),
+ sizeof(*parent->dynamic_parsers) *
+ array_count(&dynamic_parsers));
+ parent->struct_size = new_struct_size;
+}
+
+void
+settings_parser_info_update(pool_t pool, struct setting_parser_info *parent,
+ const struct dynamic_settings_parser *parsers)
+{
+ T_BEGIN {
+ info_update_real(pool, parent, parsers);
+ } T_END;
+}
+
+const void *settings_find_dynamic(struct setting_parser_info *info,
+ const void *base_set, const char *name)
+{
+ unsigned int i;
+
+ if (info->dynamic_parsers == NULL)
+ return NULL;
+
+ for (i = 0; info->dynamic_parsers[i].name != NULL; i++) {
+ if (strcmp(info->dynamic_parsers[i].name, name) == 0) {
+ return CONST_PTR_OFFSET(base_set,
+ info->dynamic_parsers[i].struct_offset);
+ }
+ }
+ return NULL;
+}
--- /dev/null
+#ifndef SETTINGS_PARSER_H
+#define SETTINGS_PARSER_H
+
+struct var_expand_table;
+
+#define SETTINGS_SEPARATOR '/'
+#define SETTINGS_SEPARATOR_S "/"
+
+/* STR_VARS pointer begins with either of these initially. Before actually
+ using the variables all variables in all unexpanded strings need to be
+ expanded. Afterwards the string pointers should be increased to skip
+ the initial '1' so it'll be easy to use them. */
+#define SETTING_STRVAR_UNEXPANDED "0"
+#define SETTING_STRVAR_EXPANDED "1"
+
+enum setting_type {
+ SET_INTERNAL, /* don't set this variable */
+ SET_BOOL,
+ SET_UINT,
+ SET_STR,
+ SET_STR_VARS, /* string with %variables */
+ SET_ENUM,
+ SET_DEFLIST, /* of type array_t */
+ SET_STRLIST /* of type ARRAY_TYPE(const_string) */
+};
+
+#define SETTING_DEFINE_LIST_END { 0, NULL, 0, NULL }
+
+struct setting_define {
+ enum setting_type type;
+ const char *key;
+
+ size_t offset;
+ const struct setting_parser_info *list_info;
+};
+
+#define SETTING_DEFINE_STRUCT_BOOL(name, struct_name) \
+ { SET_BOOL + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ ((struct struct_name *)0)->name, bool), \
+ #name, offsetof(struct struct_name, name), NULL }
+#define SETTING_DEFINE_STRUCT_UINT(name, struct_name) \
+ { SET_UINT + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ ((struct struct_name *)0)->name, unsigned int), \
+ #name, offsetof(struct struct_name, name), NULL }
+#define SETTING_DEFINE_STRUCT_STR(name, struct_name) \
+ { SET_STR + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ ((struct struct_name *)0)->name, const char *), \
+ #name, offsetof(struct struct_name, name), NULL }
+
+struct setting_parser_info {
+ const struct setting_define *defines;
+ const void *defaults;
+
+ struct setting_parser_info *parent;
+ struct dynamic_settings_parser *dynamic_parsers;
+
+ size_t parent_offset;
+ size_t type_offset;
+ size_t struct_size;
+};
+ARRAY_DEFINE_TYPE(setting_parser_info, struct setting_parser_info);
+
+/* name=NULL-terminated list of parsers. These follow the static settings.
+ After this list follows the actual settings. */
+struct dynamic_settings_parser {
+ const char *name;
+ const struct setting_parser_info *info;
+ size_t struct_offset;
+};
+ARRAY_DEFINE_TYPE(dynamic_settings_parser, struct dynamic_settings_parser);
+
+enum settings_parser_flags {
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS = 0x01
+};
+
+struct setting_parser_context;
+
+struct setting_parser_context *
+settings_parser_init(pool_t set_pool, const struct setting_parser_info *root,
+ enum settings_parser_flags flags);
+struct setting_parser_context *
+settings_parser_init_list(pool_t set_pool,
+ const struct setting_parser_info *const *roots,
+ unsigned int count, enum settings_parser_flags flags);
+void settings_parser_deinit(struct setting_parser_context **ctx);
+
+/* Return pointer to root setting structure. */
+void *settings_parser_get(struct setting_parser_context *ctx);
+/* If there are multiple roots, return list to all of their settings. */
+void **settings_parser_get_list(struct setting_parser_context *ctx);
+
+/* Return the last error. */
+const char *settings_parser_get_error(struct setting_parser_context *ctx);
+/* Return the parser info used for the previously parsed line. */
+const struct setting_parser_info *
+settings_parse_get_prev_info(struct setting_parser_context *ctx);
+/* Save all parsed input to given string. */
+void settings_parse_save_input(struct setting_parser_context *ctx,
+ string_t *dest);
+
+/* Parse a single line. Returns 1 if OK, 0 if key is unknown, -1 if error. */
+int settings_parse_line(struct setting_parser_context *ctx, const char *line);
+/* Parse data already read in input stream. */
+int settings_parse_stream(struct setting_parser_context *ctx,
+ struct istream *input);
+/* Read data from input stream and parser it. returns -1 = error,
+ 0 = eof/stream error, 1 = not finished yet (stream is non-blocking) */
+int settings_parse_stream_read(struct setting_parser_context *ctx,
+ struct istream *input);
+/* Open file and parse it. */
+int settings_parse_file(struct setting_parser_context *ctx,
+ const char *path, size_t max_line_length);
+int settings_parse_environ(struct setting_parser_context *ctx);
+/* Execute the given binary and wait for it to return the configuration. */
+int settings_parse_exec(struct setting_parser_context *ctx,
+ const char *bin_path, const char *config_path,
+ const char *service);
+
+/* While parsing values, specifies if STR_VARS strings are already expanded. */
+void settings_parse_set_expanded(struct setting_parser_context *ctx,
+ bool is_expanded);
+/* Expand all unexpanded variables using the given table. Update the string
+ pointers so that they can be used without skipping over the '1'. */
+void settings_var_expand(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table);
+/* Go through all the settings and return the first one that has an unexpanded
+ setting containing the given %key. */
+bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
+ char var_key, const char *long_var_key,
+ const char **key_r, const char **value_r);
+/* Duplicate the entire settings structure. */
+void *settings_dup(const struct setting_parser_info *info,
+ const void *set, pool_t pool);
+/* parsers is a name=NULL -terminated list. The parsers are appended as
+ dynamic_settings_list structures to parent. The new structures are allocated
+ from the given pool. */
+void
+settings_parser_info_update(pool_t pool, struct setting_parser_info *parent,
+ const struct dynamic_settings_parser *parsers);
+
+/* Return pointer to beginning of settings for given name, or NULL if there is
+ no such registered name. */
+const void *settings_find_dynamic(struct setting_parser_info *info,
+ const void *base_set, const char *name);
+
+#endif
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/lib-auth \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
mail-search.c \
mail-search-build.c \
mail-storage.c \
+ mail-storage-settings.c \
mail-user.c \
mailbox-list.c \
mailbox-search-result.c \
mail-thread.h \
mail-storage.h \
mail-storage-private.h \
+ mail-storage-settings.h \
mail-user.h \
mailbox-list.h \
mailbox-list-private.h \
const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
*layout_r = "fs";
storage, &storage->list_module_ctx);
/* finish list init after we've overridden vfuncs */
- mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags));
+ mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
return 0;
}
MEMBER(mailbox_is_file) FALSE,
{
+ NULL,
cydir_class_init,
cydir_class_deinit,
cydir_alloc,
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
dbox-index.c \
dbox-mail.c \
dbox-save.c \
+ dbox-settings.c \
dbox-sync.c \
dbox-sync-file.c \
dbox-sync-rebuild.c \
dbox-file.h \
dbox-file-maildir.h \
dbox-index.h \
+ dbox-settings.h \
dbox-storage.h \
dbox-sync.h
struct dbox_file *
dbox_file_init(struct dbox_mailbox *mbox, unsigned int file_id)
{
+ const struct dbox_settings *set = mbox->storage->set;
struct dbox_file *file;
unsigned int count;
bool maildir;
}
count = array_count(&mbox->open_files);
- if (count > mbox->max_open_files)
- dbox_close_open_files(mbox, count - mbox->max_open_files);
+ if (count > set->dbox_max_open_files)
+ dbox_close_open_files(mbox, count - set->dbox_max_open_files);
file = i_new(struct dbox_file, 1);
file->refcount = 1;
if (file->file_id != 0) {
files = array_get(&file->mbox->open_files, &count);
- if (!file->deleted && count <= file->mbox->max_open_files) {
+ if (!file->deleted &&
+ count <= file->mbox->storage->set->dbox_max_open_files) {
/* we can leave this file open for now */
return;
}
bool dbox_file_can_append(struct dbox_file *file, uoff_t mail_size)
{
+ const struct dbox_settings *set = file->mbox->storage->set;
+
if (file->nonappendable)
return FALSE;
return FALSE;
}
- if (file->append_offset < file->mbox->rotate_min_size ||
+ if (file->append_offset < set->dbox_rotate_min_size ||
file->append_offset == file->file_header_size)
return TRUE;
- if (file->append_offset + mail_size >= file->mbox->rotate_size)
+ if (file->append_offset + mail_size >= set->dbox_rotate_size)
return FALSE;
- return file->create_time >= day_begin_stamp(file->mbox->rotate_days);
+ return file->create_time >= day_begin_stamp(set->dbox_rotate_days);
}
static int dbox_file_parse_header(struct dbox_file *file, const char *line)
--- /dev/null
+/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "dbox-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct dbox_settings, name), NULL }
+
+static struct setting_define dbox_setting_defines[] = {
+ DEF(SET_UINT, dbox_rotate_size),
+ DEF(SET_UINT, dbox_rotate_min_size),
+ DEF(SET_UINT, dbox_rotate_days),
+ DEF(SET_UINT, dbox_max_open_files),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct dbox_settings dbox_default_settings = {
+ MEMBER(dbox_rotate_size) 2048*1024,
+ MEMBER(dbox_rotate_min_size) 16*1024,
+ MEMBER(dbox_rotate_days) 0,
+ MEMBER(dbox_max_open_files) 64
+};
+
+static struct setting_parser_info dbox_setting_parser_info = {
+ MEMBER(defines) dbox_setting_defines,
+ MEMBER(defaults) &dbox_default_settings,
+
+ MEMBER(parent) &mail_user_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct dbox_settings)
+};
+
+const struct setting_parser_info *dbox_get_setting_parser_info(void)
+{
+ return &dbox_setting_parser_info;
+}
--- /dev/null
+#ifndef DBOX_SETTINGS_H
+#define DBOX_SETTINGS_H
+
+struct dbox_settings {
+ unsigned int dbox_rotate_size;
+ unsigned int dbox_rotate_min_size;
+ unsigned int dbox_rotate_days;
+ unsigned int dbox_max_open_files;
+};
+
+const struct setting_parser_info *dbox_get_setting_parser_info(void);
+
+#endif
const char **layout_r, const char **alt_dir_r,
const char **error_r)
{
- bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
*layout_r = "fs";
return -1;
}
+ storage->set = mail_storage_get_driver_settings(_storage);
+
if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
return -1;
storage->list_module_ctx.super = _storage->list->v;
storage, &storage->list_module_ctx);
/* finish list init after we've overridden vfuncs */
- mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags));
+ mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
return 0;
}
struct mail_storage *_storage = &storage->storage;
struct dbox_mailbox *mbox;
struct mail_index *index;
- const char *path, *value;
+ const char *path;
pool_t pool;
path = mailbox_list_get_path(_storage->list, name,
mbox->storage = storage;
mbox->last_interactive_change = ioloop_time;
- value = getenv("DBOX_ROTATE_SIZE");
- if (value != NULL)
- mbox->rotate_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
- else
- mbox->rotate_size = DBOX_DEFAULT_ROTATE_SIZE;
- mbox->rotate_size = 0; /* FIXME: currently anything else doesn't work */
- value = getenv("DBOX_ROTATE_MIN_SIZE");
- if (value != NULL)
- mbox->rotate_min_size = (uoff_t)strtoul(value, NULL, 10) * 1024;
- else
- mbox->rotate_min_size = DBOX_DEFAULT_ROTATE_MIN_SIZE;
- if (mbox->rotate_min_size > mbox->rotate_size)
- mbox->rotate_min_size = mbox->rotate_size;
- value = getenv("DBOX_ROTATE_DAYS");
- if (value != NULL)
- mbox->rotate_days = (unsigned int)strtoul(value, NULL, 10);
- else
- mbox->rotate_days = DBOX_DEFAULT_ROTATE_DAYS;
-
- value = getenv("DBOX_MAX_OPEN_FILES");
- if (value != NULL)
- mbox->max_open_files = (unsigned int)strtoul(value, NULL, 10);
- else
- mbox->max_open_files = DBOX_DEFAULT_MAX_OPEN_FILES;
- i_array_init(&mbox->open_files, I_MIN(mbox->max_open_files, 128));
+ i_array_init(&mbox->open_files,
+ I_MIN(storage->set->dbox_max_open_files, 128));
mbox->dbox_ext_id =
mail_index_ext_register(index, "dbox", 0,
MEMBER(mailbox_is_file) FALSE,
{
+ dbox_get_setting_parser_info,
dbox_class_init,
dbox_class_deinit,
dbox_alloc,
#include "index-storage.h"
#include "mailbox-list-private.h"
+#include "dbox-settings.h"
#define DBOX_STORAGE_NAME "dbox"
#define DBOX_SUBSCRIPTION_FILE_NAME ".dbox-subscriptions"
/* Delete temp files having ctime older than this. */
#define DBOX_TMP_DELETE_SECS (36*60*60)
-/* Default rotation settings */
-#define DBOX_DEFAULT_ROTATE_SIZE (2*1024*1024)
-#define DBOX_DEFAULT_ROTATE_MIN_SIZE (1024*16)
-#define DBOX_DEFAULT_ROTATE_DAYS 0
-#define DBOX_DEFAULT_MAX_OPEN_FILES 64
-
/* Flag specifies if the message should be in primary or alternative storage */
#define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
struct dbox_storage {
struct mail_storage storage;
union mailbox_list_module_context list_module_ctx;
+ const struct dbox_settings *set;
const char *alt_dir;
};
/* set while rebuilding indexes with converted maildir files */
struct maildir_keywords_sync_ctx *maildir_sync_keywords;
- uoff_t rotate_size, rotate_min_size;
- unsigned int rotate_days;
-
ARRAY_DEFINE(open_files, struct dbox_file *);
- unsigned int max_open_files;
const char *path, *alt_path;
};
void index_mail_cache_add_idx(struct index_mail *mail, unsigned int field_idx,
const void *data, size_t data_size)
{
+ const struct mail_storage_settings *set = mail->ibox->box.storage->set;
const struct mail_index_header *hdr;
- if (mail->ibox->mail_cache_min_mail_count > 0) {
+ if (set->mail_cache_min_mail_count > 0) {
/* First check if we've configured caching not to be used with
low enough message count. */
hdr = mail_index_get_header(mail->ibox->view);
- if (hdr->messages_count < mail->ibox->mail_cache_min_mail_count)
+ if (hdr->messages_count < set->mail_cache_min_mail_count)
return;
}
#include <unistd.h>
#include <sys/stat.h>
-#define DEFAULT_CACHE_FIELDS ""
-#define DEFAULT_NEVER_CACHE_FIELDS "imap.envelope"
-
/* How many seconds to keep index opened for reuse after it's been closed */
#define INDEX_CACHE_TIMEOUT 10
/* How many closed indexes to keep */
static void index_cache_register_defaults(struct index_mailbox *ibox)
{
+ const struct mail_storage_settings *set = ibox->box.storage->set;
static bool initialized = FALSE;
struct mail_cache *cache = ibox->cache;
- const char *cache_env, *never_env, *env;
if (!initialized) {
initialized = TRUE;
- cache_env = getenv("MAIL_CACHE_FIELDS");
- if (cache_env == NULL)
- cache_env = DEFAULT_CACHE_FIELDS;
- never_env = getenv("MAIL_NEVER_CACHE_FIELDS");
- if (never_env == NULL)
- never_env = DEFAULT_NEVER_CACHE_FIELDS;
-
- set_cache_decisions("mail_cache_fields", cache_env,
+ set_cache_decisions("mail_cache_fields",
+ set->mail_cache_fields,
MAIL_CACHE_DECISION_TEMP);
- set_cache_decisions("mail_never_cache_fields", never_env,
+ set_cache_decisions("mail_never_cache_fields",
+ set->mail_never_cache_fields,
MAIL_CACHE_DECISION_NO |
MAIL_CACHE_DECISION_FORCED);
-
- env = getenv("MAIL_CACHE_MIN_MAIL_COUNT");
- if (env != NULL)
- ibox->mail_cache_min_mail_count = atoi(env);
}
ibox->cache_fields = i_malloc(sizeof(global_cache_fields));
i_assert(!ibox->box.opened);
+ index_flags = mail_storage_settings_to_index_flags(storage->set);
if (!ibox->move_to_memory)
index_flags |= MAIL_INDEX_OPEN_FLAG_CREATE;
-#ifndef MMAP_CONFLICTS_WRITE
- if ((storage->flags & MAIL_STORAGE_FLAG_MMAP_DISABLE) != 0)
-#endif
- index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
- if ((storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
- index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
- if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX) != 0)
- index_flags |= MAIL_INDEX_OPEN_FLAG_NFS_FLUSH;
- if ((storage->flags & MAIL_STORAGE_FLAG_FSYNC_DISABLE) != 0) {
- index_flags |= MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE;
- ibox->fsync_disable = TRUE;
- }
ret = mail_index_open(ibox->index, index_flags, storage->lock_method);
if (ret <= 0 || ibox->move_to_memory) {
return FALSE;
}
}
- if (i > ibox->box.storage->keyword_max_len) {
+ if (i > ibox->box.storage->set->mail_max_keyword_length) {
*error_r = "Keyword length too long";
return FALSE;
}
const ARRAY_TYPE(keywords) *keyword_names;
struct mail_cache_field *cache_fields;
- unsigned int mail_cache_min_mail_count;
ARRAY_TYPE(seq_range) recent_flags;
uint32_t recent_flags_prev_uid;
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
maildir-keywords.c \
maildir-mail.c \
maildir-save.c \
+ maildir-settings.c \
maildir-storage.c \
maildir-sync.c \
maildir-sync-index.c \
maildir-filename.h \
maildir-keywords.h \
maildir-storage.h \
+ maildir-settings.h \
maildir-sync.h \
maildir-uidlist.h
do_save_mail_vsize(path, ctx);
}
- if ((mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
+ if (mbox->storage->storage.set->mail_nfs_storage)
ret = nfs_safe_link(path, str_c(ctx->dest_path), FALSE);
else
ret = link(path, str_c(ctx->dest_path));
memset(&do_ctx, 0, sizeof(do_ctx));
do_ctx.dest_path = str_new(default_pool, 512);
- if (dest_mbox->storage->copy_preserve_filename && src_mbox != NULL) {
+ if (dest_mbox->storage->set->maildir_copy_preserve_filename &&
+ src_mbox != NULL) {
enum maildir_uidlist_rec_flag src_flags;
const char *src_fname;
struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
int ret;
- if (mbox->storage->copy_with_hardlinks &&
+ if (mbox->storage->set->maildir_copy_with_hardlinks &&
maildir_compatible_file_modes(&mbox->ibox.box, mail->box)) {
T_BEGIN {
ret = maildir_copy_hardlink(t, mail, flags,
strcase_hash, (hash_cmp_callback_t *)strcasecmp);
mk->dotlock_settings.use_excl_lock =
- (box->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
+ box->storage->set->dotlock_use_excl;
mk->dotlock_settings.nfs_flush =
- (box->storage->flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
+ box->storage->set->mail_nfs_storage;
mk->dotlock_settings.timeout = KEYWORDS_LOCK_STALE_TIMEOUT + 2;
mk->dotlock_settings.stale_timeout = KEYWORDS_LOCK_STALE_TIMEOUT;
mk->dotlock_settings.temp_prefix =
we rely on stat()'s timestamp and don't bother handling ESTALE
errors. */
- if ((mk->storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+ if (mk->storage->set->mail_nfs_storage) {
/* file is updated only by replacing it, no need to flush
attribute cache */
nfs_flush_file_handle_cache(mk->path);
if (ctx->fd == -1)
ctx->failed = TRUE;
else {
- ctx->input = (ctx->mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
- i_stream_create_crlf(input) :
- i_stream_create_lf(input);
-
+ if (ctx->mbox->storage->storage.set->mail_save_crlf)
+ ctx->input = i_stream_create_crlf(input);
+ else
+ ctx->input = i_stream_create_lf(input);
maildir_save_add(t, fname, _ctx->flags, _ctx->keywords,
_ctx->dest_mail);
}
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "maildir-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct maildir_settings, name), NULL }
+
+static struct setting_define maildir_setting_defines[] = {
+ DEF(SET_BOOL, maildir_stat_dirs),
+ DEF(SET_BOOL, maildir_copy_with_hardlinks),
+ DEF(SET_BOOL, maildir_copy_preserve_filename),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct maildir_settings maildir_default_settings = {
+ MEMBER(maildir_stat_dirs) FALSE,
+ MEMBER(maildir_copy_with_hardlinks) TRUE,
+ MEMBER(maildir_copy_preserve_filename) FALSE
+};
+
+static struct setting_parser_info maildir_setting_parser_info = {
+ MEMBER(defines) maildir_setting_defines,
+ MEMBER(defaults) &maildir_default_settings,
+
+ MEMBER(parent) &mail_user_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct maildir_settings)
+};
+
+const struct setting_parser_info *maildir_get_setting_parser_info(void)
+{
+ return &maildir_setting_parser_info;
+}
+
--- /dev/null
+#ifndef MAILDIR_SETTINGS_H
+#define MAILDIR_SETTINGS_H
+
+struct maildir_settings {
+ bool maildir_stat_dirs;
+ bool maildir_copy_with_hardlinks;
+ bool maildir_copy_preserve_filename;
+};
+
+const struct setting_parser_info *maildir_get_setting_parser_info(void);
+
+#endif
const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- enum mail_storage_flags flags = storage->flags;
struct mail_user *user = storage->ns->user;
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
const char *path, *home;
*layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME;
list_set->maildir_name = "";
if (data == NULL || *data == '\0') {
- if ((flags & MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
+ if ((storage->flags &
+ MAIL_STORAGE_FLAG_NO_AUTODETECTION) != 0) {
*error_r = "Root mail directory not given";
return -1;
}
if (mailbox_list_alloc(layout, &list, error_r) < 0)
return -1;
+ storage->set = mail_storage_get_driver_settings(_storage);
+
_storage->list = list;
storage->list_module_ctx.super = list->v;
if (strcmp(layout, MAILDIR_PLUSPLUS_DRIVER_NAME) == 0) {
storage, &storage->list_module_ctx);
/* finish list init after we've overridden vfuncs */
- mailbox_list_init(list, _storage->ns, &list_set,
- mail_storage_get_list_flags(flags));
-
- storage->copy_with_hardlinks =
- getenv("MAILDIR_COPY_WITH_HARDLINKS") != NULL;
- storage->copy_preserve_filename =
- getenv("MAILDIR_COPY_PRESERVE_FILENAME") != NULL;
- storage->stat_dirs = getenv("MAILDIR_STAT_DIRS") != NULL;
+ mailbox_list_init(list, _storage->ns, &list_set, 0);
storage->temp_prefix = mailbox_list_get_temp_prefix(list);
if (list_set.control_dir == NULL) {
return 0;
}
-static bool maildir_autodetect(const char *data, enum mail_storage_flags flags)
+static bool maildir_autodetect(const struct mail_namespace *ns)
{
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = ns->mail_set->mail_debug;
struct stat st;
const char *path;
- data = t_strcut(data, ':');
-
- path = t_strconcat(data, "/cur", NULL);
+ path = t_strconcat(t_strcut(ns->set->location, ':'), "/cur", NULL);
if (stat(path, &st) < 0) {
if (debug)
i_info("maildir autodetect: stat(%s) failed: %m", path);
const char *root_dir;
char sep;
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 &&
+ if (list->mail_set->mail_full_filesystem_access &&
(*name == '/' || *name == '~'))
return NULL;
/* Check files beginning with .nfs always because they may be
temporary files created by the kernel */
- if (storage->stat_dirs || *fname == '\0' ||
+ if (storage->set->maildir_stat_dirs || *fname == '\0' ||
strncmp(fname, ".nfs", 4) == 0) {
const char *path;
struct stat st;
MEMBER(mailbox_is_file) FALSE,
{
+ maildir_get_setting_parser_info,
maildir_class_init,
maildir_class_deinit,
maildir_alloc,
#ifndef MAILDIR_STORAGE_H
#define MAILDIR_STORAGE_H
+#include "maildir-settings.h"
+
#define MAILDIR_STORAGE_NAME "maildir"
#define MAILDIR_SUBSCRIPTION_FILE_NAME "subscriptions"
#define MAILDIR_INDEX_PREFIX "dovecot.index"
struct mail_storage storage;
union mailbox_list_module_context list_module_ctx;
+ const struct maildir_settings *set;
const char *temp_prefix;
uint32_t maildir_list_ext_id;
- unsigned int copy_with_hardlinks:1;
- unsigned int copy_preserve_filename:1;
unsigned int save_size_in_filename:1;
- unsigned int stat_dirs:1;
};
struct maildir_mailbox {
uidlist->dotlock_settings.use_io_notify = TRUE;
uidlist->dotlock_settings.use_excl_lock =
- (box->storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
+ box->storage->set->dotlock_use_excl;
uidlist->dotlock_settings.nfs_flush =
- (box->storage->flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
+ box->storage->set->mail_nfs_storage;
uidlist->dotlock_settings.timeout =
MAILDIR_UIDLIST_LOCK_STALE_TIMEOUT + 2;
uidlist->dotlock_settings.stale_timeout =
{
struct mail_storage *storage = uidlist->ibox->box.storage;
- if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+ if (storage->set->mail_nfs_storage) {
nfs_flush_file_handle_cache(uidlist->path);
nfs_flush_attr_cache_unlocked(uidlist->path);
}
return 1;
}
- if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+ if (storage->set->mail_nfs_storage) {
/* NFS: either the file hasn't been changed, or it has already
been deleted and the inodes just happen to be the same.
check if the fd is still valid. */
if (ctx->failed)
return -1;
-
for (p = filename; *p != '\0'; p++) {
if (*p == 13 || *p == 10) {
i_warning("Maildir %s: Ignoring a file with #0x%x: %s",
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-imap \
-I$(top_srcdir)/src/lib-index \
mbox-mail.c \
mbox-md5.c \
mbox-save.c \
+ mbox-settings.c \
mbox-sync-parse.c \
mbox-sync-rewrite.c \
mbox-sync-update.c \
mbox-file.h \
mbox-lock.h \
mbox-md5.h \
+ mbox-settings.h \
mbox-storage.h \
mbox-sync-private.h
/* 0.1 .. 0.2msec */
#define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
-/* lock methods to use in wanted order */
-#define DEFAULT_READ_LOCK_METHODS "fcntl"
-#define DEFAULT_WRITE_LOCK_METHODS "dotlock fcntl"
-/* lock timeout */
-#define MBOX_DEFAULT_LOCK_TIMEOUT (5*60)
-/* assume stale dotlock if mbox file hasn't changed for n seconds */
-#define DEFAULT_DOTLOCK_CHANGE_TIMEOUT (120)
-
enum mbox_lock_type {
MBOX_LOCK_DOTLOCK,
MBOX_LOCK_DOTLOCK_TRY,
{ 0, NULL, NULL }
};
-static bool lock_settings_initialized = FALSE;
-static enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
-static enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
-static int lock_timeout, dotlock_change_timeout;
-
static int mbox_lock_list(struct mbox_lock_context *ctx, int lock_type,
time_t max_wait_time, int idx);
static int mbox_unlock_files(struct mbox_lock_context *ctx);
locks[dest] = (enum mbox_lock_type)-1;
}
-static void mbox_init_lock_settings(void)
+static void mbox_init_lock_settings(struct mbox_storage *storage)
{
- const char *str;
+ enum mbox_lock_type read_locks[MBOX_LOCK_COUNT+1];
+ enum mbox_lock_type write_locks[MBOX_LOCK_COUNT+1];
int r, w;
- str = getenv("MBOX_READ_LOCKS");
- if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
- mbox_read_lock_methods(str, "MBOX_READ_LOCKS", read_locks);
-
- str = getenv("MBOX_WRITE_LOCKS");
- if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
- mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
+ mbox_read_lock_methods(storage->set->mbox_read_locks,
+ "mbox_read_locks", read_locks);
+ mbox_read_lock_methods(storage->set->mbox_write_locks,
+ "mbox_write_locks", write_locks);
/* check that read/write list orders match. write_locks must contain
at least read_locks and possibly more. */
"(and possibly more)");
}
- str = getenv("MBOX_LOCK_TIMEOUT");
- lock_timeout = str == NULL ? MBOX_DEFAULT_LOCK_TIMEOUT : atoi(str);
+ storage->read_locks = p_new(storage->storage.pool,
+ enum mbox_lock_type, MBOX_LOCK_COUNT+1);
+ memcpy(storage->read_locks, read_locks,
+ sizeof(*storage->read_locks) * (MBOX_LOCK_COUNT+1));
- str = getenv("MBOX_DOTLOCK_CHANGE_TIMEOUT");
- dotlock_change_timeout = str == NULL ?
- DEFAULT_DOTLOCK_CHANGE_TIMEOUT : atoi(str);
+ storage->write_locks = p_new(storage->storage.pool,
+ enum mbox_lock_type, MBOX_LOCK_COUNT+1);
+ memcpy(storage->write_locks, write_locks,
+ sizeof(*storage->write_locks) * (MBOX_LOCK_COUNT+1));
- lock_settings_initialized = TRUE;
+ storage->lock_settings_initialized = TRUE;
}
static int mbox_file_open_latest(struct mbox_lock_context *ctx, int lock_type)
lock_types = ctx->lock_type == F_WRLCK ||
(ctx->lock_type == F_UNLCK &&
ctx->mbox->mbox_lock_type == F_WRLCK) ?
- write_locks : read_locks;
+ ctx->mbox->storage->write_locks :
+ ctx->mbox->storage->read_locks;
for (i = 0; lock_types[i] != (enum mbox_lock_type)-1; i++) {
if (lock_types[i] == MBOX_LOCK_DOTLOCK)
ctx->dotlock_last_stale = -1;
memset(&set, 0, sizeof(set));
- set.use_excl_lock = (mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
- set.nfs_flush = (mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0;
- set.timeout = lock_timeout;
- set.stale_timeout = dotlock_change_timeout;
+ set.use_excl_lock = mbox->storage->storage.set->dotlock_use_excl;
+ set.nfs_flush = mbox->storage->storage.set->mail_nfs_storage;
+ set.timeout = mbox->storage->set->mbox_lock_timeout;
+ set.stale_timeout = mbox->storage->set->mbox_dotlock_change_timeout;
set.callback = dotlock_callback;
set.context = ctx;
lock_types = lock_type == F_WRLCK ||
(lock_type == F_UNLCK && ctx->mbox->mbox_lock_type == F_WRLCK) ?
- write_locks : read_locks;
+ ctx->mbox->storage->write_locks :
+ ctx->mbox->storage->read_locks;
for (i = idx; lock_types[i] != (enum mbox_lock_type)-1; i++) {
type = lock_types[i];
lock_status = lock_type != F_UNLCK;
index_storage_lock_notify_reset(&mbox->ibox);
- if (!lock_settings_initialized)
- mbox_init_lock_settings();
+ if (!mbox->storage->lock_settings_initialized)
+ mbox_init_lock_settings(mbox->storage);
if (mbox->mbox_fd == -1 && mbox->mbox_file_stream != NULL) {
/* read-only mbox stream. no need to lock. */
return 1;
}
- max_wait_time = time(NULL) + lock_timeout;
+ max_wait_time = time(NULL) + mbox->storage->set->mbox_lock_timeout;
memset(&ctx, 0, sizeof(ctx));
ctx.mbox = mbox;
if (mbox->mbox_lock_type == F_WRLCK) {
/* dropping to shared lock. first drop those that we
don't remove completely. */
+ const enum mbox_lock_type *read_locks =
+ mbox->storage->read_locks;
+
for (i = 0; i < MBOX_LOCK_COUNT; i++)
ctx.lock_status[i] = 1;
for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
if (drop_locks) {
/* dropping to shared lock: drop the locks that are only
in write list */
+ const enum mbox_lock_type *read_locks =
+ mbox->storage->read_locks;
+ const enum mbox_lock_type *write_locks =
+ mbox->storage->write_locks;
+
memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
ctx.lock_status[write_locks[i]] = 1;
if (ret <= 0)
return ret;
- if ((mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0) {
+ if (mbox->storage->storage.set->mail_nfs_storage) {
if (fcntl_locked) {
nfs_flush_attr_cache_fd_locked(mbox->path,
mbox->mbox_fd);
if (seq == hdr->messages_count) {
/* last message, use the synced mbox size */
- trailer_size = (mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ? 2 : 1;
+ trailer_size =
+ mbox->storage->storage.set->mail_save_crlf ? 2 : 1;
*next_offset_r = mbox->mbox_hdr.sync_size - trailer_size;
} else {
if (mbox_file_lookup_offset(mbox, view, seq + 1,
}
/* convert linefeeds to wanted format */
- ret = (ctx->mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
+ ret = ctx->mbox->storage->storage.set->mail_save_crlf ?
i_stream_create_crlf(filter) : i_stream_create_lf(filter);
i_stream_unref(&filter);
this makes it impossible to save a mail that doesn't
end with LF though. */
const char *linefeed =
- (ctx->mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_SAVE_CRLF) != 0 ?
+ ctx->mbox->storage->storage.set->mail_save_crlf ?
"\r\n" : "\n";
if (o_stream_send_str(ctx->output, linefeed) < 0)
return write_error(ctx);
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "mbox-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct mbox_settings, name), NULL }
+
+static struct setting_define mbox_setting_defines[] = {
+ DEF(SET_STR, mbox_read_locks),
+ DEF(SET_STR, mbox_write_locks),
+ DEF(SET_UINT, mbox_lock_timeout),
+ DEF(SET_UINT, mbox_dotlock_change_timeout),
+ DEF(SET_UINT, mbox_min_index_size),
+ DEF(SET_BOOL, mbox_dirty_syncs),
+ DEF(SET_BOOL, mbox_very_dirty_syncs),
+ DEF(SET_BOOL, mbox_lazy_writes),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct mbox_settings mbox_default_settings = {
+ MEMBER(mbox_read_locks) "fcntl",
+ MEMBER(mbox_write_locks) "dotlock fcntl",
+ MEMBER(mbox_lock_timeout) 5*60,
+ MEMBER(mbox_dotlock_change_timeout) 2*60,
+ MEMBER(mbox_min_index_size) 0,
+ MEMBER(mbox_dirty_syncs) TRUE,
+ MEMBER(mbox_very_dirty_syncs) FALSE,
+ MEMBER(mbox_lazy_writes) TRUE
+};
+
+static struct setting_parser_info mbox_setting_parser_info = {
+ MEMBER(defines) mbox_setting_defines,
+ MEMBER(defaults) &mbox_default_settings,
+
+ MEMBER(parent) &mail_user_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct mbox_settings)
+};
+
+const struct setting_parser_info *mbox_get_setting_parser_info(void)
+{
+ return &mbox_setting_parser_info;
+}
--- /dev/null
+#ifndef MBOX_SETTINGS_H
+#define MBOX_SETTINGS_H
+
+struct mbox_settings {
+ const char *mbox_read_locks;
+ const char *mbox_write_locks;
+ unsigned int mbox_lock_timeout;
+ unsigned int mbox_dotlock_change_timeout;
+ unsigned int mbox_min_index_size;
+ bool mbox_dirty_syncs;
+ bool mbox_very_dirty_syncs;
+ bool mbox_lazy_writes;
+};
+
+const struct setting_parser_info *mbox_get_setting_parser_info(void);
+
+#endif
return TRUE;
}
-static bool mbox_autodetect(const char *data, enum mail_storage_flags flags)
+static bool mbox_autodetect(const struct mail_namespace *ns)
{
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = ns->mail_set->mail_debug;
+ const char *data = ns->set->location;
const char *path;
path = t_strcut(data, ':');
-
if (debug) {
if (strchr(data, ':') != NULL) {
i_info("mbox autodetect: data=%s, splitting ':' -> %s",
static const char *get_root_dir(struct mail_storage *storage)
{
+ struct mail_namespace auto_ns;
+ struct mail_namespace_settings ns_set;
const char *home, *path;
- bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
if (mail_user_get_home(storage->ns->user, &home) > 0) {
path = t_strconcat(home, "/mail", NULL);
if (debug)
i_info("mbox: checking if we are chrooted:");
- if (mbox_autodetect("", storage->flags))
+
+ memset(&ns_set, 0, sizeof(ns_set));
+ ns_set.location = "";
+ memset(&auto_ns, 0, sizeof(auto_ns));
+ auto_ns.set = &ns_set;
+ auto_ns.mail_set = storage->set;
+ if (mbox_autodetect(&auto_ns))
return "/";
if (debug)
i_info("mbox: root mail directory not found");
-
return NULL;
}
return NULL;
}
- if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+ if (storage->set->mail_debug)
i_info("mbox: root directory created: %s", path);
return path;
}
const char **layout_r, const char **error_r)
{
enum mail_storage_flags flags = storage->flags;
- bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
const char *p;
struct stat st;
bool autodetect;
if (mailbox_list_alloc(layout, &_storage->list, error_r) < 0)
return -1;
+ storage->set = mail_storage_get_driver_settings(_storage);
+
storage->list_module_ctx.super = _storage->list->v;
if (strcmp(layout, "fs") == 0 && *list_set.maildir_name == '\0') {
/* have to use .imap/ directories */
/* finish list init after we've overridden vfuncs */
mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags) |
MAILBOX_LIST_FLAG_MAILBOX_FILES);
return 0;
}
static bool want_memory_indexes(struct mbox_storage *storage, const char *path)
{
- const char *env;
struct stat st;
- unsigned int min_size;
- env = getenv("MBOX_MIN_INDEX_SIZE");
- if (env == NULL)
- return FALSE;
-
- min_size = strtoul(env, NULL, 10);
- if (min_size == 0)
+ if (storage->set->mbox_min_index_size == 0)
return FALSE;
if (stat(path, &st) < 0) {
return FALSE;
}
}
- return st.st_size / 1024 < min_size;
+ return st.st_size / 1024 < storage->set->mbox_min_index_size;
}
static void mbox_lock_touch_timeout(struct mbox_mailbox *mbox)
sizeof(mbox->mbox_hdr),
sizeof(uint64_t), sizeof(uint64_t));
- mbox->mbox_very_dirty_syncs = getenv("MBOX_VERY_DIRTY_SYNCS") != NULL;
- mbox->mbox_do_dirty_syncs = mbox->mbox_very_dirty_syncs ||
- getenv("MBOX_DIRTY_SYNCS") != NULL;
-
if ((storage->storage.flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) != 0)
mbox->mbox_save_md5 = TRUE;
MEMBER(mailbox_is_file) TRUE,
{
+ mbox_get_setting_parser_info,
mbox_class_init,
mbox_class_deinit,
mbox_alloc,
#ifndef MBOX_STORAGE_H
#define MBOX_STORAGE_H
+#include "index-storage.h"
+#include "mbox-settings.h"
+#include "mailbox-list-private.h"
+
/* Padding to leave in X-Keywords header when rewriting mbox */
#define MBOX_HEADER_PADDING 50
/* Don't write Content-Length header unless it's value is larger than this. */
#define MBOX_INDEX_PREFIX "dovecot.index"
#define MBOX_INDEX_DIR_NAME ".imap"
-#include "index-storage.h"
-#include "mailbox-list-private.h"
-
struct mbox_index_header {
uint64_t sync_size;
uint32_t sync_mtime;
struct mbox_storage {
struct mail_storage storage;
+ const struct mbox_settings *set;
+ enum mbox_lock_type *read_locks;
+ enum mbox_lock_type *write_locks;
+ unsigned int lock_settings_initialized:1;
+
union mailbox_list_module_context list_module_ctx;
};
unsigned int no_mbox_file:1;
unsigned int invalid_mbox_file:1;
unsigned int mbox_broken_offsets:1;
- unsigned int mbox_do_dirty_syncs:1;
- unsigned int mbox_very_dirty_syncs:1;
unsigned int mbox_save_md5:1;
unsigned int mbox_dotlocked:1;
unsigned int mbox_used_privileges:1;
delay_writes = mbox->ibox.backend_readonly ||
((flags & MBOX_SYNC_REWRITE) == 0 &&
- getenv("MBOX_LAZY_WRITES") != NULL);
+ mbox->storage->set->mbox_lazy_writes);
- if (!mbox->mbox_do_dirty_syncs)
+ if (!mbox->storage->set->mbox_dirty_syncs &&
+ !mbox->storage->set->mbox_very_dirty_syncs)
flags |= MBOX_SYNC_UNDIRTY;
if ((flags & MBOX_SYNC_LOCK_READING) != 0) {
i_assert(*lock_id != 0);
- if ((mbox->storage->storage.flags &
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0 && mbox->mbox_fd != -1) {
+ if (mbox->storage->storage.set->mail_nfs_storage &&
+ mbox->mbox_fd != -1) {
if (fdatasync(mbox->mbox_fd) < 0) {
mbox_set_syscall_error(mbox, "fdatasync()");
ret = -1;
if (index_mailbox_want_full_sync(&mbox->ibox, flags)) {
if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
- !mbox->mbox_very_dirty_syncs)
+ !mbox->storage->set->mbox_very_dirty_syncs)
mbox_sync_flags |= MBOX_SYNC_UNDIRTY;
if ((flags & MAILBOX_SYNC_FLAG_FULL_WRITE) != 0)
mbox_sync_flags |= MBOX_SYNC_REWRITE;
const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
*layout_r = "fs";
/* finish list init after we've overridden vfuncs */
mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags));
+ MAILBOX_LIST_FLAG_MAILBOX_FILES);
return 0;
}
MEMBER(mailbox_is_file) TRUE,
{
+ NULL,
raw_class_init,
raw_class_deinit,
raw_alloc,
return -1;
}
storage->ns_prefix_pattern = p_strdup(_storage->pool, wildcardp);
- *wildcardp = '\0';
have_username = FALSE;
for (p = storage->ns_prefix_pattern; *p != '\0'; p++) {
return -1;
}
+ /* truncate prefix after the above checks are done, so they can log
+ the full prefix in error conditions */
+ *wildcardp = '\0';
+
if (mailbox_list_alloc("shared", &_storage->list, error_r) < 0)
return -1;
MODULE_CONTEXT_SET_FULL(_storage->list, shared_mailbox_list_module,
memset(&list_set, 0, sizeof(list_set));
list_set.mail_storage_flags = &_storage->flags;
list_set.lock_method = &_storage->lock_method;
- mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags));
+ mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
return 0;
}
};
struct var_expand_table *tab;
struct mail_namespace *ns;
+ struct mail_namespace_settings *ns_set;
struct mail_user *owner;
const char *domain = NULL, *username = NULL, *userdomain = NULL;
const char *name, *p, *next, **dest, *error;
return 0;
}
- owner = mail_user_init(userdomain);
+ owner = mail_user_alloc(userdomain, user->unexpanded_set);
if (!var_has_key(storage->location, 'h', "home"))
ret = 1;
else {
return -1;
}
}
+ if (mail_user_init(owner, &error) < 0) {
+ mail_storage_set_critical(_storage,
+ "Couldn't create namespace '%s' for user %s: %s",
+ _storage->ns->prefix, userdomain, error);
+ mail_user_unref(&owner);
+ return -1;
+ }
/* create the new namespace */
ns = i_new(struct mail_namespace, 1);
ns->flags = NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
NAMESPACE_FLAG_AUTOCREATED;
ns->sep = _storage->ns->sep;
+ ns->mail_set = _storage->set;
location = t_str_new(256);
if (ret > 0)
var_expand(location, storage->location, tab);
else
get_nonexisting_user_location(storage, userdomain, location);
- if (mail_storage_create(ns, NULL, str_c(location), _storage->flags,
- _storage->lock_method, &error) < 0) {
+
+ ns_set = p_new(user->pool, struct mail_namespace_settings, 1);
+ ns_set->type = "shared";
+ ns_set->separator = p_strdup_printf(user->pool, "%c", ns->sep);
+ ns_set->prefix = ns->prefix;
+ ns_set->location = p_strdup(user->pool, str_c(location));
+ ns_set->hidden = TRUE;
+ ns_set->list = "yes";
+ ns->set = ns_set;
+
+ if (mail_storage_create(ns, NULL, _storage->flags, &error) < 0) {
mail_storage_set_critical(_storage, "Namespace '%s': %s",
ns->prefix, error);
mail_namespace_destroy(ns);
MEMBER(mailbox_is_file) FALSE, /* unknown at this point */
{
+ NULL,
NULL,
NULL,
shared_alloc,
struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
const char *path;
enum mail_index_open_flags index_flags;
- enum mail_storage_flags storage_flags;
+ enum file_lock_method lock_method;
int ret;
- /* FIXME: a bit ugly way to get the flags, but this will do for now.. */
- index_flags = MAIL_INDEX_OPEN_FLAG_CREATE;
- storage_flags = *list->set.mail_storage_flags;
-#ifndef MMAP_CONFLICTS_WRITE
- if ((storage_flags & MAIL_STORAGE_FLAG_MMAP_DISABLE) != 0)
-#endif
- index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
+ index_flags = MAIL_INDEX_OPEN_FLAG_CREATE |
+ mail_storage_settings_to_index_flags(list->mail_set);
+
+ if (!file_lock_method_parse(list->mail_set->lock_method,
+ &lock_method)) {
+ i_error("Unknown lock_method: %s", list->mail_set->lock_method);
+ return -1;
+ }
if (mail_index_open(ilist->mail_index, index_flags,
*list->set.lock_method) < 0) {
/* FIXME: always disabled for now */
dir = mailbox_list_get_path(list, NULL, MAILBOX_LIST_PATH_TYPE_INDEX);
- if (*dir == '\0' || getenv("MAILBOX_LIST_INDEX_DISABLE") != NULL ||
+ if (*dir == '\0' || list->mail_set->mailbox_list_index_disable ||
strcmp(list->name, "maildir++") != 0 || 1) {
/* reserve the module context anyway, so syncing code knows
that the index is disabled */
{
const char *const *patterns, *name, *p, *last;
- if ((ctx->ctx.list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
+ if (!ctx->ctx.list->mail_set->mail_full_filesystem_access)
return NULL;
/* see if there are any absolute paths in patterns */
static bool
fs_is_valid_pattern(struct mailbox_list *list, const char *pattern)
{
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+ if (list->mail_set->mail_full_filesystem_access)
return TRUE;
return fs_list_is_valid_common_nonfs(list, pattern);
if (!fs_list_is_valid_common(name, &len))
return FALSE;
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+ if (list->mail_set->mail_full_filesystem_access)
return TRUE;
return fs_list_is_valid_common_nonfs(list, name);
if (len > FS_MAX_CREATE_MAILBOX_NAME_LENGTH)
return FALSE;
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+ if (list->mail_set->mail_full_filesystem_access)
return TRUE;
if (mailbox_list_name_is_too_large(name, '/'))
if (!maildir_list_is_valid_common(list, name, &len))
return FALSE;
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+ if (list->mail_set->mail_full_filesystem_access)
return TRUE;
return maildir_list_is_valid_common_nonfs(name);
if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH)
return FALSE;
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0)
+ if (list->mail_set->mail_full_filesystem_access)
return TRUE;
if (!maildir_list_is_valid_common_nonfs(name))
maildir_list_get_path(struct mailbox_list *_list, const char *name,
enum mailbox_list_path_type type)
{
- struct maildir_mailbox_list *list =
- (struct maildir_mailbox_list *)_list;
-
if (name == NULL) {
/* return root directories */
switch (type) {
i_unreached();
}
- if ((list->list.flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0 &&
+ if (_list->mail_set->mail_full_filesystem_access &&
(*name == '/' || *name == '~'))
return maildir_list_get_absolute_path(_list, name);
static void subsread_set_syscall_error(struct mailbox_list *list,
const char *function, const char *path)
{
- if (errno == EACCES &&
- (list->flags & MAILBOX_LIST_FLAG_DEBUG) == 0) {
+ if (errno == EACCES && !list->mail_set->mail_debug) {
mailbox_list_set_error(list, MAIL_ERROR_PERM,
"No permission to read subscriptions");
} else {
static void subswrite_set_syscall_error(struct mailbox_list *list,
const char *function, const char *path)
{
- if (errno == EACCES &&
- (list->flags & MAILBOX_LIST_FLAG_DEBUG) == 0) {
+ if (errno == EACCES && !list->mail_set->mail_debug) {
mailbox_list_set_error(list, MAIL_ERROR_PERM,
"No permission to modify subscriptions");
} else {
name = "INBOX";
memset(&dotlock_set, 0, sizeof(dotlock_set));
- dotlock_set.use_excl_lock =
- (list->flags & MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL) != 0;
- dotlock_set.nfs_flush =
- (list->flags & MAILBOX_LIST_FLAG_NFS_FLUSH) != 0;
+ dotlock_set.use_excl_lock = list->mail_set->dotlock_use_excl;
+ dotlock_set.nfs_flush = list->mail_set->mail_nfs_storage;
dotlock_set.temp_prefix = temp_prefix;
dotlock_set.timeout = SUBSCRIPTION_FILE_LOCK_TIMEOUT;
dotlock_set.stale_timeout = SUBSCRIPTION_FILE_CHANGE_TIMEOUT;
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "array.h"
#include "str.h"
#include "file-lock.h"
#include "mail-storage.h"
+#include "mail-storage-settings.h"
#include "mail-namespace.h"
#include <stdlib.h>
i_free(ns);
}
-static struct mail_namespace *
-namespace_add_env(const char *data, unsigned int num,
- struct mail_user *user, enum mail_storage_flags flags,
- enum file_lock_method lock_method,
- struct mail_namespace *prev_namespaces)
+static int
+namespace_add(struct mail_user *user,
+ struct mail_namespace_settings *ns_set,
+ const struct mail_storage_settings *mail_set,
+ struct mail_namespace *prev_namespaces,
+ struct mail_namespace **ns_p, const char **error_r)
{
struct mail_namespace *ns;
- const char *sep, *type, *prefix, *driver, *error, *list, *alias_for;
+ const char *driver, *error;
ns = i_new(struct mail_namespace, 1);
-
- sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
- type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
- prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
- list = getenv(t_strdup_printf("NAMESPACE_%u_LIST", num));
- alias_for = getenv(t_strdup_printf("NAMESPACE_%u_ALIAS", num));
- if (getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL)
- ns->flags |= NAMESPACE_FLAG_INBOX;
- if (getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL)
- ns->flags |= NAMESPACE_FLAG_HIDDEN;
- if (list != NULL) {
- if (strcmp(list, "children") == 0)
- ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN;
- else
- ns->flags |= NAMESPACE_FLAG_LIST_PREFIX;
- }
- if (getenv(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS", num)) != NULL)
- ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS;
-
- if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0) {
- ns->type = NAMESPACE_PRIVATE;
+ if (strncmp(ns_set->type, "private", 7) == 0) {
ns->owner = user;
- } else if (strncmp(type, "shared", 6) == 0)
+ ns->type = NAMESPACE_PRIVATE;
+ } else if (strncmp(ns_set->type, "shared", 6) == 0)
ns->type = NAMESPACE_SHARED;
- else if (strncmp(type, "public", 6) == 0)
+ else if (strncmp(ns_set->type, "public", 6) == 0)
ns->type = NAMESPACE_PUBLIC;
else {
- i_error("Unknown namespace type: %s", type);
+ *error_r = t_strdup_printf("Unknown namespace type: %s",
+ ns_set->type);
mail_namespace_free(ns);
- return NULL;
+ return -1;
}
- if (alias_for != NULL) {
+ if (strcmp(ns_set->list, "children") == 0)
+ ns->flags |= NAMESPACE_FLAG_LIST_CHILDREN;
+ else if (strcmp(ns_set->list, "yes") == 0)
+ ns->flags |= NAMESPACE_FLAG_LIST_PREFIX;
+ else if (strcmp(ns_set->list, "no") != 0) {
+ *error_r = t_strdup_printf("Invalid list setting value: %s",
+ ns_set->list);
+ mail_namespace_free(ns);
+ return -1;
+ }
+
+ if (ns_set->inbox)
+ ns->flags |= NAMESPACE_FLAG_INBOX;
+ if (ns_set->hidden)
+ ns->flags |= NAMESPACE_FLAG_HIDDEN;
+ if (ns_set->subscriptions)
+ ns->flags |= NAMESPACE_FLAG_SUBSCRIPTIONS;
+
+ if (ns_set->alias_for != NULL) {
ns->alias_for = mail_namespace_find_prefix(prev_namespaces,
- alias_for);
+ ns_set->alias_for);
if (ns->alias_for == NULL) {
- i_error("Invalid namespace alias_for: %s", alias_for);
+ *error_r = t_strdup_printf("Invalid namespace alias_for: %s",
+ ns_set->alias_for);
mail_namespace_free(ns);
- return NULL;
+ return -1;
}
if (ns->alias_for->alias_for != NULL) {
- i_error("Chained namespace alias_for: %s", alias_for);
+ *error_r = t_strdup_printf("Chained namespace alias_for: %s",
+ ns_set->alias_for);
mail_namespace_free(ns);
- return NULL;
+ return -1;
}
ns->alias_chain_next = ns->alias_for->alias_chain_next;
ns->alias_for->alias_chain_next = ns;
}
- if (prefix == NULL)
- prefix = "";
-
- if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0) {
+ if (mail_set->mail_debug) {
i_info("Namespace: type=%s, prefix=%s, sep=%s, "
"inbox=%s, hidden=%s, list=%s, subscriptions=%s",
- type == NULL ? "" : type, prefix, sep == NULL ? "" : sep,
- (ns->flags & NAMESPACE_FLAG_INBOX) ? "yes" : "no",
- (ns->flags & NAMESPACE_FLAG_HIDDEN) ? "yes" : "no",
- list,
- (ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) ?
- "yes" : "no");
+ ns_set->type, ns_set->prefix,
+ ns_set->separator == NULL ? "" : ns_set->separator,
+ ns_set->inbox ? "yes" : "no",
+ ns_set->hidden ? "yes" : "no",
+ ns_set->list ? "yes" : "no",
+ ns_set->subscriptions ? "yes" : "no");
}
- if (sep != NULL)
- ns->sep = *sep;
- ns->prefix = i_strdup(prefix);
+ if (*ns_set->location == '\0')
+ ns_set->location = mail_set->mail_location;
+
+ ns->set = ns_set;
+ ns->mail_set = mail_set;
+ ns->prefix = i_strdup(ns_set->prefix);
ns->user = user;
if (ns->type == NAMESPACE_SHARED && strchr(ns->prefix, '%') != NULL) {
driver = NULL;
}
- if (mail_storage_create(ns, driver, data, flags, lock_method,
- &error) < 0) {
- i_error("Namespace '%s': %s", ns->prefix, error);
+ if (mail_storage_create(ns, driver, 0, &error) < 0) {
+ *error_r = t_strdup_printf("Namespace '%s': %s",
+ ns->prefix, error);
mail_namespace_free(ns);
- return NULL;
+ return -1;
}
- return ns;
+ if (ns_set->separator != NULL)
+ ns->sep = *ns_set->separator;
+
+ *ns_p = ns;
+ return 0;
}
-static bool namespaces_check(struct mail_namespace *namespaces)
+static bool
+namespaces_check(struct mail_namespace *namespaces, const char **error_r)
{
struct mail_namespace *ns, *inbox_ns = NULL, *private_ns = NULL;
unsigned int private_ns_count = 0;
for (ns = namespaces; ns != NULL; ns = ns->next) {
if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0) {
if (inbox_ns != NULL) {
- i_error("namespace configuration error: "
+ *error_r = "namespace configuration error: "
"There can be only one namespace with "
- "inbox=yes");
+ "inbox=yes";
return FALSE;
}
inbox_ns = ns;
if (*ns->prefix != '\0' &&
(ns->flags & NAMESPACE_FLAG_LIST_PREFIX) != 0 &&
ns->prefix[strlen(ns->prefix)-1] != ns->sep) {
- i_error("namespace configuration error: "
+ *error_r = t_strdup_printf(
+ "namespace configuration error: "
"list=yes requires prefix=%s "
"to end with separator", ns->prefix);
return FALSE;
if (list_sep == '\0')
list_sep = ns->sep;
else if (list_sep != ns->sep) {
- i_error("namespace configuration error: "
+ *error_r = "namespace configuration error: "
"All list=yes namespaces must use "
- "the same separator");
+ "the same separator";
return FALSE;
}
}
if (*ns->prefix == '\0' &&
(ns->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0) {
- i_error("namespace configuration error: "
- "Empty prefix requires list=yes");
+ *error_r = "namespace configuration error: "
+ "Empty prefix requires list=yes";
return FALSE;
}
if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
the INBOX namespace. */
private_ns->flags |= NAMESPACE_FLAG_INBOX;
} else {
- i_error("namespace configuration error: "
- "inbox=yes namespace missing");
+ *error_r = "namespace configuration error: "
+ "inbox=yes namespace missing";
return FALSE;
}
}
if (list_sep == '\0') {
- i_error("namespace configuration error: "
- "no list=yes namespaces");
+ *error_r = "namespace configuration error: "
+ "no list=yes namespaces";
return FALSE;
}
if (subscriptions_count == 0) {
- i_error("namespace configuration error: "
- "no subscriptions=yes namespaces");
+ *error_r = "namespace configuration error: "
+ "no subscriptions=yes namespaces";
return FALSE;
}
return TRUE;
}
-int mail_namespaces_init(struct mail_user *user)
+int mail_namespaces_init(struct mail_user *user, const char **error_r)
{
+ const struct mail_storage_settings *mail_set;
+ struct mail_namespace_settings *const *ns_set;
struct mail_namespace *namespaces, *ns, **ns_p;
- enum mail_storage_flags flags;
- enum file_lock_method lock_method;
- const char *mail, *data, *error;
- unsigned int i;
+ struct mail_namespace_settings *inbox_set;
+ const char *error, *driver, *env;
+ unsigned int i, count;
- mail_storage_parse_env(&flags, &lock_method);
- namespaces = NULL; ns_p = &namespaces;
-
- /* first try NAMESPACE_* environments */
- for (i = 1; ; i++) {
- T_BEGIN {
- data = getenv(t_strdup_printf("NAMESPACE_%u", i));
- } T_END;
+ i_assert(user->initialized);
- if (data == NULL)
- break;
-
- T_BEGIN {
- *ns_p = namespace_add_env(data, i, user, flags,
- lock_method, namespaces);
- } T_END;
+ namespaces = NULL; ns_p = &namespaces;
- if (*ns_p == NULL)
+ mail_set = mail_user_set_get_driver_settings(user->set, "MAIL");
+ if (array_is_created(&user->set->namespaces))
+ ns_set = array_get(&user->set->namespaces, &count);
+ else {
+ ns_set = NULL;
+ count = 0;
+ }
+ for (i = 0; i < count; i++) {
+ if (namespace_add(user, ns_set[i], mail_set, namespaces,
+ ns_p, error_r) < 0)
return -1;
-
ns_p = &(*ns_p)->next;
}
if (namespaces != NULL) {
- if (!namespaces_check(namespaces)) {
+ if (!namespaces_check(namespaces, error_r)) {
while (namespaces != NULL) {
ns = namespaces;
namespaces = ns->next;
return 0;
}
- /* fallback to MAIL */
- mail = getenv("MAIL");
- if (mail == NULL) {
- /* support also maildir-specific environment */
- mail = getenv("MAILDIR");
- if (mail != NULL)
- mail = t_strconcat("maildir:", mail, NULL);
- }
-
+ /* fallback to using environment variables */
ns = i_new(struct mail_namespace, 1);
ns->type = NAMESPACE_PRIVATE;
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_SUBSCRIPTIONS;
- ns->prefix = i_strdup("");
- ns->user = user;
ns->owner = user;
- if (mail_storage_create(ns, NULL, mail, flags, lock_method,
- &error) < 0) {
- if (mail != NULL && *mail != '\0')
- i_error("mail_location: %s", error);
+ inbox_set = p_new(user->pool, struct mail_namespace_settings, 1);
+ *inbox_set = mail_namespace_default_settings;
+ inbox_set->inbox = TRUE;
+
+ driver = NULL;
+ env = "MAIL";
+ inbox_set->location = getenv("MAIL");
+ if (inbox_set->location == NULL) {
+ /* support also maildir-specific environment */
+ inbox_set->location = getenv("MAILDIR");
+ if (inbox_set->location == NULL)
+ inbox_set->location = "";
else {
- i_error("mail_location not set and "
- "autodetection failed: %s", error);
+ driver = "maildir";
+ env = "MAILDIR";
+ }
+ }
+
+ ns->set = inbox_set;
+ ns->mail_set = mail_set;
+ ns->prefix = i_strdup(ns->set->prefix);
+ ns->user = user;
+
+ if (mail_storage_create(ns, driver, 0, &error) < 0) {
+ if (*inbox_set->location != '\0') {
+ *error_r = t_strdup_printf(
+ "Initializing mail storage from environment %s "
+ "failed: %s", env, error);
+ } else {
+ *error_r = t_strdup_printf("mail_location not set and "
+ "autodetection failed: %s", error);
}
mail_namespace_free(ns);
return -1;
}
user->namespaces = ns;
+ mail_namespace_init_storage(ns);
if (hook_mail_namespaces_created != NULL) {
T_BEGIN {
return 0;
}
-struct mail_namespace *
-mail_namespaces_init_empty(struct mail_user *user)
+struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user)
{
struct mail_namespace *ns;
ns->prefix = i_strdup("");
ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST_PREFIX |
NAMESPACE_FLAG_SUBSCRIPTIONS;
+ ns->mail_set = mail_user_set_get_driver_settings(user->set, "MAIL");
user->namespaces = ns;
return ns;
}
#include "mail-user.h"
+struct mail_storage_root_settings;
+
enum namespace_type {
NAMESPACE_PRIVATE,
NAMESPACE_SHARED,
struct mailbox_list *list;
/* FIXME: we should support multiple storages in one namespace */
struct mail_storage *storage;
+
+ const struct mail_namespace_settings *set;
+ const struct mail_storage_settings *mail_set;
};
/* Called after namespaces has been created */
extern void (*hook_mail_namespaces_created)(struct mail_namespace *namespaces);
-int mail_namespaces_init(struct mail_user *user);
+int mail_namespaces_init(struct mail_user *user, const char **error_r);
struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user);
void mail_namespaces_deinit(struct mail_namespace **namespaces);
#include "module-context.h"
#include "file-lock.h"
#include "mail-storage.h"
+#include "mail-storage-settings.h"
#include "mail-index-private.h"
/* Called after mail storage has been created */
};
struct mail_storage_vfuncs {
+ const struct setting_parser_info *(*get_setting_parser_info)(void);
+
void (*class_init)(void);
void (*class_deinit)(void);
const char **error_r);
void (*destroy)(struct mail_storage *storage);
- bool (*autodetect)(const char *data, enum mail_storage_flags flags);
+ bool (*autodetect)(const struct mail_namespace *ns);
struct mailbox *(*mailbox_open)(struct mail_storage *storage,
const char *name,
const struct mail_storage *storage_class;
struct mail_namespace *ns;
struct mailbox_list *list;
+ const struct mail_storage_settings *set;
enum mail_storage_flags flags;
enum file_lock_method lock_method;
- unsigned int keyword_max_len;
struct mail_storage_callbacks *callbacks;
void *callback_context;
void mail_set_expunged(struct mail *mail);
void mailbox_set_deleted(struct mailbox *box);
-enum mailbox_list_flags
-mail_storage_get_list_flags(enum mail_storage_flags storage_flags);
#endif
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "settings-parser.h"
+#include "mail-index.h"
+#include "mail-user.h"
+#include "mail-namespace.h"
+#include "mail-storage-private.h"
+#include "mail-storage-settings.h"
+
+#include <stddef.h>
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct mail_storage_settings, name), NULL }
+
+static struct setting_define mail_storage_setting_defines[] = {
+ DEF(SET_STR_VARS, mail_location),
+ DEF(SET_STR, mail_cache_fields),
+ DEF(SET_STR, mail_never_cache_fields),
+ DEF(SET_UINT, mail_cache_min_mail_count),
+ DEF(SET_UINT, mailbox_idle_check_interval),
+ DEF(SET_UINT, mail_max_keyword_length),
+ DEF(SET_BOOL, mail_save_crlf),
+ DEF(SET_BOOL, fsync_disable),
+ DEF(SET_BOOL, mmap_disable),
+ DEF(SET_BOOL, dotlock_use_excl),
+ DEF(SET_BOOL, mail_nfs_storage),
+ DEF(SET_BOOL, mail_nfs_index),
+ DEF(SET_BOOL, mailbox_list_index_disable),
+ DEF(SET_BOOL, mail_debug),
+ DEF(SET_BOOL, mail_full_filesystem_access),
+ DEF(SET_ENUM, lock_method),
+ DEF(SET_STR, pop3_uidl_format),
+
+ SETTING_DEFINE_LIST_END
+};
+
+struct mail_storage_settings mail_storage_default_settings = {
+ MEMBER(mail_location) "",
+ MEMBER(mail_cache_fields) "flags",
+ MEMBER(mail_never_cache_fields) "imap.envelope",
+ MEMBER(mail_cache_min_mail_count) 0,
+ MEMBER(mailbox_idle_check_interval) 30,
+ MEMBER(mail_max_keyword_length) 50,
+ MEMBER(mail_save_crlf) FALSE,
+ MEMBER(fsync_disable) FALSE,
+ MEMBER(mmap_disable) FALSE,
+ MEMBER(dotlock_use_excl) FALSE,
+ MEMBER(mail_nfs_storage) FALSE,
+ MEMBER(mail_nfs_index) FALSE,
+ MEMBER(mailbox_list_index_disable) FALSE,
+ MEMBER(mail_debug) FALSE,
+ MEMBER(mail_full_filesystem_access) FALSE,
+ MEMBER(lock_method) "fcntl:flock:dotlock",
+ MEMBER(pop3_uidl_format) "%08Xu%08Xv"
+};
+
+struct setting_parser_info mail_storage_setting_parser_info = {
+ MEMBER(defines) mail_storage_setting_defines,
+ MEMBER(defaults) &mail_storage_default_settings,
+
+ MEMBER(parent) &mail_user_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct mail_storage_settings)
+};
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct mail_namespace_settings, name), NULL }
+
+static struct setting_define mail_namespace_setting_defines[] = {
+ DEF(SET_ENUM, type),
+ DEF(SET_STR, separator),
+ DEF(SET_STR_VARS, prefix),
+ DEF(SET_STR_VARS, location),
+ DEF(SET_STR_VARS, alias_for),
+
+ DEF(SET_BOOL, inbox),
+ DEF(SET_BOOL, hidden),
+ DEF(SET_ENUM, list),
+ DEF(SET_BOOL, subscriptions),
+
+ SETTING_DEFINE_LIST_END
+};
+
+struct mail_namespace_settings mail_namespace_default_settings = {
+ MEMBER(type) "private:shared:public",
+ MEMBER(separator) "",
+ MEMBER(prefix) "",
+ MEMBER(location) "",
+ MEMBER(alias_for) NULL,
+
+ MEMBER(inbox) FALSE,
+ MEMBER(hidden) FALSE,
+ MEMBER(list) "yes:no:children",
+ MEMBER(subscriptions) TRUE
+};
+
+struct setting_parser_info mail_namespace_setting_parser_info = {
+ MEMBER(defines) mail_namespace_setting_defines,
+ MEMBER(defaults) &mail_namespace_default_settings,
+
+ MEMBER(parent) &mail_user_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct mail_namespace_settings, type),
+ MEMBER(struct_size) sizeof(struct mail_namespace_settings)
+};
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct mail_user_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, \
+ offsetof(struct mail_user_settings, field), defines }
+
+static struct setting_define mail_user_setting_defines[] = {
+ DEF(SET_UINT, umask),
+
+ DEFLIST(namespaces, "namespace", &mail_namespace_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct mail_user_settings mail_user_default_settings = {
+ MEMBER(umask) 0077,
+
+ MEMBER(namespaces) ARRAY_INIT
+};
+
+struct setting_parser_info mail_user_setting_parser_info = {
+ MEMBER(defines) mail_user_setting_defines,
+ MEMBER(defaults) &mail_user_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct mail_user_settings)
+};
+
+const void *
+mail_user_set_get_driver_settings(const struct mail_user_settings *set,
+ const char *driver)
+{
+ const void *dset;
+
+ dset = settings_find_dynamic(&mail_user_setting_parser_info,
+ set, driver);
+ if (dset == NULL) {
+ i_panic("Default settings not found for storage driver %s",
+ driver);
+ }
+ return dset;
+}
+
+const void *mail_storage_get_driver_settings(struct mail_storage *storage)
+{
+ return mail_user_set_get_driver_settings(storage->ns->user->set,
+ storage->name);
+}
+
+enum mail_index_open_flags
+mail_storage_settings_to_index_flags(const struct mail_storage_settings *set)
+{
+ enum mail_index_open_flags index_flags = 0;
+
+ if (set->fsync_disable)
+ index_flags |= MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE;
+#ifndef MMAP_CONFLICTS_WRITE
+ if (set->mmap_disable)
+#endif
+ index_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
+ if (set->dotlock_use_excl)
+ index_flags |= MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL;
+ return index_flags;
+}
+
+void mail_storage_namespace_defines_init(pool_t pool)
+{
+ struct dynamic_settings_parser *parsers;
+ struct mail_storage *const *storages;
+ unsigned int i, j, count;
+
+ storages = array_get(&mail_storage_classes, &count);
+ parsers = t_new(struct dynamic_settings_parser, count + 1);
+ parsers[0].name = "MAIL";
+ parsers[0].info = &mail_storage_setting_parser_info;
+
+ for (i = 0, j = 1; i < count; i++) {
+ if (storages[i]->v.get_setting_parser_info == NULL)
+ continue;
+
+ parsers[j].name = storages[i]->name;
+ parsers[j].info = storages[i]->v.get_setting_parser_info();
+ j++;
+ }
+
+ settings_parser_info_update(pool, parsers[j-1].info->parent, parsers);
+}
--- /dev/null
+#ifndef MAIL_STORAGE_SETTINGS_H
+#define MAIL_STORAGE_SETTINGS_H
+
+struct mail_user;
+struct mail_storage;
+
+struct mail_storage_settings {
+ const char *mail_location;
+ const char *mail_cache_fields;
+ const char *mail_never_cache_fields;
+ unsigned int mail_cache_min_mail_count;
+ unsigned int mailbox_idle_check_interval;
+ unsigned int mail_max_keyword_length;
+ bool mail_save_crlf;
+ bool fsync_disable;
+ bool mmap_disable;
+ bool dotlock_use_excl;
+ bool mail_nfs_storage;
+ bool mail_nfs_index;
+ bool mailbox_list_index_disable;
+ bool mail_debug;
+ bool mail_full_filesystem_access;
+ const char *lock_method;
+ const char *pop3_uidl_format;
+};
+
+struct mail_namespace_settings {
+ const char *type;
+ const char *separator;
+ const char *prefix;
+ const char *location;
+ const char *alias_for;
+
+ bool inbox;
+ bool hidden;
+ const char *list;
+ bool subscriptions;
+};
+
+struct mail_user_settings {
+ unsigned int umask;
+
+ ARRAY_DEFINE(namespaces, struct mail_namespace_settings *);
+};
+
+extern struct setting_parser_info mail_user_setting_parser_info;
+extern struct setting_parser_info mail_namespace_setting_parser_info;
+extern struct setting_parser_info mail_storage_setting_parser_info;
+extern struct mail_namespace_settings mail_namespace_default_settings;
+
+const void *
+mail_user_set_get_driver_settings(const struct mail_user_settings *set,
+ const char *driver);
+const void *mail_storage_get_driver_settings(struct mail_storage *storage);
+
+enum mail_index_open_flags
+mail_storage_settings_to_index_flags(const struct mail_storage_settings *set);
+
+void mail_storage_namespace_defines_init(pool_t pool);
+
+#endif
#include "mail-index-private.h"
#include "mailbox-list-private.h"
#include "mail-storage-private.h"
+#include "mail-storage-settings.h"
#include "mail-namespace.h"
#include "mail-search.h"
#include "mailbox-search-result-private.h"
#include <stdlib.h>
#include <ctype.h>
-#define DEFAULT_MAX_KEYWORD_LENGTH 50
-
struct mail_storage_module_register mail_storage_module_register = { 0 };
struct mail_module_register mail_module_register = { 0 };
void (*hook_mailbox_opened)(struct mailbox *box) = NULL;
void (*hook_mailbox_index_opened)(struct mailbox *box) = NULL;
-static ARRAY_DEFINE(storages, struct mail_storage *);
+ARRAY_TYPE(mail_storage) mail_storage_classes;
void mail_storage_init(void)
{
mailbox_lists_init();
- i_array_init(&storages, 8);
+ i_array_init(&mail_storage_classes, 8);
}
void mail_storage_deinit(void)
{
- if (array_is_created(&storages))
- array_free(&storages);
+ if (array_is_created(&mail_storage_classes))
+ array_free(&mail_storage_classes);
mailbox_lists_deinit();
}
void mail_storage_class_register(struct mail_storage *storage_class)
{
+ i_assert(mail_storage_find_class(storage_class->name) == NULL);
+
if (storage_class->v.class_init != NULL)
storage_class->v.class_init();
/* append it after the list, so the autodetection order is correct */
- array_append(&storages, &storage_class, 1);
+ array_append(&mail_storage_classes, &storage_class, 1);
}
void mail_storage_class_unregister(struct mail_storage *storage_class)
struct mail_storage *const *classes;
unsigned int i, count;
- classes = array_get(&storages, &count);
+ classes = array_get(&mail_storage_classes, &count);
for (i = 0; i < count; i++) {
if (classes[i] == storage_class) {
- array_delete(&storages, i, 1);
+ array_delete(&mail_storage_classes, i, 1);
break;
}
}
storage_class->v.class_deinit();
}
-void mail_storage_parse_env(enum mail_storage_flags *flags_r,
- enum file_lock_method *lock_method_r)
-{
- const char *str;
-
- *flags_r = 0;
- if (getenv("FULL_FILESYSTEM_ACCESS") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
- if (getenv("DEBUG") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_DEBUG;
- if (getenv("MMAP_DISABLE") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_MMAP_DISABLE;
- if (getenv("MMAP_NO_WRITE") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_MMAP_NO_WRITE;
- if (getenv("DOTLOCK_USE_EXCL") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL;
- if (getenv("MAIL_SAVE_CRLF") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_SAVE_CRLF;
- if (getenv("FSYNC_DISABLE") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_FSYNC_DISABLE;
- if (getenv("MAIL_NFS_STORAGE") != NULL)
- *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE;
- if (getenv("MAIL_NFS_INDEX") != NULL) {
- *flags_r |= MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX;
- if ((*flags_r & MAIL_STORAGE_FLAG_MMAP_DISABLE) == 0)
- i_fatal("mail_nfs_index=yes requires mmap_disable=yes");
- if ((*flags_r & MAIL_STORAGE_FLAG_FSYNC_DISABLE) != 0)
- i_fatal("mail_nfs_index=yes requires fsync_disable=no");
- }
-
- str = getenv("POP3_UIDL_FORMAT");
- if (str != NULL && (str = strchr(str, '%')) != NULL &&
- str != NULL && var_get_key(str + 1) == 'm')
- *flags_r |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
-
- str = getenv("LOCK_METHOD");
- if (str == NULL)
- *lock_method_r = FILE_LOCK_METHOD_FCNTL;
- else if (!file_lock_method_parse(str, lock_method_r))
- i_fatal("Unknown lock_method: %s", str);
-}
-
struct mail_storage *mail_storage_find_class(const char *name)
{
struct mail_storage *const *classes;
i_assert(name != NULL);
- classes = array_get(&storages, &count);
+ classes = array_get(&mail_storage_classes, &count);
for (i = 0; i < count; i++) {
if (strcasecmp(classes[i]->name, name) == 0)
return classes[i];
}
static struct mail_storage *
-mail_storage_autodetect(const char *data, enum mail_storage_flags flags)
+mail_storage_autodetect(const struct mail_namespace *ns)
{
struct mail_storage *const *classes;
unsigned int i, count;
- classes = array_get(&storages, &count);
+ classes = array_get(&mail_storage_classes, &count);
for (i = 0; i < count; i++) {
if (classes[i]->v.autodetect != NULL &&
- classes[i]->v.autodetect(data, flags))
+ classes[i]->v.autodetect(ns))
return classes[i];
}
return NULL;
}
int mail_storage_create(struct mail_namespace *ns, const char *driver,
- const char *data, enum mail_storage_flags flags,
- enum file_lock_method lock_method,
- const char **error_r)
+ enum mail_storage_flags flags, const char **error_r)
{
struct mail_storage *storage_class, *storage;
struct mail_storage *const *classes;
- const char *home, *value;
+ const char *data = ns->set->location;
+ const char *home, *p;
unsigned int i, count;
+ if ((flags & MAIL_STORAGE_FLAG_KEEP_HEADER_MD5) == 0 &&
+ ns->mail_set->pop3_uidl_format != NULL) {
+ /* if pop3_uidl_format contains %m, we want to keep the
+ header MD5 sums stored even if we're not running POP3
+ right now. */
+ p = ns->mail_set->pop3_uidl_format;
+ while ((p = strchr(p, '%')) != NULL) {
+ if (p[1] == '%')
+ p += 2;
+ else if (var_get_key(++p) == 'm') {
+ flags |= MAIL_STORAGE_FLAG_KEEP_HEADER_MD5;
+ break;
+ }
+ }
+ }
+
if (data == NULL)
data = "";
else if (driver == NULL)
if (*data == '\0' && driver == NULL) {
/* use the first driver that works */
- classes = array_get(&storages, &count);
+ classes = array_get(&mail_storage_classes, &count);
} else if (driver == NULL) {
- storage_class = mail_storage_autodetect(data, flags);
+ storage_class = mail_storage_autodetect(ns);
if (storage_class == NULL) {
*error_r = t_strdup_printf(
"Ambiguous mail location setting, "
for (i = 0; i < count; i++) {
storage = classes[i]->v.alloc();
+ storage->set = ns->mail_set;
storage->flags = flags;
- storage->lock_method = lock_method;
+ if (!file_lock_method_parse(storage->set->lock_method,
+ &storage->lock_method)) {
+ i_fatal("Unknown lock_method: %s",
+ storage->set->lock_method);
+ }
storage->ns = ns;
storage->callbacks =
if (classes[i]->v.create(storage, data, error_r) == 0)
break;
- if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0 && count > 1) {
+ if (ns->mail_set->mail_debug && count > 1) {
i_info("%s: Couldn't create mail storage %s: %s",
classes[i]->name, data, *error_r);
}
return -1;
}
- value = getenv("MAIL_MAX_KEYWORD_LENGTH");
- storage->keyword_max_len = value != NULL ?
- atoi(value) : DEFAULT_MAX_KEYWORD_LENGTH;
-
if (hook_mail_storage_created != NULL) {
T_BEGIN {
hook_mail_storage_created(storage);
return storage->ns;
}
+const struct mail_storage_settings *
+mail_storage_get_settings(struct mail_storage *storage)
+{
+ return storage->set;
+}
+
void mail_storage_set_callbacks(struct mail_storage *storage,
struct mail_storage_callbacks *callbacks,
void *context)
MAILBOX_LIST_PATH_TYPE_INDEX);
}
-enum mailbox_list_flags
-mail_storage_get_list_flags(enum mail_storage_flags storage_flags)
-{
- enum mailbox_list_flags list_flags = 0;
-
- if ((storage_flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
- list_flags |= MAILBOX_LIST_FLAG_DEBUG;
- if ((storage_flags & MAIL_STORAGE_FLAG_FULL_FS_ACCESS) != 0)
- list_flags |= MAILBOX_LIST_FLAG_FULL_FS_ACCESS;
- if ((storage_flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
- list_flags |= MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL;
- if ((storage_flags & MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE) != 0)
- list_flags |= MAILBOX_LIST_FLAG_NFS_FLUSH;
- return list_flags;
-}
-
bool mail_storage_set_error_from_errno(struct mail_storage *storage)
{
const char *error_string;
if (!mail_error_from_errno(&error, &error_string))
return FALSE;
- if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0 &&
- error != MAIL_ERROR_NOTFOUND) {
+ if (storage->set->mail_debug && error != MAIL_ERROR_NOTFOUND) {
/* debugging is enabled - admin may be debugging a
(permission) problem, so return FALSE to get the caller to
log the full error message. */
return box->storage;
}
+const struct mail_storage_settings *mailbox_get_settings(struct mailbox *box)
+{
+ return box->storage->set;
+}
+
const char *mailbox_get_name(const struct mailbox *box)
{
return box->name;
#define MAIL_STORAGE_STAYALIVE_SECS 15
enum mail_storage_flags {
- /* Print debugging information while initializing the storage */
- MAIL_STORAGE_FLAG_DEBUG = 0x01,
- /* Allow full filesystem access with absolute or relative paths. */
- MAIL_STORAGE_FLAG_FULL_FS_ACCESS = 0x02,
- /* Don't try to mmap() files */
- MAIL_STORAGE_FLAG_MMAP_DISABLE = 0x04,
- /* Don't try to write() to mmap()ed files. Required for the few
- OSes that don't have unified buffer cache
- (currently OpenBSD <= 3.5) */
- MAIL_STORAGE_FLAG_MMAP_NO_WRITE = 0x08,
/* Remember message headers' MD5 sum */
- MAIL_STORAGE_FLAG_KEEP_HEADER_MD5 = 0x10,
- /* Use CRLF linefeeds when saving mails. */
- MAIL_STORAGE_FLAG_SAVE_CRLF = 0x40,
+ MAIL_STORAGE_FLAG_KEEP_HEADER_MD5 = 0x01,
/* Don't try to autodetect anything, require that the given data
contains all the necessary information. */
- MAIL_STORAGE_FLAG_NO_AUTODETECTION = 0x100,
+ MAIL_STORAGE_FLAG_NO_AUTODETECTION = 0x02,
/* Don't autocreate any directories. If they don't exist,
fail to create the storage. */
- MAIL_STORAGE_FLAG_NO_AUTOCREATE = 0x200,
- /* Rely on O_EXCL when creating dotlocks */
- MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL = 0x400,
- /* Flush NFS caches for mail storage / index */
- MAIL_STORAGE_FLAG_NFS_FLUSH_STORAGE = 0x800,
- MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX = 0x1000,
- /* Don't use fsync() or fdatasync() */
- MAIL_STORAGE_FLAG_FSYNC_DISABLE = 0x2000
+ MAIL_STORAGE_FLAG_NO_AUTOCREATE = 0x04
};
enum mailbox_open_flags {
const char *pattern;
};
ARRAY_DEFINE_TYPE(mailbox_virtual_patterns, struct mailbox_virtual_pattern);
-
+ARRAY_DEFINE_TYPE(mail_storage, struct mail_storage *);
ARRAY_DEFINE_TYPE(mailboxes, struct mailbox *);
+extern ARRAY_TYPE(mail_storage) mail_storage_classes;
+
typedef void mailbox_notify_callback_t(struct mailbox *box, void *context);
void mail_storage_init(void);
/* Find mail storage class by name */
struct mail_storage *mail_storage_find_class(const char *name);
-/* Returns flags and lock_method based on environment settings. */
-void mail_storage_parse_env(enum mail_storage_flags *flags_r,
- enum file_lock_method *lock_method_r);
-
/* Create a new instance of registered mail storage class with given
storage-specific data. If driver is NULL, it's tried to be autodetected
- from data. If data is NULL, it uses the first storage that exists.
- The storage is put into ns->storage. */
+ from ns location. If ns location is NULL, it uses the first storage that
+ exists. The storage is put into ns->storage. */
int mail_storage_create(struct mail_namespace *ns, const char *driver,
- const char *data, enum mail_storage_flags flags,
- enum file_lock_method lock_method,
- const char **error_r);
+ enum mail_storage_flags flags, const char **error_r);
void mail_storage_destroy(struct mail_storage **storage);
+/* Returns the storage's real hierarchy separator. */
char mail_storage_get_hierarchy_sep(struct mail_storage *storage);
+/* Returns the storage's mailbox list backend. */
struct mailbox_list *
mail_storage_get_list(const struct mail_storage *storage) ATTR_PURE;
+/* Returns the storage's namespace. */
struct mail_namespace *
mail_storage_get_namespace(const struct mail_storage *storage) ATTR_PURE;
+/* Returns the mail storage settings. */
+const struct mail_storage_settings *
+mail_storage_get_settings(struct mail_storage *storage) ATTR_PURE;
/* Set storage callback functions to use. */
void mail_storage_set_callbacks(struct mail_storage *storage,
/* Enable the given feature for the mailbox. */
int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
-enum mailbox_feature mailbox_get_enabled_features(struct mailbox *box);
+/* Returns all enabled features. */
+enum mailbox_feature
+mailbox_get_enabled_features(struct mailbox *box) ATTR_PURE;
/* Returns storage of given mailbox */
struct mail_storage *mailbox_get_storage(const struct mailbox *box) ATTR_PURE;
+/* Returns the storage's settings. */
+const struct mail_storage_settings *
+mailbox_get_settings(struct mailbox *box) ATTR_PURE;
/* Returns name of given mailbox */
const char *mailbox_get_name(const struct mailbox *box) ATTR_PURE;
#include "lib.h"
#include "array.h"
+#include "hostpid.h"
+#include "network.h"
+#include "var-expand.h"
+#include "settings-parser.h"
#include "auth-master.h"
+#include "mail-storage-settings.h"
#include "mail-namespace.h"
#include "mail-user.h"
pool_unref(&user->pool);
}
-struct mail_user *mail_user_init(const char *username)
+struct mail_user *mail_user_alloc(const char *username,
+ const struct mail_user_settings *set)
{
struct mail_user *user;
pool_t pool;
i_assert(username != NULL);
i_assert(*username != '\0');
- pool = pool_alloconly_create("mail user", 512);
+ pool = pool_alloconly_create("mail user", 2048);
user = p_new(pool, struct mail_user, 1);
user->pool = pool;
user->refcount = 1;
user->username = p_strdup(pool, username);
+ user->unexpanded_set = set;
+ user->set = settings_dup(&mail_user_setting_parser_info, set, pool);
user->v.deinit = mail_user_deinit_base;
p_array_init(&user->module_contexts, user->pool, 5);
+ return user;
+}
+int mail_user_init(struct mail_user *user, const char **error_r)
+{
+ const char *home, *key, *value;
+
+ if (user->_home == NULL &&
+ settings_vars_have_key(&mail_user_setting_parser_info, user->set,
+ 'h', "home", &key, &value) &&
+ mail_user_get_home(user, &home) <= 0) {
+ *error_r = t_strdup_printf(
+ "userdb didn't return a home directory, "
+ "but %s used it (%%h): %s", key, value);
+ return -1;
+ }
+
+ settings_var_expand(&mail_user_setting_parser_info, user->set,
+ user->pool, mail_user_var_expand_table(user));
+
+ user->initialized = TRUE;
if (hook_mail_user_created != NULL)
hook_mail_user_created(user);
- return user;
+ return 0;
}
void mail_user_ref(struct mail_user *user)
return NULL;
}
+void mail_user_set_vars(struct mail_user *user, uid_t uid, const char *service,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip)
+{
+ user->uid = uid;
+ user->service = p_strdup(user->pool, service);
+ if (local_ip != NULL) {
+ user->local_ip = p_new(user->pool, struct ip_addr, 1);
+ *user->local_ip = *local_ip;
+ }
+ if (remote_ip != NULL) {
+ user->remote_ip = p_new(user->pool, struct ip_addr, 1);
+ *user->remote_ip = *remote_ip;
+ }
+}
+
+const struct var_expand_table *
+mail_user_var_expand_table(struct mail_user *user)
+{
+ static struct var_expand_table static_tab[] = {
+ { 'u', NULL, "user" },
+ { 'n', NULL, "username" },
+ { 'd', NULL, "domain" },
+ { 's', NULL, "service" },
+ { 'h', NULL, "home" },
+ { 'l', NULL, "lip" },
+ { 'r', NULL, "rip" },
+ { 'p', NULL, "pid" },
+ { 'i', NULL, "uid" },
+ { '\0', NULL, NULL }
+ };
+ struct var_expand_table *tab;
+
+ if (user->var_expand_table != NULL)
+ return user->var_expand_table;
+
+ tab = p_malloc(user->pool, sizeof(static_tab));
+ memcpy(tab, static_tab, sizeof(static_tab));
+
+ tab[0].value = user->username;
+ tab[1].value = p_strdup(user->pool, t_strcut(user->username, '@'));
+ tab[2].value = strchr(user->username, '@');
+ if (tab[2].value != NULL) tab[2].value++;
+ tab[3].value = user->service;
+ tab[4].value = user->_home; /* don't look it up unless we need it */
+ tab[5].value = user->local_ip == NULL ? NULL :
+ p_strdup(user->pool, net_ip2addr(user->local_ip));
+ tab[6].value = user->remote_ip == NULL ? NULL :
+ p_strdup(user->pool, net_ip2addr(user->remote_ip));
+ tab[7].value = my_pid;
+ tab[8].value = p_strdup(user->pool, dec2str(user->uid));
+
+ user->var_expand_table = tab;
+ return user->var_expand_table;
+}
+
void mail_user_set_home(struct mail_user *user, const char *home)
{
user->_home = p_strdup(user->pool, home);
/* don't access the home directly. It may be set lazily. */
const char *_home;
+ uid_t uid;
+ const char *service;
+ struct ip_addr *local_ip, *remote_ip;
+ const struct var_expand_table *var_expand_table;
+ /* error during initialization */
+ const char *error;
+
+ const struct mail_user_settings *unexpanded_set;
+ struct mail_user_settings *set;
struct mail_namespace *namespaces;
/* Module-specific contexts. See mail_storage_module_id. */
/* User is an administrator. Allow operations not normally allowed
for other people. */
unsigned int admin:1;
+ /* mail_user_init() has been called */
+ unsigned int initialized:1;
};
struct mail_user_module_register {
void mail_users_init(const char *auth_socket_path, bool debug);
void mail_users_deinit(void);
-struct mail_user *mail_user_init(const char *username);
+struct mail_user *mail_user_alloc(const char *username,
+ const struct mail_user_settings *set);
+/* Returns -1 if settings were invalid. */
+int mail_user_init(struct mail_user *user, const char **error_r);
+
void mail_user_ref(struct mail_user *user);
void mail_user_unref(struct mail_user **user);
/* Find another user from the given user's namespaces. */
struct mail_user *mail_user_find(struct mail_user *user, const char *name);
+/* Specify mail location %variable expansion data. */
+void mail_user_set_vars(struct mail_user *user, uid_t uid, const char *service,
+ const struct ip_addr *local_ip,
+ const struct ip_addr *remote_ip);
+/* Return %variable expansion table for the user. */
+const struct var_expand_table *
+mail_user_var_expand_table(struct mail_user *user);
+
/* Specify the user's home directory. This should be called also when it's
known that the user doesn't have a home directory to avoid the internal
lookup. */
#include "mail-namespace.h"
#include "mailbox-list.h"
+#include "mail-storage-settings.h"
struct dirent;
struct imap_match_glob;
pool_t pool;
struct mail_namespace *ns;
struct mailbox_list_settings set;
+ const struct mail_storage_settings *mail_set;
enum mailbox_list_flags flags;
/* -1 if not set yet. use mailbox_list_get_permissions() to set them */
*set->subscription_fname != '\0');
list->ns = ns;
+ list->mail_set = ns->mail_set;
list->flags = flags;
list->file_create_mode = (mode_t)-1;
list->file_create_gid = (gid_t)-1;
list->set.mail_storage_flags = set->mail_storage_flags;
list->set.lock_method = set->lock_method;
- if ((flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+ if (ns->mail_set->mail_debug) {
i_info("%s: root=%s, index=%s, control=%s, inbox=%s",
list->name,
list->set.root_dir == NULL ? "" : list->set.root_dir,
if (!ENOTFOUND(errno)) {
mailbox_list_set_critical(list, "stat(%s) failed: %m",
path);
- } else if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+ } else if (list->mail_set->mail_debug) {
i_info("Namespace %s: Permission lookup failed from %s",
list->ns->prefix, path);
}
list->file_create_gid = st.st_gid;
}
- if ((list->flags & MAILBOX_LIST_FLAG_DEBUG) != 0) {
+ if (list->mail_set->mail_debug) {
i_info("Namespace %s: Using permissions from %s: "
"mode=0%o gid=%ld", list->ns->prefix, path,
(int)list->file_create_mode,
bool mailbox_list_try_get_absolute_path(struct mailbox_list *list,
const char **name)
{
- if ((list->flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) == 0)
+ if (!list->mail_set->mail_full_filesystem_access)
return FALSE;
if (**name == '/')
};
enum mailbox_list_flags {
- /* Print debugging information while initializing the driver */
- MAILBOX_LIST_FLAG_DEBUG = 0x01,
- /* Allow full filesystem access with absolute or relative paths. */
- MAILBOX_LIST_FLAG_FULL_FS_ACCESS = 0x04,
- /* Rely on O_EXCL when creating dotlocks */
- MAILBOX_LIST_FLAG_DOTLOCK_USE_EXCL = 0x08,
/* Mailboxes are files, not directories. */
- MAILBOX_LIST_FLAG_MAILBOX_FILES = 0x10,
- /* Flush NFS attribute cache when needed */
- MAILBOX_LIST_FLAG_NFS_FLUSH = 0x20
+ MAILBOX_LIST_FLAG_MAILBOX_FILES = 0x01
};
enum mailbox_info_flags {
ARRAY_DEFINE_TYPE(string, char *);
ARRAY_DEFINE_TYPE(const_string, const char *);
ARRAY_DEFINE_TYPE(uint32_t, uint32_t);
+ARRAY_DEFINE_TYPE(void_array, void *);
#endif
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-auth \
-DPKG_RUNDIR=\""$(rundir)"\" \
-DPKG_STATEDIR=\""$(statedir)"\" \
- -DSBINDIR=\""$(sbindir)"\"
+ -DSBINDIR=\""$(sbindir)"\" \
+ -DSSLDIR=\""$(ssldir)\""
liblogin_common_a_SOURCES = \
client-common.c \
login-proxy.c \
+ login-settings.c \
main.c \
master.c \
sasl-server.c \
noinst_HEADERS = \
client-common.h \
login-proxy.h \
+ login-settings.h \
common.h \
master.h \
sasl-server.h \
memcpy(tab, static_tab, sizeof(static_tab));
str = t_str_new(256);
- for (e = log_format_elements; *e != NULL; e++) {
+ for (e = login_settings->log_format_elements_split; *e != NULL; e++) {
for (p = *e; *p != '\0'; p++) {
if (*p != '%' || p[1] == '\0')
continue;
tab[1].value = msg;
str_truncate(str, 0);
- var_expand(str, log_format, tab);
+ var_expand(str, login_settings->login_log_format, tab);
return str_c(str);
}
struct ip_addr net_ip;
unsigned int bits;
- if (trusted_networks == NULL)
+ if (login_settings->login_trusted_networks == NULL)
return FALSE;
- net = t_strsplit_spaces(trusted_networks, ", ");
+ net = t_strsplit_spaces(login_settings->login_trusted_networks, ", ");
for (; *net != NULL; net++) {
if (net_parse_range(*net, &net_ip, &bits) < 0) {
i_error("login_trusted_networks: "
const char *client_get_extra_disconnect_reason(struct client *client)
{
- if (ssl_require_client_cert && client->proxy != NULL) {
+ if (login_settings->ssl_require_client_cert && client->proxy != NULL) {
if (ssl_proxy_has_broken_client_cert(client->proxy))
return "(client sent an invalid cert)";
if (!ssl_proxy_has_valid_client_cert(client->proxy))
/* some auth attempts without SSL/TLS */
if (client->auth_tried_disabled_plaintext)
return "(tried to use disabled plaintext auth)";
- if (ssl_require_client_cert)
+ if (login_settings->ssl_require_client_cert)
return "(cert required, client didn't start TLS)";
return t_strdup_printf("(auth failed, %u attempts)",
#define COMMON_H
#include "lib.h"
+#include "login-settings.h"
/* Used only for string sanitization */
#define MAX_MECH_NAME 64
extern const char *login_protocol;
-extern bool disable_plaintext_auth, process_per_connection;
-extern bool verbose_proctitle, verbose_ssl, verbose_auth, auth_debug;
-extern bool ssl_required, ssl_require_client_cert;
-extern const char *greeting, *log_format;
-extern const char *const *log_format_elements;
-extern const char *capability_string;
-extern const char *trusted_networks;
-extern unsigned int max_connections;
-extern unsigned int login_process_uid;
extern struct auth_client *auth_client;
extern bool closing_down;
+extern unsigned int login_process_uid;
+
+extern struct login_settings *login_settings;
void main_ref(void);
void main_unref(void);
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "login-settings.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct login_settings, name), NULL }
+
+static struct setting_define login_setting_defines[] = {
+ DEF(SET_STR, login_dir),
+ DEF(SET_BOOL, login_chroot),
+ DEF(SET_STR, login_trusted_networks),
+ DEF(SET_STR, login_greeting),
+ DEF(SET_STR, login_log_format_elements),
+ DEF(SET_STR, login_log_format),
+
+ DEF(SET_BOOL, login_process_per_connection),
+ DEF(SET_STR, capability_string),
+
+ DEF(SET_ENUM, ssl),
+ DEF(SET_STR, ssl_ca_file),
+ DEF(SET_STR, ssl_cert_file),
+ DEF(SET_STR, ssl_key_file),
+ DEF(SET_STR, ssl_key_password),
+ DEF(SET_STR, ssl_parameters_file),
+ DEF(SET_STR, ssl_cipher_list),
+ DEF(SET_STR, ssl_cert_username_field),
+ DEF(SET_BOOL, ssl_verify_client_cert),
+ DEF(SET_BOOL, ssl_require_client_cert),
+ DEF(SET_BOOL, ssl_username_from_cert),
+ DEF(SET_BOOL, verbose_ssl),
+
+ DEF(SET_BOOL, disable_plaintext_auth),
+ DEF(SET_BOOL, verbose_auth),
+ DEF(SET_BOOL, auth_debug),
+ DEF(SET_BOOL, verbose_proctitle),
+
+ DEF(SET_UINT, login_max_connections),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct login_settings login_default_settings = {
+ MEMBER(login_dir) "login",
+ MEMBER(login_chroot) TRUE,
+ MEMBER(login_trusted_networks) "",
+ MEMBER(login_greeting) PACKAGE" ready.",
+ MEMBER(login_log_format_elements) "user=<%u> method=%m rip=%r lip=%l %c",
+ MEMBER(login_log_format) "%$: %s",
+
+ MEMBER(login_process_per_connection) TRUE,
+ MEMBER(capability_string) NULL,
+
+ MEMBER(ssl) "yes:no:required",
+ MEMBER(ssl_ca_file) "",
+ MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
+ MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem",
+ MEMBER(ssl_key_password) "",
+ MEMBER(ssl_parameters_file) "ssl-parameters.dat",
+ MEMBER(ssl_cipher_list) "ALL:!LOW:!SSLv2",
+ MEMBER(ssl_cert_username_field) "commonName",
+ MEMBER(ssl_verify_client_cert) FALSE,
+ MEMBER(ssl_require_client_cert) FALSE,
+ MEMBER(ssl_username_from_cert) FALSE,
+ MEMBER(verbose_ssl) FALSE,
+
+ MEMBER(disable_plaintext_auth) TRUE,
+ MEMBER(verbose_auth) FALSE,
+ MEMBER(auth_debug) FALSE,
+ MEMBER(verbose_proctitle) FALSE,
+
+ MEMBER(login_max_connections) 256
+};
+
+struct setting_parser_info login_setting_parser_info = {
+ MEMBER(defines) login_setting_defines,
+ MEMBER(defaults) &login_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct login_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+static int ssl_settings_check(struct login_settings *set ATTR_UNUSED)
+{
+#ifndef HAVE_SSL
+ i_error("SSL support not compiled in but ssl_disable=no");
+ return FALSE;
+#else
+ if (*set->ssl_cert_file == '\0') {
+ i_error("ssl_cert_file not set");
+ return FALSE;
+ }
+ if (access(set->ssl_cert_file, R_OK) < 0) {
+ i_error("ssl_cert_file: access(%s) failed: %m",
+ set->ssl_cert_file);
+ return FALSE;
+ }
+
+ if (*set->ssl_key_file == '\0') {
+ i_error("ssl_key_file not set");
+ return FALSE;
+ }
+ if (access(set->ssl_key_file, R_OK) < 0) {
+ i_error("ssl_key_file: access(%s) failed: %m",
+ set->ssl_key_file);
+ return FALSE;
+ }
+
+ if (*set->ssl_ca_file != '\0' &&
+ access(set->ssl_ca_file, R_OK) < 0) {
+ i_error("ssl_ca_file: access(%s) failed: %m",
+ set->ssl_ca_file);
+ return FALSE;
+ }
+
+ if (set->ssl_verify_client_cert && *set->ssl_ca_file == '\0') {
+ i_error("ssl_verify_client_cert set, but ssl_ca_file not");
+ return FALSE;
+ }
+ return TRUE;
+#endif
+}
+
+static void login_settings_check(struct login_settings *set)
+{
+ if (strcmp(set->ssl, "no") == 0) {
+ /* disabled */
+ } else if (strcmp(set->ssl, "yes") == 0) {
+ if (!ssl_settings_check(set))
+ set->ssl = "no";
+ } else if (strcmp(set->ssl, "required") == 0) {
+ if (!ssl_settings_check(set))
+ i_fatal("Couldn't initialize ssl with ssl=required");
+ set->disable_plaintext_auth = TRUE;
+ } else {
+ i_fatal("Unknown ssl setting value: %s", set->ssl);
+ }
+
+ set->log_format_elements_split =
+ t_strsplit(set->login_log_format_elements, " ");
+
+ if (set->ssl_require_client_cert || set->ssl_username_from_cert) {
+ /* if we require valid cert, make sure we also ask for it */
+ set->ssl_verify_client_cert = TRUE;
+ }
+ if (set->login_max_connections < 1)
+ i_fatal("login_max_connections must be at least 1");
+}
+
+struct login_settings *login_settings_read(void)
+{
+ struct setting_parser_context *parser;
+ struct login_settings *set;
+
+ if (settings_pool == NULL)
+ settings_pool = pool_alloconly_create("settings pool", 512);
+ else
+ p_clear(settings_pool);
+
+ parser = settings_parser_init(settings_pool,
+ &login_setting_parser_info,
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+ if (settings_parse_environ(parser) < 0) {
+ i_fatal("Error reading configuration: %s",
+ settings_parser_get_error(parser));
+ }
+
+ set = settings_parser_get(parser);
+ settings_parser_deinit(&parser);
+ login_settings_check(set);
+ return set;
+}
--- /dev/null
+#ifndef __LOGIN_SETTINGS_H
+#define __LOGIN_SETTINGS_H
+
+struct login_settings {
+ const char *login_dir;
+ bool login_chroot;
+ const char *login_trusted_networks;
+ const char *login_greeting;
+ const char *login_log_format_elements, *login_log_format;
+
+ bool login_process_per_connection;
+ const char *capability_string;
+
+ const char *ssl;
+ const char *ssl_ca_file;
+ const char *ssl_cert_file;
+ const char *ssl_key_file;
+ const char *ssl_key_password;
+ const char *ssl_parameters_file;
+ const char *ssl_cipher_list;
+ const char *ssl_cert_username_field;
+ bool ssl_verify_client_cert;
+ bool ssl_require_client_cert;
+ bool ssl_username_from_cert;
+ bool verbose_ssl;
+
+ bool disable_plaintext_auth;
+ bool verbose_auth;
+ bool auth_debug;
+ bool verbose_proctitle;
+
+ unsigned int login_max_connections;
+
+ /* generated: */
+ const char *const *log_format_elements_split;
+};
+
+struct login_settings *login_settings_read(void);
+
+#endif
#include <unistd.h>
#include <syslog.h>
-bool disable_plaintext_auth, process_per_connection;
-bool verbose_proctitle, verbose_ssl, verbose_auth, auth_debug;
-bool ssl_required, ssl_require_client_cert;
-const char *greeting, *log_format;
-const char *const *log_format_elements;
-const char *trusted_networks;
-unsigned int max_connections;
+struct login_settings *login_settings;
unsigned int login_process_uid;
struct auth_client *auth_client;
bool closing_down;
client->remote_port = remote_port;
client->local_port = local_port;
- if (process_per_connection) {
+ if (login_settings->login_process_per_connection) {
closing_down = TRUE;
main_listen_stop();
}
client->local_port = local_port;
}
- if (process_per_connection) {
+ if (login_settings->login_process_per_connection) {
closing_down = TRUE;
main_listen_stop();
}
}
current_count = ssl_proxy_get_count() + login_proxy_get_count();
- if (current_count >= max_connections) {
+ if (current_count >= login_settings->login_max_connections) {
/* can't accept any more connections until existing proxies
get destroyed */
return;
void connection_queue_add(unsigned int connection_count)
{
+ unsigned int max_connections = login_settings->login_max_connections;
unsigned int current_count;
- if (process_per_connection)
+ if (login_settings->login_process_per_connection)
return;
current_count = clients_get_count() + ssl_proxy_get_count() +
{
const char *value;
+ login_settings = login_settings_read();
+
if (!is_inetd)
i_set_failure_internal();
else {
if (chdir(value) < 0)
i_error("chdir(%s) failed: %m", value);
+
/* Initialize SSL proxy so it can read certificate and private
key file. */
random_init();
listen_count = value == NULL ? 0 : atoi(value);
value = getenv("SSL_LISTEN_FDS");
ssl_listen_count = value == NULL ? 0 : atoi(value);
- value = getenv("MAX_CONNECTIONS");
- max_connections = value == NULL ? 1 : strtoul(value, NULL, 10);
/* set the number of fds we want to use. it may get increased or
decreased. leave a couple of extra fds for auth sockets and such.
normal connections each use one fd, but SSL connections use two */
*max_fds_r = LOGIN_MASTER_SOCKET_FD + 16 +
- listen_count + ssl_listen_count + max_connections*2;
+ listen_count + ssl_listen_count +
+ login_settings->login_max_connections*2;
restrict_fd_limit(*max_fds_r);
/* Refuse to run as root - we should never need it and it's
lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
lib_signals_ignore(SIGPIPE, TRUE);
- process_per_connection = getenv("PROCESS_PER_CONNECTION") != NULL;
- verbose_proctitle = getenv("VERBOSE_PROCTITLE") != NULL;
- verbose_ssl = getenv("VERBOSE_SSL") != NULL;
- verbose_auth = getenv("VERBOSE_AUTH") != NULL;
- auth_debug = getenv("AUTH_DEBUG") != NULL;
- ssl_required = getenv("SSL_REQUIRED") != NULL;
- ssl_require_client_cert = getenv("SSL_REQUIRE_CLIENT_CERT") != NULL;
- disable_plaintext_auth = ssl_required ||
- getenv("DISABLE_PLAINTEXT_AUTH") != NULL;
-
- greeting = getenv("GREETING");
- if (greeting == NULL)
- greeting = PACKAGE" ready.";
-
- value = getenv("LOG_FORMAT_ELEMENTS");
- if (value == NULL)
- value = "user=<%u> method=%m rip=%r lip=%l %c : %$";
- log_format_elements = t_strsplit(value, " ");
-
- log_format = getenv("LOG_FORMAT");
- if (log_format == NULL)
- log_format = "%$: %s";
-
- trusted_networks = getenv("TRUSTED_NETWORKS");
-
value = getenv("PROCESS_UID");
if (value == NULL)
i_fatal("BUG: PROCESS_UID environment not given");
if (login_process_uid == 0)
i_fatal("BUG: PROCESS_UID environment is 0");
- /* capability default is set in imap/pop3-login */
- value = getenv("CAPABILITY_STRING");
- if (value != NULL && *value != '\0')
- capability_string = value;
-
closing_down = FALSE;
main_refcount = 0;
{
struct client *client;
- if (reply->tag == 0 && !process_per_connection) {
+ if (reply->tag == 0 && !login_settings->login_process_per_connection) {
/* this means we have to start listening again.
we've reached maximum number of login processes. */
main_listen_start();
return;
}
- if (!client->secured && disable_plaintext_auth &&
+ if (!client->secured && login_settings->disable_plaintext_auth &&
(mech->flags & MECH_SEC_PLAINTEXT) != 0) {
sasl_server_auth_failed(client,
"Plaintext authentication disabled.");
{
i_assert(client->authenticating);
- if (verbose_auth && reason != NULL) {
+ if (login_settings->verbose_auth && reason != NULL) {
const char *auth_name =
str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
client_syslog(client,
#include "network.h"
#include "ostream.h"
#include "read-full.h"
+#include "safe-memset.h"
#include "llist.h"
#include "ssl-proxy.h"
#include <openssl/err.h>
#include <openssl/rand.h>
-#define DOVECOT_SSL_DEFAULT_CIPHER_LIST "ALL:!LOW:!SSLv2"
/* Check every 30 minutes if parameters file has been updated */
#define SSL_PARAMFILE_CHECK_INTERVAL (60*30)
proxy = SSL_get_ex_data(ssl, extdata_index);
proxy->cert_received = TRUE;
- if (verbose_ssl || (verbose_auth && !preverify_ok)) {
+ if (login_settings->verbose_ssl ||
+ (login_settings->verbose_auth && !preverify_ok)) {
char buf[1024];
X509_NAME *subject;
void ssl_proxy_init(void)
{
static char dovecot[] = "dovecot";
- const char *cafile, *certfile, *keyfile, *cipher_list, *username_field;
- char *password;
+ const struct login_settings *set = login_settings;
unsigned char buf;
+ char *password;
unsigned long err;
- memset(&ssl_params, 0, sizeof(ssl_params));
-
- cafile = getenv("SSL_CA_FILE");
- certfile = getenv("SSL_CERT_FILE");
- keyfile = getenv("SSL_KEY_FILE");
- ssl_params.fname = getenv("SSL_PARAM_FILE");
- password = getenv("SSL_KEY_PASSWORD");
-
- if (certfile == NULL || keyfile == NULL || ssl_params.fname == NULL) {
- /* SSL support is disabled */
+ if (strcmp(set->ssl, "no") == 0)
return;
- }
CRYPTO_set_mem_functions(ssl_clean_malloc, ssl_clean_realloc,
ssl_clean_free);
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL);
- cipher_list = getenv("SSL_CIPHER_LIST");
- if (cipher_list == NULL)
- cipher_list = DOVECOT_SSL_DEFAULT_CIPHER_LIST;
- if (SSL_CTX_set_cipher_list(ssl_ctx, cipher_list) != 1) {
+ if (SSL_CTX_set_cipher_list(ssl_ctx, set->ssl_cipher_list) != 1) {
i_fatal("Can't set cipher list to '%s': %s",
- cipher_list, ssl_last_error());
+ set->ssl_cipher_list, ssl_last_error());
}
- if (cafile != NULL) {
- if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, NULL) != 1) {
+ if (*set->ssl_ca_file != '\0') {
+ if (SSL_CTX_load_verify_locations(ssl_ctx, set->ssl_ca_file,
+ NULL) != 1) {
i_fatal("Can't load CA file %s: %s",
- cafile, ssl_last_error());
+ set->ssl_ca_file, ssl_last_error());
}
}
- if (SSL_CTX_use_certificate_chain_file(ssl_ctx, certfile) != 1) {
+ if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
+ set->ssl_cert_file) != 1) {
err = ERR_peek_error();
if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
i_fatal("Can't load certificate file %s: %s",
- certfile, ssl_last_error());
- } else if (is_pem_key_file(certfile)) {
+ set->ssl_cert_file, ssl_last_error());
+ } else if (is_pem_key_file(set->ssl_cert_file)) {
i_fatal("Can't load certificate file %s: "
"The file contains a private key "
"(you've mixed ssl_cert_file and ssl_key_file settings)",
- certfile);
+ set->ssl_cert_file);
} else {
i_fatal("Can't load certificate file %s: "
"The file doesn't contain a certificate.",
- certfile);
+ set->ssl_cert_file);
}
}
+ password = t_strdup_noconst(set->ssl_key_password);
SSL_CTX_set_default_passwd_cb(ssl_ctx, pem_password_callback);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, password);
- if (SSL_CTX_use_PrivateKey_file(ssl_ctx, keyfile,
+ if (SSL_CTX_use_PrivateKey_file(ssl_ctx, set->ssl_key_file,
SSL_FILETYPE_PEM) != 1) {
i_fatal("Can't load private key file %s: %s",
- keyfile, ssl_last_error());
+ set->ssl_key_file, ssl_last_error());
}
+ safe_memset(password, 0, strlen(password));
if (SSL_CTX_need_tmp_RSA(ssl_ctx))
SSL_CTX_set_tmp_rsa_callback(ssl_ctx, ssl_gen_rsa_key);
SSL_CTX_set_tmp_dh_callback(ssl_ctx, ssl_tmp_dh_callback);
- if (verbose_ssl)
+ if (set->verbose_ssl)
SSL_CTX_set_info_callback(ssl_ctx, ssl_info_callback);
- if (getenv("SSL_VERIFY_CLIENT_CERT") != NULL) {
+ if (set->ssl_verify_client_cert) {
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
X509_STORE *store;
SSL_VERIFY_CLIENT_ONCE,
ssl_verify_client_cert);
SSL_CTX_set_client_CA_list(ssl_ctx,
- SSL_load_client_CA_file(cafile));
+ SSL_load_client_CA_file(set->ssl_ca_file));
}
- username_field = getenv("SSL_CERT_USERNAME_FIELD");
- if (username_field == NULL)
- ssl_username_nid = NID_commonName;
- else {
- ssl_username_nid = OBJ_txt2nid(username_field);
- if (ssl_username_nid == NID_undef) {
- i_fatal("Invalid ssl_cert_username_field: %s",
- username_field);
- }
+ ssl_username_nid = OBJ_txt2nid(set->ssl_cert_username_field);
+ if (ssl_username_nid == NID_undef) {
+ i_fatal("Invalid ssl_cert_username_field: %s",
+ set->ssl_cert_username_field);
}
/* PRNG initialization might want to use /dev/urandom, make sure it
-DPKG_RUNDIR=\""$(rundir)"\" \
-DPKG_STATEDIR=\""$(statedir)"\" \
-DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \
+ -DBINDIR=\""$(bindir)"\" \
-DMODULEDIR=\""$(moduledir)"\" \
-DSSLDIR=\""$(ssldir)\""
log.c \
login-process.c \
mail-process.c \
- main.c \
master-settings.c \
+ main.c \
syslog-util.c \
ssl-init.c \
sysinfo-get.c
ssl-init.h \
sysinfo-get.h
-EXTRA_DIST = \
- master-settings-defs.c
-
ssl_build_param_SOURCES = \
ssl-init-main.c \
ssl-init-openssl.c \
/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
#include "common.h"
+#include "array.h"
#include "hash.h"
#include "ioloop.h"
#include "env-util.h"
struct auth_process_group *next;
int listen_fd;
- struct auth_settings *set;
+ const struct master_settings *master_set;
+ const struct master_auth_settings *set;
unsigned int process_count;
struct auth_process *processes;
path = t_strdup_printf("%s/auth-worker.%s",
*group->set->chroot != '\0' ?
group->set->chroot :
- group->set->parent->defaults->base_dir,
+ group->master_set->base_dir,
dec2str(pid));
p->worker_listen_fd =
unix_socket_create(path, 0600, group->set->uid,
path = t_strdup_printf("%s/auth-worker.%s",
*p->group->set->chroot != '\0' ?
p->group->set->chroot :
- p->group->set->parent->defaults->base_dir,
+ p->group->master_set->base_dir,
dec2str(p->pid));
(void)unlink(path);
i_free(p);
}
-static void
-socket_settings_env_put(const char *env_base, struct socket_settings *set)
-{
- if (!set->used)
- return;
-
- env_put(t_strdup_printf("%s=%s", env_base, set->path));
- if (set->mode != 0)
- env_put(t_strdup_printf("%s_MODE=%o", env_base, set->mode));
- if (*set->user != '\0')
- env_put(t_strdup_printf("%s_USER=%s", env_base, set->user));
- if (*set->group != '\0')
- env_put(t_strdup_printf("%s_GROUP=%s", env_base, set->group));
-}
-
static int connect_auth_socket(struct auth_process_group *group,
const char *path)
{
return 0;
}
-static void auth_set_environment(struct auth_settings *set)
+static void auth_set_environment(const struct master_settings *master_set,
+ const struct master_auth_settings *set)
{
- struct auth_socket_settings *as;
- struct auth_passdb_settings *ap;
- struct auth_userdb_settings *au;
- const char *str;
- int i;
+ master_settings_export_to_env(master_set);
/* setup access environment */
restrict_access_set_env(set->user, set->uid, set->gid,
/* set other environment */
env_put("DOVECOT_MASTER=1");
env_put(t_strconcat("AUTH_NAME=", set->name, NULL));
- env_put(t_strconcat("MECHANISMS=", set->mechanisms, NULL));
- env_put(t_strconcat("REALMS=", set->realms, NULL));
- env_put(t_strconcat("DEFAULT_REALM=", set->default_realm, NULL));
- env_put(t_strconcat("USERNAME_CHARS=", set->username_chars, NULL));
- env_put(t_strconcat("ANONYMOUS_USERNAME=",
- set->anonymous_username, NULL));
- env_put(t_strconcat("USERNAME_TRANSLATION=",
- set->username_translation, NULL));
- env_put(t_strconcat("USERNAME_FORMAT=", set->username_format, NULL));
- env_put(t_strconcat("MASTER_USER_SEPARATOR=",
- set->master_user_separator, NULL));
- env_put(t_strdup_printf("CACHE_SIZE=%u", set->cache_size));
- env_put(t_strdup_printf("CACHE_TTL=%u", set->cache_ttl));
- env_put(t_strdup_printf("CACHE_NEGATIVE_TTL=%u",
- set->cache_negative_ttl));
-
- for (ap = set->passdbs, i = 1; ap != NULL; ap = ap->next, i++) {
- env_put(t_strdup_printf("PASSDB_%u_DRIVER=%s", i, ap->driver));
- if (ap->args != NULL) {
- env_put(t_strdup_printf("PASSDB_%u_ARGS=%s",
- i, ap->args));
- }
- if (ap->deny)
- env_put(t_strdup_printf("PASSDB_%u_DENY=1", i));
- if (ap->pass)
- env_put(t_strdup_printf("PASSDB_%u_PASS=1", i));
- if (ap->master)
- env_put(t_strdup_printf("PASSDB_%u_MASTER=1", i));
- }
- for (au = set->userdbs, i = 1; au != NULL; au = au->next, i++) {
- env_put(t_strdup_printf("USERDB_%u_DRIVER=%s", i, au->driver));
- if (au->args != NULL) {
- env_put(t_strdup_printf("USERDB_%u_ARGS=%s",
- i, au->args));
- }
- }
-
- for (as = set->sockets, i = 1; as != NULL; as = as->next, i++) {
- if (strcmp(as->type, "listen") != 0)
- continue;
+ restrict_process_size(set->process_size, (unsigned int)-1);
+}
- str = t_strdup_printf("AUTH_%u", i);
- socket_settings_env_put(str, &as->client);
- socket_settings_env_put(t_strconcat(str, "_MASTER", NULL),
- &as->master);
- }
+static const struct master_auth_socket_settings *
+get_connect_socket(const struct master_auth_settings *auth_set)
+{
+ struct master_auth_socket_settings *const *as;
+ unsigned int count;
- if (set->verbose)
- env_put("VERBOSE=1");
- if (set->debug)
- env_put("VERBOSE_DEBUG=1");
- if (set->debug_passwords)
- env_put("VERBOSE_DEBUG_PASSWORDS=1");
- if (set->ssl_require_client_cert)
- env_put("SSL_REQUIRE_CLIENT_CERT=1");
- if (set->ssl_username_from_cert)
- env_put("SSL_USERNAME_FROM_CERT=1");
- if (set->use_winbind)
- env_put("USE_WINBIND=1");
- if (*set->krb5_keytab != '\0') {
- /* Environment may be used by Kerberos 5 library directly,
- although we also try to use it directly as well */
- env_put(t_strconcat("KRB5_KTNAME=", set->krb5_keytab, NULL));
- }
- if (*set->gssapi_hostname != '\0') {
- env_put(t_strconcat("GSSAPI_HOSTNAME=",
- set->gssapi_hostname, NULL));
- }
- env_put(t_strconcat("WINBIND_HELPER_PATH=",
- set->winbind_helper_path, NULL));
- env_put(t_strdup_printf("FAILURE_DELAY=%u", set->failure_delay));
+ if (!array_is_created(&auth_set->sockets))
+ return NULL;
- restrict_process_size(set->process_size, (unsigned int)-1);
+ as = array_get(&auth_set->sockets, &count);
+ if (count > 0 && strcmp(as[0]->type, "connect") == 0)
+ return as[0];
+ else
+ return NULL;
}
static int create_auth_process(struct auth_process_group *group)
{
- struct auth_socket_settings *as;
+ const struct master_auth_socket_settings *as;
+ struct master_auth_socket_unix_settings *const *masters;
const char *prefix, *executable;
struct log_io *log;
pid_t pid;
+ unsigned int count;
int fd[2], log_fd, i;
/* see if this is a connect socket */
- as = group->set->sockets;
- if (as != NULL && strcmp(as->type, "connect") == 0)
- return connect_auth_socket(group, as->master.path);
+ as = get_connect_socket(group->set);
+ if (as != NULL) {
+ masters = array_get(&as->masters, &count);
+ if (count > 0)
+ return connect_auth_socket(group, masters[0]->path);
+ }
/* create communication to process with a socket pair */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
if (dup2(log_fd, 2) < 0)
i_fatal("dup2(stderr) failed: %m");
- child_process_init_env();
+ child_process_init_env(group->master_set);
if (group->listen_fd != 3) {
if (dup2(group->listen_fd, 3) < 0)
for (i = 0; i <= 2; i++)
fd_close_on_exec(i, FALSE);
- auth_set_environment(group->set);
+ auth_set_environment(group->master_set, group->set);
env_put(t_strdup_printf("AUTH_WORKER_PATH=%s/auth-worker.%s",
*group->set->chroot != '\0' ? "" :
- group->set->parent->defaults->base_dir,
+ group->master_set->base_dir,
dec2str(getpid())));
- env_put(t_strdup_printf("AUTH_WORKER_MAX_COUNT=%u",
- group->set->worker_max_count));
/* make sure we don't leak syslog fd, but do it last so that
any errors above will be logged */
fd_close_on_exec(i, FALSE);
fd_close_on_exec(4, FALSE);
- child_process_init_env();
- auth_set_environment(process->group->set);
+ child_process_init_env(process->group->master_set);
+ auth_set_environment(process->group->master_set, process->group->set);
/* make sure we don't leak syslog fd, but do it last so that
any errors above will be logged */
return NULL;
}
-static void auth_process_group_create(struct auth_settings *auth_set)
+static void auth_process_group_create(struct master_settings *set,
+ struct master_auth_settings *auth_set)
{
struct auth_process_group *group;
const char *path;
group = i_new(struct auth_process_group, 1);
+ group->master_set = set;
group->set = auth_set;
group->next = process_groups;
process_groups = group;
- if (auth_set->sockets != NULL &&
- strcmp(auth_set->sockets->type, "connect") == 0)
+ if (get_connect_socket(auth_set) != NULL)
return;
- path = t_strconcat(auth_set->parent->defaults->login_dir, "/",
- auth_set->name, NULL);
+ path = t_strconcat(set->login_dir, "/", auth_set->name, NULL);
group->listen_fd = unix_socket_create(path, 0660, master_uid,
- auth_set->parent->login_gid, 128);
+ set->server->login_gid, 128);
if (group->listen_fd == -1)
i_fatal("Couldn't create auth process listener");
group->processes = next;
}
- path = t_strconcat(group->set->parent->defaults->login_dir, "/",
+ path = t_strconcat(group->master_set->login_dir, "/",
group->set->name, NULL);
(void)unlink(path);
have_initialized_auth_processes = FALSE;
}
-static void auth_process_groups_create(struct server_settings *server)
+static void auth_process_groups_create(struct master_settings *set)
{
- 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);
+ struct master_auth_settings *const *auth_sets;
+ unsigned int i, count;
- server = server->next;
- }
+ auth_sets = array_get(&set->auths, &count);
+ for (i = 0; i < count; i++)
+ auth_process_group_create(set, auth_sets[i]);
}
static void auth_processes_stall(void)
if (process_groups == NULL) {
/* first time here, create the groups */
- auth_process_groups_create(settings_root);
+ auth_process_groups_create(master_set->defaults);
}
for (group = process_groups; group != NULL; group = group->next) {
hash_table_remove(processes, POINTER_CAST(pid));
}
-void child_process_init_env(void)
+void child_process_init_env(const struct master_settings *set)
{
int facility;
if (env_tz != NULL)
env_put(t_strconcat("TZ=", env_tz, NULL));
- if (settings_root == NULL ||
- !syslog_facility_find(settings_root->defaults->syslog_facility,
- &facility))
+ if (master_set == NULL ||
+ !syslog_facility_find(set->syslog_facility, &facility))
facility = LOG_MAIL;
env_put(t_strdup_printf("SYSLOG_FACILITY=%d", facility));
- if (settings_root != NULL && !settings_root->defaults->version_ignore)
+ if (master_set != NULL && !set->version_ignore)
env_put("DOVECOT_VERSION="PACKAGE_VERSION);
#ifdef DEBUG
if (gdb) env_put("GDB=1");
void child_process_add(pid_t pid, struct child_process *process);
void child_process_remove(pid_t pid);
-void child_process_init_env(void);
+void child_process_init_env(const struct master_settings *set);
void client_process_exec(const char *cmd, const char *title);
void client_process_exec_argv(const char *executable, const char **argv);
for (i = 0; i <= 3; i++)
fd_close_on_exec(i, FALSE);
- child_process_init_env();
+ child_process_init_env(master_set->defaults);
env_put(t_strconcat("DICT_LISTEN_FROM_FD=",
process->listener->path, NULL));
- if (settings_root->defaults->dict_db_config != NULL) {
+ if (master_set->defaults->dict_db_config != NULL) {
env_put(t_strconcat("DB_CONFIG=",
- settings_root->defaults->dict_db_config,
+ master_set->defaults->dict_db_config,
NULL));
}
- dicts = array_get(&settings_root->dicts, &count);
+ dicts = array_get(&master_set->defaults->dicts, &count);
i_assert((count % 2) == 0);
for (i = 0; i < count; i += 2)
env_put(t_strdup_printf("DICT_%s=%s", dicts[i], dicts[i+1]));
static void dict_listener_input(struct dict_listener *listener)
{
- unsigned int i;
+ unsigned int i = 0;
int fd;
i_assert(listener->processes == NULL);
- for (i = 0; i < settings_root->defaults->dict_process_count; i++) {
- if (dict_process_create(listener) < 0)
- break;
+ if (array_is_created(&master_set->defaults->dicts)) {
+ for (i = 0; i < master_set->defaults->dict_process_count; i++) {
+ if (dict_process_create(listener) < 0)
+ break;
+ }
}
if (i > 0)
io_remove(&listener->io);
{
const char *path;
- path = t_strconcat(settings_root->defaults->base_dir,
+ path = t_strconcat(master_set->defaults->base_dir,
"/"DICT_SERVER_SOCKET_NAME, NULL);
dict_listener = dict_listener_init(path);
}
static void
-check_conflicts_set(const struct settings *set, const struct ip_addr *ip,
+check_conflicts_set(const struct master_settings *set, const struct ip_addr *ip,
unsigned int port, const char *name1, const char *name2)
{
const struct listener *listens = NULL;
static void check_conflicts(const struct ip_addr *ip, unsigned int port,
const char *proto)
{
- struct server_settings *server;
-
- for (server = settings_root; server != NULL; server = server->next) {
- if (server->imap != NULL) {
- check_conflicts_set(server->imap, ip, port,
- "imap", proto);
- }
- if (server->pop3 != NULL) {
- check_conflicts_set(server->pop3, ip, port,
- "pop3", proto);
- }
+ if (master_set->imap != NULL) {
+ check_conflicts_set(master_set->imap, ip, port,
+ "imap", proto);
+ }
+ if (master_set->pop3 != NULL) {
+ check_conflicts_set(master_set->pop3, ip, port,
+ "pop3", proto);
}
}
array_free(listens_arr);
}
-static void listen_parse_and_close_unneeded(struct settings *set)
+static void listen_parse_and_close_unneeded(struct master_settings *set)
{
const char *const *proto;
unsigned int default_port;
}
}
-static void listen_copy_old(struct settings *old_set, struct settings *new_set)
+static void listen_copy_old(struct master_settings *old_set,
+ struct master_settings *new_set)
{
if (old_set == NULL || new_set == NULL) {
if (old_set != NULL) {
}
static void
-listener_listen_missing(struct settings *set, const char *proto, bool retry)
+listener_listen_missing(struct master_settings *set,
+ const char *proto, bool retry)
{
listener_array_listen_missing(proto, &set->listens, retry);
listener_array_listen_missing(t_strconcat(proto, "s", NULL),
&set->ssl_listens, retry);
}
-void listeners_open_fds(struct server_settings *old_set, bool retry)
+void listeners_open_fds(struct master_server_settings *old_set, bool retry)
{
- struct server_settings *server;
-
- for (server = settings_root; server != NULL; server = server->next) {
- if (old_set != NULL) {
- listen_copy_old(old_set->imap, server->imap);
- listen_copy_old(old_set->pop3, server->pop3);
- }
- listen_parse_and_close_unneeded(server->imap);
- listen_parse_and_close_unneeded(server->pop3);
-
- if (old_set != NULL)
- old_set = old_set->next;
+ if (old_set != NULL) {
+ listen_copy_old(old_set->imap, master_set->imap);
+ listen_copy_old(old_set->pop3, master_set->pop3);
}
+ listen_parse_and_close_unneeded(master_set->imap);
+ listen_parse_and_close_unneeded(master_set->pop3);
- for (server = settings_root; server != NULL; server = server->next) {
- if (server->imap != NULL)
- listener_listen_missing(server->imap, "imap", retry);
- if (server->pop3 != NULL)
- listener_listen_missing(server->pop3, "pop3", retry);
- }
+ if (master_set->imap != NULL)
+ listener_listen_missing(master_set->imap, "imap", retry);
+ if (master_set->pop3 != NULL)
+ listener_listen_missing(master_set->pop3, "pop3", retry);
}
void listeners_close_fds(void)
{
- struct server_settings *server;
-
- for (server = settings_root; server != NULL; server = server->next) {
- if (server->imap != NULL) {
- listener_close_fds(&server->imap->listens);
- listener_close_fds(&server->imap->ssl_listens);
- }
- if (server->pop3 != NULL) {
- listener_close_fds(&server->pop3->listens);
- listener_close_fds(&server->pop3->ssl_listens);
- }
+ if (master_set->imap != NULL) {
+ listener_close_fds(&master_set->imap->listens);
+ listener_close_fds(&master_set->imap->ssl_listens);
+ }
+ if (master_set->pop3 != NULL) {
+ listener_close_fds(&master_set->pop3->listens);
+ listener_close_fds(&master_set->pop3->ssl_listens);
}
}
#ifndef LISTENER_H
#define LISTENER_H
-void listeners_open_fds(struct server_settings *old_set, bool retry);
+void listeners_open_fds(struct master_server_settings *old_set, bool retry);
void listeners_close_fds(void);
#endif
#include "auth-process.h"
#include "mail-process.h"
#include "master-login-interface.h"
+#include "master-settings.h"
#include "log.h"
#include "ssl-init.h"
static bool login_process_init_group(struct login_process *p);
static void login_processes_start_missing(void *context);
-static void login_group_create(struct settings *set)
+static void login_group_create(struct master_settings *set)
{
struct login_group *group;
static void login_process_groups_create(void)
{
- struct server_settings *server;
-
- 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);
- }
+ if (master_set->imap != NULL)
+ login_group_create(master_set->imap);
+ if (master_set->pop3 != NULL)
+ login_group_create(master_set->pop3);
}
static struct login_group *
-login_group_process_find(const char *name, enum mail_protocol protocol)
+login_group_process_find(enum mail_protocol protocol)
{
struct login_group *group;
login_process_groups_create();
for (group = login_groups; group != NULL; group = group->next) {
- if (strcmp(group->set->server->name, name) == 0 &&
- group->set->protocol == protocol)
+ if (group->set->protocol == protocol)
return group;
}
static bool login_process_read_group(struct login_process *p)
{
struct login_group *group;
- const char *name, *proto;
+ const char *proto;
unsigned char buf[256];
enum mail_protocol protocol;
unsigned int len;
else if (len == 0 || (size_t)ret != len)
i_error("login: Server name wasn't sent");
else {
- name = t_strndup(buf, len);
- proto = strchr(name, '/');
- if (proto == NULL) {
- proto = name;
- name = "default";
- } else {
- name = t_strdup_until(name, proto++);
- }
-
+ proto = t_strndup(buf, len);
if (strcmp(proto, "imap") == 0)
protocol = MAIL_PROTOCOL_IMAP;
else if (strcmp(proto, "pop3") == 0)
return FALSE;
}
- group = login_group_process_find(name, protocol);
+ group = login_group_process_find(protocol);
if (group == NULL) {
- i_error("login: Unknown server name '%s'", name);
+ i_error("login: No group for protocol '%s'", proto);
return FALSE;
}
static void login_process_init_env(struct login_group *group, pid_t pid)
{
- struct settings *set = group->set;
- const struct auth_settings *auth;
- bool require_cert;
+ struct master_settings *set = group->set;
- child_process_init_env();
+ child_process_init_env(group->set);
/* setup access environment - needs to be done after
clean_child_process() since it clears environment. Don't set user
env_put("DOVECOT_MASTER=1");
- if (strcmp(set->ssl, "no") != 0) {
- const char *ssl_key_password;
-
- ssl_key_password = *set->ssl_key_password != '\0' ?
- set->ssl_key_password : ssl_manual_key_password;
-
- if (*set->ssl_ca_file != '\0') {
- env_put(t_strconcat("SSL_CA_FILE=",
- set->ssl_ca_file, NULL));
- }
- if (strcmp(set->ssl, "required") == 0)
- env_put("SSL_REQUIRED=1");
- 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_PASSWORD=",
- ssl_key_password, NULL));
- env_put("SSL_PARAM_FILE="SSL_PARAMETERS_FILENAME);
- if (*set->ssl_cipher_list != '\0') {
- env_put(t_strconcat("SSL_CIPHER_LIST=",
- set->ssl_cipher_list, NULL));
- }
- env_put(t_strconcat("SSL_CERT_USERNAME_FIELD=",
- set->ssl_cert_username_field, NULL));
- if (set->ssl_verify_client_cert)
- env_put("SSL_VERIFY_CLIENT_CERT=1");
- }
-
- if (set->disable_plaintext_auth)
- env_put("DISABLE_PLAINTEXT_AUTH=1");
- if (set->verbose_proctitle)
- env_put("VERBOSE_PROCTITLE=1");
- if (set->verbose_ssl)
- env_put("VERBOSE_SSL=1");
- if (set->server->auths->verbose)
- env_put("VERBOSE_AUTH=1");
- if (set->server->auths->debug)
- env_put("AUTH_DEBUG=1");
- require_cert = TRUE;
- for (auth = set->server->auths; auth != NULL; auth = auth->next) {
- if (!auth->ssl_require_client_cert)
- require_cert = FALSE;
- }
- if (require_cert)
- env_put("SSL_REQUIRE_CLIENT_CERT=1");
-
- if (set->login_process_per_connection) {
- env_put("PROCESS_PER_CONNECTION=1");
- env_put("MAX_CONNECTIONS=1");
- } else {
- env_put(t_strdup_printf("MAX_CONNECTIONS=%u",
- set->login_max_connections));
+ master_settings_export_to_env(group->set);
+ if (ssl_manual_key_password != NULL) {
+ env_put(t_strconcat("SSL_MANUAL_KEY_PASSWORD=",
+ ssl_manual_key_password, NULL));
}
env_put(t_strconcat("PROCESS_UID=", dec2str(pid), NULL));
- env_put(t_strconcat("GREETING=", set->login_greeting, NULL));
- env_put(t_strconcat("LOG_FORMAT_ELEMENTS=",
- set->login_log_format_elements, NULL));
- env_put(t_strconcat("LOG_FORMAT=", set->login_log_format, NULL));
- env_put(t_strconcat("IMAP_ID_SEND=", set->imap_id_send, NULL));
- env_put(t_strconcat("IMAP_ID_LOG=", set->imap_id_log, NULL));
-
if (group->mail_process_type == PROCESS_TYPE_IMAP) {
- env_put(t_strconcat("CAPABILITY_STRING=",
- *set->imap_capability != '\0' ?
- set->imap_capability :
+ env_put(t_strconcat("GENERATED_CAPABILITY=",
set->imap_generated_capability, NULL));
}
- if (*set->login_trusted_networks != '\0') {
- env_put(t_strconcat("TRUSTED_NETWORKS=",
- set->login_trusted_networks, NULL));
- }
env_put(t_strconcat("LOGIN_DIR=", set->login_dir, NULL));
}
int refcount;
enum process_type mail_process_type;
- struct settings *set;
+ struct master_settings *set;
unsigned int processes;
unsigned int listening_processes;
#include "restrict-process-size.h"
#include "home-expand.h"
#include "var-expand.h"
+#include "settings-parser.h"
#include "mail-process.h"
#include "login-process.h"
#include "log.h"
i_free(group);
}
-static bool validate_uid_gid(struct settings *set, uid_t uid, gid_t gid,
+static bool validate_uid_gid(struct master_settings *set, uid_t uid, gid_t gid,
const char *user)
{
if (uid == 0) {
return TRUE;
}
-static bool validate_chroot(struct settings *set, const char *dir)
+static bool validate_chroot(struct master_settings *set, const char *dir)
{
const char *const *chroot_dirs;
var_has_key(str, 'h', "home");
}
-static const char *
-expand_mail_env(const char *env, const struct var_expand_table *table)
-{
- string_t *str;
- const char *p;
-
- str = t_str_new(256);
-
- /* it's either type:data or just data */
- p = strchr(env, ':');
- if (p != NULL) {
- while (env != p) {
- str_append_c(str, *env);
- env++;
- }
-
- str_append_c(str, *env++);
- }
-
- if (has_missing_used_home(env, table)) {
- i_fatal("userdb didn't return a home directory, "
- "but mail location used it (%%h): %s", env);
- }
-
- /* expand %vars */
- var_expand(str, env, table);
- return str_c(str);
-}
-
static void
-env_put_namespace(struct namespace_settings *ns, const char *default_location,
- const struct var_expand_table *table)
+mail_process_set_environment(struct master_settings *set,
+ const struct var_expand_table *table)
{
- const char *location;
- unsigned int i;
- string_t *str;
-
- if (default_location == NULL)
- default_location = "";
- for (i = 1; ns != NULL; i++, ns = ns->next) {
- location = *ns->location != '\0' ? ns->location :
- default_location;
- location = expand_mail_env(location, table);
- env_put(t_strdup_printf("NAMESPACE_%u=%s", i, location));
-
- if (ns->separator != NULL) {
- env_put(t_strdup_printf("NAMESPACE_%u_SEP=%s",
- i, ns->separator));
- }
- if (ns->type != NULL) {
- env_put(t_strdup_printf("NAMESPACE_%u_TYPE=%s",
- i, ns->type));
- }
- if (ns->alias_for != NULL) {
- env_put(t_strdup_printf("NAMESPACE_%u_ALIAS=%s",
- i, ns->alias_for));
- }
- if (ns->prefix != NULL) {
- /* expand variables, eg. ~%u/ can be useful */
- str = t_str_new(256);
- str_printfa(str, "NAMESPACE_%u_PREFIX=", i);
- var_expand(str, ns->prefix, table);
- env_put(str_c(str));
- }
- if (ns->inbox)
- env_put(t_strdup_printf("NAMESPACE_%u_INBOX=1", i));
- if (ns->hidden)
- env_put(t_strdup_printf("NAMESPACE_%u_HIDDEN=1", i));
- if (strcmp(ns->list, "no") != 0) {
- env_put(t_strdup_printf("NAMESPACE_%u_LIST=%s",
- i, ns->list));
- }
- if (ns->subscriptions)
- env_put(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS=1",
- i));
- }
-}
-
-static void
-mail_process_set_environment(struct settings *set, const char *mail,
- const struct var_expand_table *var_expand_table,
- bool exec_mail)
-{
- const char *const *envs;
+ const char **envs;
string_t *str;
unsigned int i, count;
- env_put(t_strconcat("MAIL_CACHE_FIELDS=",
- set->mail_cache_fields, NULL));
- env_put(t_strconcat("MAIL_NEVER_CACHE_FIELDS=",
- set->mail_never_cache_fields, NULL));
- env_put(t_strdup_printf("MAIL_CACHE_MIN_MAIL_COUNT=%u",
- set->mail_cache_min_mail_count));
- env_put(t_strdup_printf("MAILBOX_IDLE_CHECK_INTERVAL=%u",
- set->mailbox_idle_check_interval));
- env_put(t_strdup_printf("MAIL_MAX_KEYWORD_LENGTH=%u",
- set->mail_max_keyword_length));
-
- if (set->protocol == MAIL_PROTOCOL_IMAP) {
- env_put(t_strdup_printf("IMAP_MAX_LINE_LENGTH=%u",
- set->imap_max_line_length));
- if (*set->imap_capability != '\0') {
- env_put(t_strconcat("IMAP_CAPABILITY=",
- set->imap_capability, NULL));
- }
- env_put(t_strconcat("IMAP_CLIENT_WORKAROUNDS=",
- set->imap_client_workarounds, NULL));
- env_put(t_strconcat("IMAP_LOGOUT_FORMAT=",
- set->imap_logout_format, NULL));
- env_put(t_strconcat("IMAP_ID_SEND=", set->imap_id_send, NULL));
- env_put(t_strconcat("IMAP_ID_LOG=", set->imap_id_log, NULL));
- }
- if (set->protocol == MAIL_PROTOCOL_POP3) {
- env_put(t_strconcat("POP3_CLIENT_WORKAROUNDS=",
- set->pop3_client_workarounds, NULL));
- env_put(t_strconcat("POP3_LOGOUT_FORMAT=",
- set->pop3_logout_format, NULL));
- if (set->pop3_no_flag_updates)
- env_put("POP3_NO_FLAG_UPDATES=1");
- if (set->pop3_reuse_xuidl)
- env_put("POP3_REUSE_XUIDL=1");
- if (set->pop3_enable_last)
- env_put("POP3_ENABLE_LAST=1");
- if (set->pop3_lock_session)
- env_put("POP3_LOCK_SESSION=1");
- }
-
- /* We care about POP3 UIDL format in all process types */
- env_put(t_strconcat("POP3_UIDL_FORMAT=", set->pop3_uidl_format, NULL));
-
- if (set->mail_save_crlf)
- env_put("MAIL_SAVE_CRLF=1");
- if (set->mmap_disable)
- env_put("MMAP_DISABLE=1");
- if (set->dotlock_use_excl)
- env_put("DOTLOCK_USE_EXCL=1");
- if (set->fsync_disable)
- env_put("FSYNC_DISABLE=1");
- if (set->mail_nfs_storage)
- env_put("MAIL_NFS_STORAGE=1");
- if (set->mail_nfs_index)
- env_put("MAIL_NFS_INDEX=1");
- if (set->mailbox_list_index_disable)
- env_put("MAILBOX_LIST_INDEX_DISABLE=1");
- if (set->maildir_stat_dirs)
- env_put("MAILDIR_STAT_DIRS=1");
- if (set->maildir_copy_with_hardlinks)
- env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
- if (set->maildir_copy_preserve_filename)
- env_put("MAILDIR_COPY_PRESERVE_FILENAME=1");
- if (set->mail_debug)
- env_put("DEBUG=1");
- if (set->mail_full_filesystem_access)
- env_put("FULL_FILESYSTEM_ACCESS=1");
- if (set->mbox_dirty_syncs)
- env_put("MBOX_DIRTY_SYNCS=1");
- if (set->mbox_very_dirty_syncs)
- env_put("MBOX_VERY_DIRTY_SYNCS=1");
- if (set->mbox_lazy_writes)
- env_put("MBOX_LAZY_WRITES=1");
- /* when we're not certain that the log fd points to the master
- process's log pipe (dump-capability, --exec-mail), don't let
- the imap process listen for stderr since it might break
- (e.g. epoll_ctl() gives EPERM). */
- if (set->shutdown_clients && !exec_mail)
- env_put("STDERR_CLOSE_SHUTDOWN=1");
+ settings_var_expand(&master_setting_parser_info, set,
+ system_pool, table);
+
(void)umask(set->umask);
- env_put(t_strconcat("LOCK_METHOD=", set->lock_method, NULL));
- env_put(t_strconcat("MBOX_READ_LOCKS=", set->mbox_read_locks, NULL));
- env_put(t_strconcat("MBOX_WRITE_LOCKS=", set->mbox_write_locks, NULL));
- env_put(t_strdup_printf("MBOX_LOCK_TIMEOUT=%u",
- set->mbox_lock_timeout));
- env_put(t_strdup_printf("MBOX_DOTLOCK_CHANGE_TIMEOUT=%u",
- set->mbox_dotlock_change_timeout));
- env_put(t_strdup_printf("MBOX_MIN_INDEX_SIZE=%u",
- set->mbox_min_index_size));
-
- env_put(t_strdup_printf("DBOX_ROTATE_SIZE=%u",
- set->dbox_rotate_size));
- env_put(t_strdup_printf("DBOX_ROTATE_MIN_SIZE=%u",
- set->dbox_rotate_min_size));
- env_put(t_strdup_printf("DBOX_ROTATE_DAYS=%u",
- set->dbox_rotate_days));
-
- if (*set->mail_plugins != '\0') {
- env_put(t_strconcat("MAIL_PLUGIN_DIR=",
- set->mail_plugin_dir, NULL));
- env_put(t_strconcat("MAIL_PLUGINS=", set->mail_plugins, NULL));
- }
-
- /* user given environment - may be malicious. virtual_user comes from
- auth process, but don't trust that too much either. Some auth
- mechanism might allow leaving extra data there. */
- if ((mail == NULL || *mail == '\0') && *set->mail_location != '\0')
- mail = expand_mail_env(set->mail_location, var_expand_table);
- env_put(t_strconcat("MAIL=", mail, NULL));
-
- if (set->server->namespaces != NULL) {
- env_put_namespace(set->server->namespaces,
- mail, var_expand_table);
+ if (array_is_created(&set->plugin_envs))
+ envs = array_get_modifiable(&set->plugin_envs, &count);
+ else {
+ count = 0;
+ envs = NULL;
}
-
str = t_str_new(256);
- envs = array_get(&set->plugin_envs, &count);
i_assert((count % 2) == 0);
for (i = 0; i < count; i += 2) {
- str_truncate(str, 0);
- var_expand(str, envs[i+1], var_expand_table);
-
- if (has_missing_used_home(envs[i+1], var_expand_table)) {
+ if (has_missing_used_home(envs[i+1], table)) {
i_error("userdb didn't return a home directory, "
"but it's used in plugin setting %s: %s",
envs[i], envs[i+1]);
}
-
- env_put(t_strconcat(t_str_ucase(envs[i]), "=",
- str_c(str), NULL));
+ str_truncate(str, 0);
+ var_expand(str, envs[i+1], table);
+ envs[i+1] = t_strdup(str_c(str));
}
+
+ master_settings_export_to_env(set);
}
void mail_process_exec(const char *protocol, const char **args)
{
- struct server_settings *server = settings_root;
const struct var_expand_table *var_expand_table;
- struct settings *set;
+ struct master_settings *set;
const char *executable;
if (strcmp(protocol, "ext") == 0) {
/* external binary. section contains path for it. */
if (*args == NULL)
i_fatal("External binary parameter not given");
- set = server->defaults;
+ set = master_set->defaults;
executable = *args;
} else {
- const char *section = *args;
-
- if (section != NULL) {
- for (; server != NULL; server = server->next) {
- if (strcmp(server->name, section) == 0)
- break;
- }
- if (server == NULL)
- i_fatal("Section not found: '%s'", section);
- }
-
if (strcmp(protocol, "imap") == 0)
- set = server->imap;
+ set = master_set->imap;
else if (strcmp(protocol, "pop3") == 0)
- set = server->pop3;
+ set = master_set->pop3;
else
i_fatal("Unknown protocol: '%s'", protocol);
executable = set->mail_executable;
env_put(str_c(str));
}
- mail_process_set_environment(set, getenv("MAIL"), var_expand_table,
- TRUE);
+ mail_process_set_environment(set, var_expand_table);
if (args == NULL)
client_process_exec(executable, "");
else
}
enum master_login_status
-create_mail_process(enum process_type process_type, struct settings *set,
+create_mail_process(enum process_type process_type, struct master_settings *set,
const struct mail_login_request *request,
const char *user, const char *const *args,
const unsigned char *data, bool dump_capability,
log_set_prefix(log, str_c(str));
}
- child_process_init_env();
+ child_process_init_env(set);
/* move the client socket into stdin and stdout fds, log to stderr */
if (dup2(dump_capability ? null_fd : request->fd, 0) < 0)
i_fatal("chdir(/tmp) failed: %m");
}
- mail_process_set_environment(set, mail, var_expand_table,
- dump_capability);
+ mail_process_set_environment(set, var_expand_table);
/* extra args. uppercase key value. */
args = array_get(&extra_args, &count);
if (nfs_check) {
/* ideally we should check all of the namespaces,
but for now don't bother. */
- const char *mail_location = getenv("NAMESPACE_1");
+ const char *mail_location = getenv("NAMESPACE_1"); //FIXME
if (mail_location == NULL)
mail_location = getenv("MAIL");
void mail_process_exec(const char *protocol, const char **args) ATTR_NORETURN;
enum master_login_status
-create_mail_process(enum process_type process_type, struct settings *set,
+create_mail_process(enum process_type process_type, struct master_settings *set,
const struct mail_login_request *request,
const char *user, const char *const *args,
const unsigned char *data, bool dump_capability,
master_fatal_callback(enum log_type type, int status,
const char *format, va_list args)
{
- const struct settings *set = settings_root->defaults;
+ const struct master_settings *set = master_set->defaults;
const char *path, *str;
va_list args2;
int fd;
static void fatal_log_check(void)
{
- const struct settings *set = settings_root->defaults;
+ const struct master_settings *set = master_set->defaults;
const char *path;
char buf[1024];
ssize_t ret;
i_error("unlink(%s) failed: %m", path);
}
-static void auth_warning_print(const struct server_settings *set)
+static void auth_warning_print(const struct master_server_settings *set)
{
+ struct master_auth_settings *const *auths;
+ unsigned int count;
struct stat st;
auth_success_written = stat(AUTH_SUCCESS_PATH, &st) == 0;
- if (!auth_success_written && !set->auths->debug &&
+ auths = array_get(&set->defaults->auths, &count);
+ if (!auth_success_written && count > 0 && !auths[0]->debug &&
strcmp(set->defaults->protocols, "none") != 0) {
i_info("If you have trouble with authentication failures,\n"
"enable auth_debug setting. "
}
}
-static void set_logfile(struct settings *set)
+static void set_logfile(struct master_settings *set)
{
int facility;
static void settings_reload(void)
{
- struct server_settings *old_set = settings_root;
+ /* this old_set wrapping works because master settings are
+ alternatingly read using two different pools */
+ struct master_server_settings *set, *old_set = master_set;
i_warning("SIGHUP received - reloading configuration");
/* see if hostname changed */
hostpid_init();
- if (!master_settings_read(configfile, FALSE, FALSE))
+ if (master_settings_read(configfile, &set) < 0 ||
+ !master_settings_check(set, FALSE, FALSE))
i_warning("Invalid configuration, keeping old one");
else {
if (!IS_INETD())
listeners_open_fds(old_set, TRUE);
- set_logfile(settings_root->defaults);
+ set_logfile(set->defaults);
}
}
static void sig_reopen_logs(int signo ATTR_UNUSED,
void *context ATTR_UNUSED)
{
- set_logfile(settings_root->defaults);
+ set_logfile(master_set->defaults);
}
-static bool have_stderr_set(struct settings *set)
+static bool have_stderr_set(struct master_settings *set)
{
if (*set->log_path != '\0' &&
strcmp(set->log_path, "/dev/stderr") == 0)
return FALSE;
}
-static bool have_stderr(struct server_settings *server)
+static bool have_stderr(struct master_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;
- }
-
+ if (server->imap != NULL && have_stderr_set(server->imap))
+ return TRUE;
+ if (server->pop3 != NULL && have_stderr_set(server->pop3))
+ return TRUE;
return FALSE;
}
(void)close(fd);
}
+static void pid_file_check_running(const struct master_settings *set)
+{
+ const char *path;
+ char buf[32];
+ int fd;
+ ssize_t ret;
+
+ path = t_strconcat(set->base_dir, "/master.pid", NULL);
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno == ENOENT)
+ return;
+ i_fatal("open(%s) failed: %m", path);
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+ if (ret <= 0) {
+ if (ret == 0)
+ i_error("Empty PID file in %s, overriding", path);
+ else
+ i_fatal("read(%s) failed: %m", path);
+ } else {
+ pid_t pid;
+
+ if (buf[ret-1] == '\n')
+ ret--;
+ buf[ret] = '\0';
+ pid = atoi(buf);
+ if (pid == getpid() || (kill(pid, 0) < 0 && errno == ESRCH)) {
+ /* doesn't exist */
+ } else {
+ i_fatal("Dovecot is already running with PID %s "
+ "(read from %s)", buf, path);
+ }
+ }
+ (void)close(fd);
+}
+
static void main_log_startup(void)
{
#define STARTUP_STRING PACKAGE_NAME" v"VERSION" starting up"
/* deny file access from everyone else except owner */
(void)umask(0077);
- set_logfile(settings_root->defaults);
+ set_logfile(master_set->defaults);
/* close stderr unless we're logging into /dev/stderr. */
- if (!have_stderr(settings_root)) {
+ if (!have_stderr(master_set)) {
if (dup2(null_fd, 2) < 0)
i_fatal("dup2(2) failed: %m");
}
login_processes_init();
mail_processes_init();
- create_pid_file(t_strconcat(settings_root->defaults->base_dir,
+ create_pid_file(t_strconcat(master_set->defaults->base_dir,
"/master.pid", NULL));
}
static void main_deinit(void)
{
- (void)unlink(t_strconcat(settings_root->defaults->base_dir,
+ (void)unlink(t_strconcat(master_set->defaults->base_dir,
"/master.pid", NULL));
login_processes_destroy_all();
closelog();
}
-static void daemonize(struct settings *set)
+static void daemonize(struct master_settings *set)
{
pid_t pid;
int main(int argc, char *argv[])
{
/* parse arguments */
+ struct master_server_settings *set;
const char *exec_protocol = NULL, **exec_args = NULL, *user, *home;
bool foreground = FALSE, ask_key_pass = FALSE, log_error = FALSE;
bool dump_config = FALSE, dump_config_nondefaults = FALSE;
/* read and verify settings before forking */
T_BEGIN {
master_settings_init();
- if (!master_settings_read(configfile, exec_protocol != NULL,
- dump_config || log_error))
+ if (master_settings_read(configfile, &set) < 0)
i_fatal("Invalid configuration in %s", configfile);
} T_END;
+ if (!log_error && !dump_config && exec_protocol == NULL)
+ pid_file_check_running(set->defaults);
+
+ if (!master_settings_check(set, exec_protocol != NULL,
+ dump_config || log_error))
+ i_fatal("Invalid configuration in %s", configfile);
+
if (dump_config) {
const char *info;
- info = sysinfo_get(settings_root->defaults->mail_location);
+ info = sysinfo_get(master_set->defaults->mail_location);
if (*info != '\0')
printf("# %s\n", info);
- master_settings_dump(settings_root, dump_config_nondefaults);
- return 0;
+ if (dump_config_nondefaults)
+ client_process_exec(DOVECOT_CONFIG_BIN_PATH" -a", "");
+ else
+ client_process_exec(DOVECOT_CONFIG_BIN_PATH" -n", "");
+ i_fatal("exec(%s) failed: %m", DOVECOT_CONFIG_BIN_PATH);
}
- if (ask_key_pass) T_BEGIN {
+ if (ask_key_pass && !log_error) T_BEGIN {
const char *prompt;
prompt = t_strdup_printf("Give the password for SSL key file "
"%s: ",
- settings_root->defaults->ssl_key_file);
+ master_set->defaults->ssl_key_file);
askpass(prompt, ssl_manual_key_password,
sizeof(ssl_manual_key_password));
} T_END;
open_fds();
fatal_log_check();
- auth_warning_print(settings_root);
+ auth_warning_print(master_set);
if (!foreground)
- daemonize(settings_root->defaults);
+ daemonize(master_set->defaults);
master_original_pid = getpid();
ioloop = io_loop_create();
+++ /dev/null
-/* kludgy: this file is included from master-settings.c and from deliver */
-
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, settings)
-
-static struct setting_def setting_defs[] = {
- /* common */
- DEF_STR(base_dir),
- DEF_STR(log_path),
- DEF_STR(info_log_path),
- DEF_STR(log_timestamp),
- DEF_STR(syslog_facility),
-
- /* general */
- DEF_STR(protocols),
- DEF_STR(listen),
- DEF_STR(ssl_listen),
-
- DEF_STR(ssl),
- DEF_STR(ssl_ca_file),
- DEF_STR(ssl_cert_file),
- DEF_STR(ssl_key_file),
- DEF_STR(ssl_key_password),
- DEF_INT(ssl_parameters_regenerate),
- DEF_STR(ssl_cipher_list),
- DEF_STR(ssl_cert_username_field),
- DEF_BOOL(ssl_verify_client_cert),
- DEF_BOOL(disable_plaintext_auth),
- DEF_BOOL(verbose_ssl),
- DEF_BOOL(shutdown_clients),
- DEF_BOOL(nfs_check),
- DEF_BOOL(version_ignore),
-
- /* login */
- DEF_STR(login_dir),
- DEF_STR(login_executable),
- DEF_STR(login_user),
- DEF_STR(login_greeting),
- DEF_STR(login_log_format_elements),
- DEF_STR(login_log_format),
-
- DEF_BOOL(login_process_per_connection),
- DEF_BOOL(login_chroot),
- DEF_STR(login_trusted_networks),
-
- DEF_INT(login_process_size),
- DEF_INT(login_processes_count),
- DEF_INT(login_max_processes_count),
- DEF_INT(login_max_connections),
-
- /* mail */
- DEF_STR(valid_chroot_dirs),
- DEF_STR(mail_chroot),
- DEF_INT(max_mail_processes),
- DEF_INT(mail_max_userip_connections),
- DEF_BOOL(verbose_proctitle),
-
- DEF_INT(first_valid_uid),
- DEF_INT(last_valid_uid),
- DEF_INT(first_valid_gid),
- DEF_INT(last_valid_gid),
- DEF_STR(mail_access_groups),
- DEF_STR(mail_privileged_group),
- DEF_STR(mail_uid),
- DEF_STR(mail_gid),
-
- DEF_STR(mail_location),
- DEF_STR(mail_cache_fields),
- DEF_STR(mail_never_cache_fields),
- DEF_INT(mail_cache_min_mail_count),
- DEF_INT(mailbox_idle_check_interval),
- DEF_BOOL(mail_debug),
- DEF_BOOL(mail_full_filesystem_access),
- DEF_INT(mail_max_keyword_length),
- DEF_BOOL(mail_save_crlf),
- DEF_BOOL(mmap_disable),
- DEF_BOOL(dotlock_use_excl),
- DEF_BOOL(fsync_disable),
- DEF_BOOL(mail_nfs_storage),
- DEF_BOOL(mail_nfs_index),
- DEF_BOOL(mailbox_list_index_disable),
- DEF_STR(lock_method),
- DEF_BOOL(maildir_stat_dirs),
- DEF_BOOL(maildir_copy_with_hardlinks),
- DEF_BOOL(maildir_copy_preserve_filename),
- DEF_STR(mbox_read_locks),
- DEF_STR(mbox_write_locks),
- DEF_INT(mbox_lock_timeout),
- DEF_INT(mbox_dotlock_change_timeout),
- DEF_INT(mbox_min_index_size),
- DEF_BOOL(mbox_dirty_syncs),
- DEF_BOOL(mbox_very_dirty_syncs),
- DEF_BOOL(mbox_lazy_writes),
- DEF_INT(dbox_rotate_size),
- DEF_INT(dbox_rotate_min_size),
- DEF_INT(dbox_rotate_days),
- DEF_INT(umask),
- DEF_BOOL(mail_drop_priv_before_exec),
-
- DEF_STR(mail_executable),
- DEF_INT(mail_process_size),
- DEF_STR(mail_plugins),
- DEF_STR(mail_plugin_dir),
- DEF_STR(mail_log_prefix),
- DEF_INT(mail_log_max_lines_per_sec),
-
- /* imap */
- DEF_INT(imap_max_line_length),
- DEF_STR(imap_capability),
- DEF_STR(imap_client_workarounds),
- DEF_STR(imap_logout_format),
- DEF_STR(imap_id_send),
- DEF_STR(imap_id_log),
-
- /* pop3 */
- DEF_BOOL(pop3_no_flag_updates),
- DEF_BOOL(pop3_enable_last),
- DEF_BOOL(pop3_reuse_xuidl),
- DEF_BOOL(pop3_lock_session),
- DEF_STR(pop3_uidl_format),
- DEF_STR(pop3_client_workarounds),
- DEF_STR(pop3_logout_format),
-
- /* dict */
- DEF_STR(dict_db_config),
- DEF_INT(dict_process_count),
-
- { 0, NULL, 0 }
-};
#include "array.h"
#include "str.h"
#include "istream.h"
+#include "env-util.h"
#include "fd-close-on-exec.h"
#include "safe-mkdir.h"
#include "mkdir-parents.h"
#include "syslog-util.h"
#include "mail-process.h"
#include "master-login-interface.h"
-#include "settings.h"
+#include "settings-parser.h"
#include <stdio.h>
#include <stddef.h>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
+#include <ctype.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
# include <sys/resource.h>
#endif
-enum settings_type {
- SETTINGS_TYPE_ROOT,
- SETTINGS_TYPE_SERVER,
- SETTINGS_TYPE_AUTH,
- SETTINGS_TYPE_AUTH_SOCKET,
- SETTINGS_TYPE_AUTH_PASSDB,
- SETTINGS_TYPE_AUTH_USERDB,
- SETTINGS_TYPE_NAMESPACE,
- SETTINGS_TYPE_SOCKET,
- SETTINGS_TYPE_DICT,
- SETTINGS_TYPE_PLUGIN
-};
+extern struct setting_parser_info master_auth_setting_parser_info;
+extern struct setting_parser_info master_setting_parser_info;
+extern struct setting_parser_info master_auth_socket_setting_parser_info;
-struct settings_parse_ctx {
- enum settings_type type, parent_type;
- enum mail_protocol protocol;
+#undef DEF
+#define DEF(type, name) \
+ { type, #name, offsetof(struct master_auth_socket_unix_settings, name), NULL }
- struct server_settings *root, *server;
- struct auth_settings *auth;
- struct socket_settings *socket;
- struct auth_socket_settings *auth_socket;
- struct auth_passdb_settings *auth_passdb;
- struct auth_userdb_settings *auth_userdb;
- struct namespace_settings *namespace;
+static struct setting_define master_auth_socket_master_setting_defines[] = {
+ DEF(SET_STR, path),
- int level;
+ SETTING_DEFINE_LIST_END
};
-#include "master-settings-defs.c"
-
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, auth_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, auth_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, auth_settings)
-
-static struct setting_def auth_setting_defs[] = {
- DEF_STR(mechanisms),
- DEF_STR(realms),
- DEF_STR(default_realm),
- DEF_INT(cache_size),
- DEF_INT(cache_ttl),
- DEF_INT(cache_negative_ttl),
- DEF_STR(executable),
- DEF_STR(user),
- DEF_STR(chroot),
- DEF_STR(username_chars),
- DEF_STR(username_translation),
- DEF_STR(username_format),
- DEF_STR(master_user_separator),
- DEF_STR(anonymous_username),
- DEF_STR(krb5_keytab),
- DEF_STR(gssapi_hostname),
- DEF_STR(winbind_helper_path),
- DEF_INT(failure_delay),
-
- DEF_BOOL(verbose),
- DEF_BOOL(debug),
- DEF_BOOL(debug_passwords),
- DEF_BOOL(ssl_require_client_cert),
- DEF_BOOL(ssl_username_from_cert),
- DEF_BOOL(use_winbind),
-
- DEF_INT(count),
- DEF_INT(worker_max_count),
- DEF_INT(process_size),
-
- { 0, NULL, 0 }
+static struct master_auth_socket_unix_settings master_auth_socket_master_default_settings = {
+ MEMBER(path) "auth-master"
};
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, socket_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, socket_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, socket_settings)
+struct setting_parser_info master_auth_socket_master_setting_parser_info = {
+ MEMBER(defines) master_auth_socket_master_setting_defines,
+ MEMBER(defaults) &master_auth_socket_master_default_settings,
+
+ MEMBER(parent) &master_auth_socket_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
-static struct setting_def socket_setting_defs[] = {
- DEF_STR(path),
- DEF_INT(mode),
- DEF_STR(user),
- DEF_STR(group),
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct master_auth_socket_unix_settings)
+};
- { 0, NULL, 0 }
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct master_auth_socket_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct master_auth_socket_settings, field), defines }
+static struct setting_define master_auth_socket_setting_defines[] = {
+ DEF(SET_STR, type),
+ DEFLIST(masters, "master", &master_auth_socket_master_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
};
-static struct setting_def auth_socket_setting_defs[] = {
- DEF_STRUCT_STR(type, auth_socket_settings),
+struct setting_parser_info master_auth_socket_setting_parser_info = {
+ MEMBER(defines) master_auth_socket_setting_defines,
+ MEMBER(defaults) NULL,
+
+ MEMBER(parent) &master_auth_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
- { 0, NULL, 0 }
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct master_auth_socket_settings, type),
+ MEMBER(struct_size) sizeof(struct master_auth_socket_settings)
};
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, auth_passdb_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, auth_passdb_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, auth_passdb_settings)
-
-static struct setting_def auth_passdb_setting_defs[] = {
- DEF_STR(driver),
- DEF_STR(args),
- DEF_BOOL(deny),
- DEF_BOOL(pass),
- DEF_BOOL(master),
-
- { 0, NULL, 0 }
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct master_auth_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct master_auth_settings, field), defines }
+
+static struct setting_define master_auth_setting_defines[] = {
+ DEF(SET_STR, name),
+ DEF(SET_STR, executable),
+ DEF(SET_STR, user),
+ DEF(SET_STR, chroot),
+ DEF(SET_UINT, count),
+ DEF(SET_UINT, process_size),
+ DEF(SET_STR, mechanisms),
+ DEF(SET_BOOL, debug),
+ DEFLIST(sockets, "socket", &master_auth_socket_setting_parser_info),
+
+ SETTING_DEFINE_LIST_END
};
-static struct setting_def auth_userdb_setting_defs[] = {
- DEF_STRUCT_STR(driver, auth_userdb_settings),
- DEF_STRUCT_STR(args, auth_userdb_settings),
+static struct master_auth_settings master_auth_default_settings = {
+ MEMBER(name) "default",
+ MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth",
+ MEMBER(user) "root",
+ MEMBER(chroot) "",
+ MEMBER(count) 1,
+ MEMBER(mechanisms) "plain",
+ MEMBER(debug) FALSE,
+ MEMBER(process_size) 256
- { 0, NULL, 0 }
+ /* .. */
};
-#undef DEF_STR
-#undef DEF_INT
-#undef DEF_BOOL
-#define DEF_STR(name) DEF_STRUCT_STR(name, namespace_settings)
-#define DEF_INT(name) DEF_STRUCT_INT(name, namespace_settings)
-#define DEF_BOOL(name) DEF_STRUCT_BOOL(name, namespace_settings)
-
-static struct setting_def namespace_setting_defs[] = {
- DEF_STR(type),
- DEF_STR(separator),
- DEF_STR(prefix),
- DEF_STR(location),
- DEF_STR(alias_for),
- DEF_BOOL(inbox),
- DEF_BOOL(hidden),
- DEF_STR(list),
- DEF_BOOL(subscriptions),
-
- { 0, NULL, 0 }
+struct setting_parser_info master_auth_setting_parser_info = {
+ MEMBER(defines) master_auth_setting_defines,
+ MEMBER(defaults) &master_auth_default_settings,
+
+ MEMBER(parent) &master_setting_parser_info,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) offsetof(struct master_auth_settings, name),
+ MEMBER(struct_size) sizeof(struct master_auth_settings)
};
-struct settings default_settings = {
- MEMBER(server) NULL,
- MEMBER(protocol) 0,
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct master_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct master_settings, field), defines }
+
+static struct setting_define master_setting_defines[] = {
+ /* common */
+ DEF(SET_STR, base_dir),
+ DEF(SET_STR, log_path),
+ DEF(SET_STR, info_log_path),
+ DEF(SET_STR, log_timestamp),
+ DEF(SET_STR, syslog_facility),
+
+ /* general */
+ DEF(SET_STR, protocols),
+ DEF(SET_STR, listen),
+ DEF(SET_STR, ssl_listen),
+
+ DEF(SET_STR, ssl),
+ DEF(SET_STR, ssl_key_file),
+ DEF(SET_UINT, ssl_parameters_regenerate),
+ DEF(SET_BOOL, nfs_check),
+ DEF(SET_BOOL, version_ignore),
+
+ /* 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, disable_plaintext_auth),
+
+ DEF(SET_UINT, login_process_size),
+ DEF(SET_UINT, login_processes_count),
+ DEF(SET_UINT, login_max_processes_count),
+
+ /* mail */
+ DEF(SET_STR, valid_chroot_dirs),
+ DEF(SET_STR, mail_chroot),
+ DEF(SET_UINT, max_mail_processes),
+ DEF(SET_UINT, mail_max_userip_connections),
+ DEF(SET_BOOL, verbose_proctitle),
+
+ DEF(SET_UINT, first_valid_uid),
+ DEF(SET_UINT, last_valid_uid),
+ DEF(SET_UINT, first_valid_gid),
+ DEF(SET_UINT, last_valid_gid),
+ DEF(SET_STR, mail_access_groups),
+ DEF(SET_STR, mail_privileged_group),
+ DEF(SET_STR, mail_uid),
+ DEF(SET_STR, mail_gid),
+
+ DEF(SET_STR, mail_plugins),
+ DEF(SET_STR, imap_capability),
+
+ DEF(SET_STR_VARS, mail_location),
+ DEF(SET_BOOL, mail_debug),
+ DEF(SET_BOOL, mail_nfs_index),
+ DEF(SET_UINT, umask),
+ DEF(SET_BOOL, mail_drop_priv_before_exec),
+
+ DEF(SET_STR, mail_executable),
+ DEF(SET_UINT, mail_process_size),
+ DEF(SET_STR_VARS, mail_log_prefix),
+ DEF(SET_UINT, mail_log_max_lines_per_sec),
+ /* dict */
+ DEF(SET_STR, dict_db_config),
+ DEF(SET_UINT, dict_process_count),
+ DEFLIST(auths, "auth", &master_auth_setting_parser_info),
+ { SET_STRLIST, "dict", offsetof(struct master_settings, dicts), NULL },
+ { SET_STRLIST, "plugin", offsetof(struct master_settings, plugin_envs), NULL },
+
+ SETTING_DEFINE_LIST_END
+};
+
+struct master_settings master_default_settings = {
/* common */
MEMBER(base_dir) PKG_RUNDIR,
MEMBER(log_path) "",
MEMBER(ssl_listen) "",
MEMBER(ssl) "yes",
- MEMBER(ssl_ca_file) "",
- MEMBER(ssl_cert_file) SSLDIR"/certs/dovecot.pem",
MEMBER(ssl_key_file) SSLDIR"/private/dovecot.pem",
- MEMBER(ssl_key_password) "",
MEMBER(ssl_parameters_regenerate) 168,
- MEMBER(ssl_cipher_list) "",
- MEMBER(ssl_cert_username_field) "commonName",
- MEMBER(ssl_verify_client_cert) FALSE,
- MEMBER(disable_plaintext_auth) TRUE,
- MEMBER(verbose_ssl) FALSE,
- MEMBER(shutdown_clients) TRUE,
MEMBER(nfs_check) TRUE,
MEMBER(version_ignore) FALSE,
MEMBER(login_dir) "login",
MEMBER(login_executable) NULL,
MEMBER(login_user) "dovecot",
- MEMBER(login_greeting) PACKAGE_NAME" ready.",
- MEMBER(login_log_format_elements) "user=<%u> method=%m rip=%r lip=%l %c",
- MEMBER(login_log_format) "%$: %s",
MEMBER(login_process_per_connection) TRUE,
MEMBER(login_chroot) TRUE,
- MEMBER(login_trusted_networks) "",
+ MEMBER(disable_plaintext_auth) TRUE,
MEMBER(login_process_size) 64,
MEMBER(login_processes_count) 3,
MEMBER(login_max_processes_count) 128,
- MEMBER(login_max_connections) 256,
/* mail */
MEMBER(valid_chroot_dirs) "",
MEMBER(mail_privileged_group) "",
MEMBER(mail_uid) "",
MEMBER(mail_gid) "",
+ MEMBER(mail_plugins) "",
+ MEMBER(imap_capability) "",
MEMBER(mail_location) "",
- MEMBER(mail_cache_fields) "",
- MEMBER(mail_never_cache_fields) "imap.envelope",
- MEMBER(mail_cache_min_mail_count) 0,
- MEMBER(mailbox_idle_check_interval) 30,
MEMBER(mail_debug) FALSE,
- MEMBER(mail_full_filesystem_access) FALSE,
- MEMBER(mail_max_keyword_length) 50,
- MEMBER(mail_save_crlf) FALSE,
-#ifdef MMAP_CONFLICTS_WRITE
- MEMBER(mmap_disable) TRUE,
-#else
- MEMBER(mmap_disable) FALSE,
-#endif
- MEMBER(dotlock_use_excl) TRUE,
- MEMBER(fsync_disable) FALSE,
- MEMBER(mail_nfs_storage) FALSE,
MEMBER(mail_nfs_index) FALSE,
- MEMBER(mailbox_list_index_disable) TRUE,
- MEMBER(lock_method) "fcntl",
- MEMBER(maildir_stat_dirs) FALSE,
- MEMBER(maildir_copy_with_hardlinks) TRUE,
- MEMBER(maildir_copy_preserve_filename) FALSE,
- MEMBER(mbox_read_locks) "fcntl",
- MEMBER(mbox_write_locks) "dotlock fcntl",
- MEMBER(mbox_lock_timeout) 300,
- MEMBER(mbox_dotlock_change_timeout) 120,
- MEMBER(mbox_min_index_size) 0,
- MEMBER(mbox_dirty_syncs) TRUE,
- MEMBER(mbox_very_dirty_syncs) FALSE,
- MEMBER(mbox_lazy_writes) TRUE,
- MEMBER(dbox_rotate_size) 2048,
- MEMBER(dbox_rotate_min_size) 16,
- MEMBER(dbox_rotate_days) 1,
MEMBER(umask) 0077,
MEMBER(mail_drop_priv_before_exec) FALSE,
- MEMBER(mail_executable) PKG_LIBEXECDIR"/imap",
+ MEMBER(mail_executable) NULL,
MEMBER(mail_process_size) 256,
- MEMBER(mail_plugins) "",
- MEMBER(mail_plugin_dir) MODULEDIR"/imap",
MEMBER(mail_log_prefix) "%Us(%u): ",
MEMBER(mail_log_max_lines_per_sec) 10,
- /* imap */
- MEMBER(imap_max_line_length) 65536,
- MEMBER(imap_capability) "",
- MEMBER(imap_client_workarounds) "",
- MEMBER(imap_logout_format) "bytes=%i/%o",
- MEMBER(imap_id_send) "",
- MEMBER(imap_id_log) "",
-
- /* pop3 */
- MEMBER(pop3_no_flag_updates) FALSE,
- MEMBER(pop3_enable_last) FALSE,
- MEMBER(pop3_reuse_xuidl) FALSE,
- MEMBER(pop3_lock_session) FALSE,
- MEMBER(pop3_uidl_format) "%08Xu%08Xv",
- MEMBER(pop3_client_workarounds) "",
- MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
-
/* dict */
MEMBER(dict_db_config) NULL,
MEMBER(dict_process_count) 1,
/* .. */
};
-struct auth_settings default_auth_settings = {
+struct setting_parser_info master_setting_parser_info = {
+ MEMBER(defines) master_setting_defines,
+ MEMBER(defaults) &master_default_settings,
+
MEMBER(parent) NULL,
- MEMBER(next) NULL,
+ MEMBER(dynamic_parsers) NULL,
- MEMBER(name) NULL,
- MEMBER(mechanisms) "plain",
- MEMBER(realms) "",
- MEMBER(default_realm) "",
- MEMBER(cache_size) 0,
- MEMBER(cache_ttl) 3600,
- MEMBER(cache_negative_ttl) 3600,
- MEMBER(executable) PKG_LIBEXECDIR"/dovecot-auth",
- MEMBER(user) "root",
- MEMBER(chroot) "",
- MEMBER(username_chars) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@",
- MEMBER(username_translation) "",
- MEMBER(username_format) "",
- MEMBER(master_user_separator) "",
- MEMBER(anonymous_username) "anonymous",
- MEMBER(krb5_keytab) "",
- MEMBER(gssapi_hostname) "",
- MEMBER(winbind_helper_path) "/usr/bin/ntlm_auth",
- MEMBER(failure_delay) 2,
-
- MEMBER(verbose) FALSE,
- MEMBER(debug) FALSE,
- MEMBER(debug_passwords) FALSE,
- MEMBER(ssl_require_client_cert) FALSE,
- MEMBER(ssl_username_from_cert) FALSE,
- MEMBER(use_winbind) FALSE,
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct master_settings)
+};
- MEMBER(count) 1,
- MEMBER(worker_max_count) 30,
- MEMBER(process_size) 256,
+static pool_t settings_pool, settings2_pool;
+struct master_server_settings *master_set = NULL;
- /* .. */
- MEMBER(uid) 0,
- MEMBER(gid) 0,
- MEMBER(passdbs) NULL,
- MEMBER(userdbs) NULL,
- MEMBER(sockets) NULL
-};
+#ifdef HAVE_MODULES
+static const char *
+get_process_capability(enum process_type ptype, struct master_settings *set)
+{
+ /* FIXME: pretty ugly code just for getting the capability
+ automatically */
+ static const char *args[] = {
+ "uid=65534",
+ "gid=65534",
+ "home=/tmp",
+ NULL
+ };
+ const char *pname = process_names[ptype];
+ enum master_login_status login_status;
+ struct mail_login_request request;
+ char buf[4096];
+ int fd[2], status;
+ ssize_t ret;
+ unsigned int pos;
+ uid_t uid;
+ pid_t pid;
-struct socket_settings default_socket_settings = {
-#define DEFAULT_MASTER_SOCKET_PATH "auth-master"
-#define DEFAULT_CLIENT_SOCKET_PATH "auth-client"
- MEMBER(path) "",
- MEMBER(mode) 0600,
- MEMBER(user) "",
- MEMBER(group) ""
-};
+ uid = geteuid();
+ if (uid != 0) {
+ /* use the current user */
+ args[0] = t_strdup_printf("uid=%s", dec2str(uid));
+ args[1] = t_strdup_printf("gid=%s", dec2str(getegid()));
+ }
-struct namespace_settings default_namespace_settings = {
- MEMBER(parent) NULL,
- MEMBER(next) NULL,
- MEMBER(type) NULL,
-
- MEMBER(separator) "",
- MEMBER(prefix) "",
- MEMBER(location) "",
- MEMBER(alias_for) NULL,
-
- MEMBER(inbox) FALSE,
- MEMBER(hidden) FALSE,
- MEMBER(list) "yes",
- MEMBER(subscriptions) TRUE
-};
+ if (pipe(fd) < 0) {
+ i_error("pipe() failed: %m");
+ return NULL;
+ }
+ fd_close_on_exec(fd[0], TRUE);
+ fd_close_on_exec(fd[1], TRUE);
-static pool_t settings_pool, settings2_pool;
-struct server_settings *settings_root = NULL;
+ memset(&request, 0, sizeof(request));
+ request.fd = fd[1];
+ login_status = create_mail_process(ptype, set, &request,
+ "dump-capability", args, NULL, TRUE,
+ &pid);
+ if (login_status != MASTER_LOGIN_STATUS_OK) {
+ (void)close(fd[0]);
+ (void)close(fd[1]);
+ return NULL;
+ }
+ (void)close(fd[1]);
+
+ alarm(5);
+ if (wait(&status) == -1) {
+ i_fatal("%s dump-capability process %d got stuck",
+ pname, (int)pid);
+ }
+ alarm(0);
+
+ if (status != 0) {
+ (void)close(fd[0]);
+ if (WIFSIGNALED(status)) {
+ i_error("%s dump-capability process "
+ "killed with signal %d",
+ pname, WTERMSIG(status));
+ } else {
+ i_error("%s dump-capability process returned %d",
+ pname, WIFEXITED(status) ? WEXITSTATUS(status) :
+ status);
+ }
+ return NULL;
+ }
+
+ pos = 0;
+ while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0)
+ pos += ret;
+
+ if (ret < 0) {
+ i_error("read(%s dump-capability process) failed: %m", pname);
+ (void)close(fd[0]);
+ return NULL;
+ }
+ (void)close(fd[0]);
+
+ if (pos == 0 || buf[pos-1] != '\n') {
+ i_error("%s dump-capability: Couldn't read capability "
+ "(got %u bytes)", pname, pos);
+ return NULL;
+ }
+ buf[pos-1] = '\0';
+
+ return i_strdup(buf);
+}
+
+static bool get_imap_capability(struct master_settings *set)
+{
+ static const char *generated_capability = NULL;
+
+ if (generated_capability != NULL) {
+ /* Reloading configuration. Don't try to execute the imap
+ process again. Too risky and the wait() call below will
+ break it anyway. Just use the previous capability list we
+ already had generated. */
+ set->imap_generated_capability =
+ p_strdup(settings_pool, generated_capability);
+ return TRUE;
+ }
+
+ generated_capability = get_process_capability(PROCESS_TYPE_IMAP, set);
+ if (generated_capability == NULL)
+ return FALSE;
+
+ set->imap_generated_capability =
+ p_strdup(settings_pool, generated_capability);
+ return TRUE;
+}
+#endif
-static void fix_base_path(struct settings *set, const char **str)
+static void fix_base_path(struct master_settings *set, const char **str)
{
if (*str != NULL && **str != '\0' && **str != '/') {
*str = p_strconcat(settings_pool,
return TRUE;
}
-static bool get_login_uid(struct settings *set)
+static bool get_login_uid(struct master_settings *set)
{
struct passwd *pw;
dec2str(pw->pw_gid));
return FALSE;
}
-
set->login_uid = pw->pw_uid;
return TRUE;
}
-static bool auth_settings_verify(struct auth_settings *auth)
+static bool auth_settings_verify(struct master_settings *set,
+ struct master_auth_settings *auth)
{
struct passwd *pw;
- struct auth_socket_settings *s;
+ struct master_auth_socket_settings *const *sockets;
+ unsigned int i, count;
if ((pw = getpwnam(auth->user)) == NULL) {
i_error("Auth user doesn't exist: %s", auth->user);
return FALSE;
}
- if (auth->parent->defaults->login_uid == pw->pw_uid &&
- master_uid != pw->pw_uid) {
+ if (set->login_uid == pw->pw_uid && master_uid != pw->pw_uid) {
i_error("login_user %s (uid %s) must not be same as auth_user",
auth->user, dec2str(pw->pw_uid));
return FALSE;
return FALSE;
}
- fix_base_path(auth->parent->defaults, &auth->chroot);
+ fix_base_path(set, &auth->chroot);
if (*auth->chroot != '\0' && access(auth->chroot, X_OK) < 0) {
i_error("Can't access auth chroot directory %s: %m",
auth->chroot);
return FALSE;
}
- if (auth->ssl_require_client_cert || auth->ssl_username_from_cert) {
- /* if we require valid cert, make sure we also ask for it */
- if (auth->parent->pop3 != NULL)
- auth->parent->pop3->ssl_verify_client_cert = TRUE;
- if (auth->parent->imap != NULL)
- auth->parent->imap->ssl_verify_client_cert = TRUE;
- }
-
- for (s = auth->sockets; s != NULL; s = s->next) {
- if (auth->count > 1 && strcmp(s->type, "listen") == 0) {
+ sockets = array_get(&auth->sockets, &count);
+ for (i = 0; i < count; i++) {
+ if (auth->count > 1 &&
+ strcmp(sockets[i]->type, "listen") == 0) {
i_error("Currently auth process count must be 1 if "
"you're using auth socket listeners.");
return FALSE;
}
- fix_base_path(auth->parent->defaults, &s->master.path);
- fix_base_path(auth->parent->defaults, &s->client.path);
- }
- return TRUE;
-}
-
-static bool namespace_settings_verify(struct server_settings *server,
- struct namespace_settings *ns)
-{
- struct namespace_settings *n;
- const char *name;
-
- name = ns->prefix != NULL ? ns->prefix : "";
-
- if (ns->separator != NULL &&
- ns->separator[0] != '\0' && ns->separator[1] != '\0') {
- i_error("Namespace '%s': "
- "Hierarchy separator must be only one character long",
- name);
- return FALSE;
- }
- if (strcmp(ns->list, "yes") != 0 &&
- strcmp(ns->list, "no") != 0 &&
- strcmp(ns->list, "children") != 0) {
- i_error("Namespace '%s': Invalid list value: %s",
- name, ns->list);
- return FALSE;
- }
-
- if (ns->alias_for != NULL) {
- for (n = server->namespaces; n != ns; n = n->next) {
- if (strcmp(n->prefix, ns->alias_for) == 0)
- break;
- }
- if (n == ns) {
- i_error("Namespace '%s': alias_for points to "
- "unknown namespace: %s", name, ns->alias_for);
- return FALSE;
- }
- if (n->alias_for != NULL) {
- i_error("Namespace '%s': alias_for chaining isn't "
- "allowed: %s -> %s", name, ns->alias_for,
- n->alias_for);
- return FALSE;
- }
}
-
return TRUE;
}
}
}
-static bool settings_is_active(struct settings *set)
+static bool settings_is_active(struct master_settings *set)
{
if (*set->protocols == '\0') {
/* we're probably using this with --exec-mail */
return TRUE;
}
-static bool settings_have_connect_sockets(struct settings *set)
+static bool settings_have_connect_sockets(struct master_settings *set)
{
- struct auth_settings *auth;
- struct server_settings *server;
-
- for (server = set->server; server != NULL; server = server->next) {
- for (auth = server->auths; auth != NULL; auth = auth->next) {
- if (auth->sockets != NULL &&
- strcmp(auth->sockets->type, "connect") == 0)
- return TRUE;
- }
+ struct master_auth_settings *const *auths;
+ struct master_auth_socket_settings *const *sockets;
+ unsigned int i, count, count2;
+
+ auths = array_get(&set->auths, &count);
+ for (i = 0; i < count; i++) {
+ sockets = array_get(&auths[i]->sockets, &count2);
+ if (count2 > 0 && strcmp(sockets[0]->type, "connect") == 0)
+ return TRUE;
}
return FALSE;
}
-static bool settings_have_nonplaintext_auths(struct settings *set)
+static bool settings_have_nonplaintext_auths(struct master_settings *set)
{
- struct auth_settings *auth;
- struct server_settings *server;
+ struct master_auth_settings *const *auths;
const char *const *tmp;
+ unsigned int i, count;
- for (server = set->server; server != NULL; server = server->next) {
- for (auth = server->auths; auth != NULL; auth = auth->next) {
- tmp = t_strsplit_spaces(auth->mechanisms, " ");
- for (; *tmp != NULL; tmp++) {
- if (strcasecmp(*tmp, "PLAIN") != 0 &&
- strcasecmp(*tmp, "LOGIN") != 0)
- return TRUE;
- }
+ auths = array_get(&set->auths, &count);
+ for (i = 0; i < count; i++) {
+ tmp = t_strsplit_spaces(auths[i]->mechanisms, " ");
+ for (; *tmp != NULL; tmp++) {
+ if (strcasecmp(*tmp, "PLAIN") != 0 &&
+ strcasecmp(*tmp, "LOGIN") != 0)
+ return TRUE;
}
}
(void)closedir(dirp);
}
-#ifdef HAVE_MODULES
-static const char *
-get_process_capability(enum process_type ptype, struct settings *set)
+static bool settings_verify(struct master_settings *set)
{
- /* FIXME: pretty ugly code just for getting the capability
- automatically */
- static const char *args[] = {
- "uid=65534",
- "gid=65534",
- "home=/tmp",
- NULL
- };
- const char *pname = process_names[ptype];
- enum master_login_status login_status;
- struct mail_login_request request;
- char buf[4096];
- int fd[2], status;
- ssize_t ret;
- unsigned int pos;
- uid_t uid;
- pid_t pid;
+ const char *dir;
+ int facility;
- uid = geteuid();
- if (uid != 0) {
- /* use the current user */
- args[0] = t_strdup_printf("uid=%s", dec2str(uid));
- args[1] = t_strdup_printf("gid=%s", dec2str(getegid()));
- }
+ if (!get_login_uid(set))
+ return FALSE;
- if (pipe(fd) < 0) {
- i_error("pipe() failed: %m");
- return NULL;
- }
- fd_close_on_exec(fd[0], TRUE);
- fd_close_on_exec(fd[1], TRUE);
+ set->mail_uid_t = (uid_t)-1;
+ set->mail_gid_t = (gid_t)-1;
+ set->mail_priv_gid_t = (gid_t)-1;
- memset(&request, 0, sizeof(request));
- request.fd = fd[1];
- login_status = create_mail_process(ptype, set, &request,
- "dump-capability", args, NULL, TRUE,
- &pid);
- if (login_status != MASTER_LOGIN_STATUS_OK) {
- (void)close(fd[0]);
- (void)close(fd[1]);
- return NULL;
+ if (*set->mail_uid != '\0') {
+ if (!parse_uid(set->mail_uid, &set->mail_uid_t)) {
+ i_error("Non-existing mail_uid: %s", set->mail_uid);
+ return FALSE;
+ }
}
- (void)close(fd[1]);
-
- alarm(5);
- if (wait(&status) == -1) {
- i_fatal("%s dump-capability process %d got stuck",
- pname, (int)pid);
- }
- alarm(0);
-
- if (status != 0) {
- (void)close(fd[0]);
- if (WIFSIGNALED(status)) {
- i_error("%s dump-capability process "
- "killed with signal %d",
- pname, WTERMSIG(status));
- } else {
- i_error("%s dump-capability process returned %d",
- pname, WIFEXITED(status) ? WEXITSTATUS(status) :
- status);
- }
- return NULL;
- }
-
- pos = 0;
- while ((ret = read(fd[0], buf + pos, sizeof(buf) - pos)) > 0)
- pos += ret;
-
- if (ret < 0) {
- i_error("read(%s dump-capability process) failed: %m", pname);
- (void)close(fd[0]);
- return NULL;
- }
- (void)close(fd[0]);
-
- if (pos == 0 || buf[pos-1] != '\n') {
- i_error("%s dump-capability: Couldn't read capability "
- "(got %u bytes)", pname, pos);
- return NULL;
- }
- buf[pos-1] = '\0';
-
- return i_strdup(buf);
-}
-
-static bool get_imap_capability(struct settings *set)
-{
- static const char *generated_capability = NULL;
-
- if (generated_capability != NULL) {
- /* Reloading configuration. Don't try to execute the imap
- process again. Too risky and the wait() call below will
- break it anyway. Just use the previous capability list we
- already had generated. */
- set->imap_generated_capability =
- p_strdup(settings_pool, generated_capability);
- return TRUE;
- }
-
- generated_capability = get_process_capability(PROCESS_TYPE_IMAP, set);
- if (generated_capability == NULL)
- return FALSE;
-
- set->imap_generated_capability =
- p_strdup(settings_pool, generated_capability);
- return TRUE;
-}
-#endif
-
-static bool settings_verify(struct settings *set)
-{
- const char *dir;
- int facility;
-
- if (!get_login_uid(set))
- return FALSE;
-
- set->mail_uid_t = (uid_t)-1;
- set->mail_gid_t = (gid_t)-1;
- set->mail_priv_gid_t = (gid_t)-1;
-
- if (*set->mail_uid != '\0') {
- if (!parse_uid(set->mail_uid, &set->mail_uid_t)) {
- i_error("Non-existing mail_uid: %s", set->mail_uid);
- return FALSE;
- }
- }
- if (*set->mail_gid != '\0') {
- if (!parse_gid(set->mail_gid, &set->mail_gid_t)) {
- i_error("Non-existing mail_gid: %s", set->mail_uid);
- return FALSE;
- }
+ if (*set->mail_gid != '\0') {
+ if (!parse_gid(set->mail_gid, &set->mail_gid_t)) {
+ i_error("Non-existing mail_gid: %s", set->mail_uid);
+ return FALSE;
+ }
}
if (*set->mail_privileged_group != '\0') {
if (!parse_gid(set->mail_privileged_group,
i_error("ssl setting: Invalid value: %s", set->ssl);
return FALSE;
}
-#ifdef HAVE_SSL
+#ifndef HAVE_SSL
if (strcmp(set->ssl, "no") != 0) {
- if (*set->ssl_ca_file != '\0' &&
- access(set->ssl_ca_file, R_OK) < 0) {
- i_fatal("ssl_ca_file: Can't use %s: %m",
- set->ssl_ca_file);
- }
- if (access(set->ssl_cert_file, R_OK) < 0) {
- i_error("ssl_cert_file: Can't use %s: %m",
- set->ssl_cert_file);
- return FALSE;
- }
- if (access(set->ssl_key_file, R_OK) < 0) {
- i_error("ssl_key_file: Can't use %s: %m",
- set->ssl_key_file);
- return FALSE;
- }
- }
-#else
- if (strcmp(set->ssl, "no") != 0) {
i_error("SSL support not compiled in but ssl=%s", set->ssl);
return FALSE;
}
i_error("login_processes_count must be at least 1");
return FALSE;
}
- if (set->login_max_connections < 1) {
- i_error("login_max_connections must be at least 1");
- return FALSE;
- }
+#if 0 //FIXME
if (set->mail_nfs_index && !set->mmap_disable) {
i_error("mail_nfs_index=yes requires mmap_disable=yes");
return FALSE;
i_error("mail_nfs_index=yes requires fsync_disable=no");
return FALSE;
}
-
#ifdef HAVE_MODULES
if (*set->mail_plugins != '\0' &&
access(set->mail_plugin_dir, R_OK | X_OK) < 0) {
"can't load plugins: %s", set->mail_plugins);
return FALSE;
}
+#endif
#endif
return TRUE;
}
-static bool settings_do_fixes(struct settings *set)
+static bool settings_do_fixes(struct master_settings *set)
{
struct stat st;
return TRUE;
}
-static bool settings_fix(struct settings *set, bool nochecks, bool nofixes)
+static bool
+settings_fix(struct master_settings *set, bool nochecks, bool nofixes)
{
/* fix relative paths */
fix_base_path(set, &set->login_dir);
return nofixes ? TRUE : settings_do_fixes(set);
}
-static void pid_file_check_running(const char *path)
-{
- char buf[32];
- int fd;
- ssize_t ret;
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- if (errno == ENOENT)
- return;
- i_fatal("open(%s) failed: %m", path);
- }
-
- ret = read(fd, buf, sizeof(buf));
- if (ret <= 0) {
- if (ret == 0)
- i_error("Empty PID file in %s, overriding", path);
- else
- i_fatal("read(%s) failed: %m", path);
- } else {
- pid_t pid;
-
- if (buf[ret-1] == '\n')
- ret--;
- buf[ret] = '\0';
- pid = atoi(buf);
- if (pid == getpid() || (kill(pid, 0) < 0 && errno == ESRCH)) {
- /* doesn't exist */
- } else {
- i_fatal("Dovecot is already running with PID %s "
- "(read from %s)", buf, path);
- }
- }
- (void)close(fd);
-}
-
-static struct auth_settings *
-auth_settings_new(struct server_settings *server, const char *name)
-{
- struct auth_settings *auth;
-
- auth = p_new(settings_pool, struct auth_settings, 1);
-
- /* copy defaults */
- *auth = server->auth_defaults;
- auth->parent = server;
- auth->name = p_strdup(settings_pool, name);
-
- auth->next = server->auths;
- server->auths = auth;
-
- return auth;
-}
-
-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) {
- *errormsg = "Authentication process name must not contain '/'";
- return NULL;
- }
-
- for (auth = server->auths; auth != NULL; auth = auth->next) {
- if (strcmp(auth->name, name) == 0) {
- *errormsg = "Authentication process already exists "
- "with the same name";
- return NULL;
- }
- }
-
- return auth_settings_new(server, name);
-}
-
-static struct auth_passdb_settings *
-auth_passdb_settings_new(struct auth_settings *auth, const char *type)
-{
- struct auth_passdb_settings *as, **as_p;
-
- as = p_new(settings_pool, struct auth_passdb_settings, 1);
-
- as->parent = auth;
- as->driver = str_lcase(p_strdup(settings_pool, type));
-
- as_p = &auth->passdbs;
- while (*as_p != NULL)
- as_p = &(*as_p)->next;
- *as_p = as;
-
- return as;
-}
-
-static struct auth_userdb_settings *
-auth_userdb_settings_new(struct auth_settings *auth, const char *type)
-{
- struct auth_userdb_settings *as, **as_p;
-
- as = p_new(settings_pool, struct auth_userdb_settings, 1);
-
- as->parent = auth;
- as->driver = str_lcase(p_strdup(settings_pool, type));
-
- as_p = &auth->userdbs;
- while (*as_p != NULL)
- as_p = &(*as_p)->next;
- *as_p = as;
-
- return as;
-}
-
-static struct auth_socket_settings *
-auth_socket_settings_new(struct auth_settings *auth, const char *type)
-{
- struct auth_socket_settings *as, **as_p;
-
- as = p_new(settings_pool, struct auth_socket_settings, 1);
-
- as->parent = auth;
- as->type = str_lcase(p_strdup(settings_pool, type));
- as->master = default_socket_settings;
- as->client = default_socket_settings;
-
- as->master.path = DEFAULT_MASTER_SOCKET_PATH;
- as->client.path = DEFAULT_CLIENT_SOCKET_PATH;
-
- as_p = &auth->sockets;
- while (*as_p != NULL)
- as_p = &(*as_p)->next;
- *as_p = as;
-
- return as;
-}
-
-static struct auth_socket_settings *
-parse_new_auth_socket(struct auth_settings *auth, const char *name,
- const char **errormsg)
-{
- if (strcmp(name, "connect") != 0 && strcmp(name, "listen") != 0) {
- *errormsg = "Unknown auth socket type";
- return NULL;
- }
-
- if (auth->sockets != NULL && strcmp(name, "connect") == 0) {
- *errormsg = "With connect auth socket no other sockets "
- "can be used in same auth section";
- return NULL;
- }
-
- return auth_socket_settings_new(auth, name);
-}
-
-static struct namespace_settings *
-namespace_settings_new(struct server_settings *server, const char *type)
-{
- struct namespace_settings *ns, **ns_p;
-
- ns = p_new(settings_pool, struct namespace_settings, 1);
- *ns = default_namespace_settings;
-
- ns->parent = server;
- ns->type = str_lcase(p_strdup(settings_pool, type));
-
- ns_p = &server->namespaces;
- while (*ns_p != NULL)
- ns_p = &(*ns_p)->next;
- *ns_p = ns;
-
- return ns;
-}
-
-static struct namespace_settings *
-parse_new_namespace(struct server_settings *server, const char *name,
- const char **errormsg)
-{
- if (strcasecmp(name, "private") != 0 &&
- strcasecmp(name, "shared") != 0 &&
- strcasecmp(name, "public") != 0) {
- *errormsg = "Unknown namespace type";
- return NULL;
- }
-
- return namespace_settings_new(server, name);
-}
-
-static const char *parse_setting(const char *key, const char *value,
- struct settings_parse_ctx *ctx)
-{
- const char *error;
-
- 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;
-
- if (strncmp(key, "auth_", 5) == 0) {
- return parse_setting_from_defs(settings_pool,
- auth_setting_defs,
- ctx->auth,
- key + 5, value);
- }
- return error;
- case SETTINGS_TYPE_AUTH:
- if (strncmp(key, "auth_", 5) == 0)
- key += 5;
- return parse_setting_from_defs(settings_pool, auth_setting_defs,
- ctx->auth, key, value);
- case SETTINGS_TYPE_AUTH_SOCKET:
- return parse_setting_from_defs(settings_pool,
- auth_socket_setting_defs,
- ctx->auth_socket, key, value);
- case SETTINGS_TYPE_AUTH_PASSDB:
- return parse_setting_from_defs(settings_pool,
- auth_passdb_setting_defs,
- ctx->auth_passdb, key, value);
- case SETTINGS_TYPE_AUTH_USERDB:
- return parse_setting_from_defs(settings_pool,
- auth_userdb_setting_defs,
- ctx->auth_userdb, key, value);
- case SETTINGS_TYPE_NAMESPACE:
- return parse_setting_from_defs(settings_pool,
- namespace_setting_defs,
- ctx->namespace, key, value);
- case SETTINGS_TYPE_SOCKET:
- return parse_setting_from_defs(settings_pool,
- socket_setting_defs,
- ctx->socket, key, value);
- case SETTINGS_TYPE_DICT:
- key = p_strdup(settings_pool, key);
- value = p_strdup(settings_pool, value);
-
- array_append(&ctx->server->dicts, &key, 1);
- array_append(&ctx->server->dicts, &value, 1);
- return NULL;
- case SETTINGS_TYPE_PLUGIN:
- key = p_strdup(settings_pool, key);
- value = p_strdup(settings_pool, value);
-
- if (ctx->protocol == MAIL_PROTOCOL_ANY ||
- ctx->protocol == MAIL_PROTOCOL_IMAP) {
- array_append(&ctx->server->imap->plugin_envs, &key, 1);
- array_append(&ctx->server->imap->plugin_envs,
- &value, 1);
- }
- if (ctx->protocol == MAIL_PROTOCOL_ANY ||
- ctx->protocol == MAIL_PROTOCOL_POP3) {
- array_append(&ctx->server->pop3->plugin_envs, &key, 1);
- array_append(&ctx->server->pop3->plugin_envs,
- &value, 1);
- }
- return NULL;
- }
-
- i_unreached();
-}
-
-static struct server_settings *
-create_new_server(const char *name,
- struct settings *imap_defaults,
- struct settings *pop3_defaults)
-{
- struct server_settings *server;
-
- 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);
- server->auth_defaults = default_auth_settings;
-
- *server->imap = *imap_defaults;
- *server->pop3 = *pop3_defaults;
-
- p_array_init(&server->dicts, settings_pool, 4);
- p_array_init(&server->imap->plugin_envs, settings_pool, 8);
- p_array_init(&server->pop3->plugin_envs, settings_pool, 8);
-
- server->imap->server = server;
- server->imap->protocol = MAIL_PROTOCOL_IMAP;
- server->imap->login_executable = PKG_LIBEXECDIR"/imap-login";
- server->imap->mail_executable = PKG_LIBEXECDIR"/imap";
- server->imap->mail_plugin_dir = MODULEDIR"/imap";
-
- server->pop3->server = server;
- server->pop3->protocol = MAIL_PROTOCOL_POP3;
- server->pop3->login_executable = PKG_LIBEXECDIR"/pop3-login";
- server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3";
- server->pop3->mail_plugin_dir = MODULEDIR"/pop3";
-
- return server;
-}
-
-static bool parse_section(const char *type, const char *name,
- struct settings_parse_ctx *ctx, const char **errormsg)
-{
- struct server_settings *server;
-
- if (type == NULL) {
- /* section closing */
- if (ctx->level-- > 0) {
- ctx->type = ctx->parent_type;
- ctx->protocol = MAIL_PROTOCOL_ANY;
-
- switch (ctx->type) {
- case SETTINGS_TYPE_AUTH_SOCKET:
- ctx->parent_type = SETTINGS_TYPE_AUTH;
- break;
- default:
- ctx->parent_type = SETTINGS_TYPE_ROOT;
- break;
- }
- } else {
- ctx->type = SETTINGS_TYPE_ROOT;
- ctx->server = ctx->root;
- ctx->auth = &ctx->root->auth_defaults;
- ctx->namespace = NULL;
- }
- return TRUE;
- }
-
- ctx->level++;
- ctx->parent_type = ctx->type;
-
- if (strcmp(type, "server") == 0) {
- if (ctx->type != SETTINGS_TYPE_ROOT) {
- *errormsg = "Server section not allowed here";
- return FALSE;
- }
-
- 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(type, "protocol") == 0) {
- if ((ctx->type != SETTINGS_TYPE_ROOT &&
- ctx->type != SETTINGS_TYPE_SERVER) ||
- ctx->level != 1) {
- *errormsg = "Protocol section not allowed here";
- return FALSE;
- }
-
- if (strcmp(name, "imap") == 0)
- ctx->protocol = MAIL_PROTOCOL_IMAP;
- else if (strcmp(name, "pop3") == 0)
- ctx->protocol = MAIL_PROTOCOL_POP3;
- else if (strcmp(name, "lda") == 0)
- ctx->protocol = MAIL_PROTOCOL_LDA;
- else {
- *errormsg = "Unknown protocol name";
- return FALSE;
- }
- return TRUE;
- }
-
- 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;
- }
-
- if (ctx->type == SETTINGS_TYPE_AUTH &&
- strcmp(type, "socket") == 0) {
- ctx->type = SETTINGS_TYPE_AUTH_SOCKET;
- ctx->auth_socket = parse_new_auth_socket(ctx->auth,
- name, errormsg);
- return ctx->auth_socket != NULL;
- }
-
- if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "passdb") == 0) {
- ctx->type = SETTINGS_TYPE_AUTH_PASSDB;
- ctx->auth_passdb = auth_passdb_settings_new(ctx->auth, name);
- return TRUE;
- }
-
- if (ctx->type == SETTINGS_TYPE_AUTH && strcmp(type, "userdb") == 0) {
- ctx->type = SETTINGS_TYPE_AUTH_USERDB;
- ctx->auth_userdb = auth_userdb_settings_new(ctx->auth, name);
- return TRUE;
- }
-
- if (ctx->type == SETTINGS_TYPE_AUTH_SOCKET) {
- ctx->type = SETTINGS_TYPE_SOCKET;
-
- if (strcmp(type, "master") == 0) {
- ctx->socket = &ctx->auth_socket->master;
- ctx->socket->used = TRUE;
- return TRUE;
- }
-
- if (strcmp(type, "client") == 0) {
- ctx->socket = &ctx->auth_socket->client;
- ctx->socket->used = TRUE;
- return TRUE;
- }
- }
-
- if (strcmp(type, "namespace") == 0) {
- if (ctx->type != SETTINGS_TYPE_ROOT &&
- ctx->type != SETTINGS_TYPE_SERVER) {
- *errormsg = "Namespace section not allowed here";
- return FALSE;
- }
-
- ctx->type = SETTINGS_TYPE_NAMESPACE;
- ctx->namespace = parse_new_namespace(ctx->server, name,
- errormsg);
- return ctx->namespace != NULL;
- }
-
- if (strcmp(type, "dict") == 0) {
- if (ctx->type != SETTINGS_TYPE_ROOT &&
- ctx->type != SETTINGS_TYPE_SERVER) {
- *errormsg = "Plugin section not allowed here";
- return FALSE;
- }
-
- ctx->type = SETTINGS_TYPE_DICT;
- return TRUE;
- }
-
- if (strcmp(type, "plugin") == 0) {
- if (ctx->type != SETTINGS_TYPE_ROOT &&
- ctx->type != SETTINGS_TYPE_SERVER) {
- *errormsg = "Plugin section not allowed here";
- return FALSE;
- }
-
- ctx->type = SETTINGS_TYPE_PLUGIN;
- return TRUE;
- }
-
- *errormsg = "Unknown section type";
- return FALSE;
-}
-
static void
-settings_warn_needed_fds(struct server_settings *server ATTR_UNUSED)
+settings_warn_needed_fds(struct master_server_settings *server ATTR_UNUSED)
{
#ifdef HAVE_SETRLIMIT
struct rlimit rlim;
/* count only log pipes needed for login and mail processes. we need
more, but they're the ones that can use up most of the fds */
- for (; server != NULL; server = server->next) {
- if (server->imap != NULL)
- fd_count += server->imap->login_max_processes_count;
- if (server->pop3 != NULL)
- fd_count += server->pop3->login_max_processes_count;
- fd_count += server->defaults->max_mail_processes;
- }
+ if (server->imap != NULL)
+ fd_count += server->imap->login_max_processes_count;
+ if (server->pop3 != NULL)
+ fd_count += server->pop3->login_max_processes_count;
+ fd_count += server->defaults->max_mail_processes;
if (rlim.rlim_cur < fd_count) {
i_warning("fd limit %d is lower than what Dovecot can use under "
"full load (more than %u). Either grow the limit or "
"change login_max_processes_count and "
- "max_mail_processes settings",
+ "max_mail_processes master_settings",
(int)rlim.rlim_cur, fd_count);
}
#endif
}
-bool master_settings_read(const char *path, bool nochecks, bool nofixes)
+static void
+config_split_all_settings(struct master_settings *set, const char *input)
{
- struct settings_parse_ctx ctx;
- struct server_settings *server, *prev;
- struct auth_settings *auth;
- struct namespace_settings *ns;
- pool_t temp;
+ const char *p, *line;
+ string_t *str;
- memset(&ctx, 0, sizeof(ctx));
+ str = t_str_new(256);
+ p_array_init(&set->all_settings, settings_pool, 256);
+ for (p = input; *p != '\n'; p++) {
+ str_truncate(str, 0);
+ for (; *p != '='; p++) {
+ i_assert(*p != '\n' && *p != '\0');
+ str_append_c(str, i_toupper(*p));
+ }
+ for (; *p != '\n'; p++) {
+ i_assert(*p != '\0');
+ str_append_c(str, *p);
+ }
+ line = p_strdup(settings_pool, str_c(str));
+ array_append(&set->all_settings, &line, 1);
+ }
+}
- p_clear(settings_pool);
+static int config_exec(const char *path, const char *service,
+ struct master_settings **set_r)
+{
+ struct setting_parser_context *parser;
+ string_t *all_settings;
+ int ret;
+
+ all_settings = str_new(default_pool, 10240);
+ parser = settings_parser_init(settings_pool,
+ &master_setting_parser_info,
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+ settings_parse_save_input(parser, all_settings);
+ if ((ret = settings_parse_exec(parser, DOVECOT_CONFIG_BIN_PATH,
+ path, service)) == 0) {
+ *set_r = settings_parser_get(parser);
+ config_split_all_settings(*set_r, str_c(all_settings));
+ }
+ settings_parser_deinit(&parser);
+ str_free(&all_settings);
+ return ret;
+}
- ctx.type = SETTINGS_TYPE_ROOT;
- ctx.protocol = MAIL_PROTOCOL_ANY;
- ctx.server = ctx.root =
- create_new_server("default",
- &default_settings, &default_settings);
- ctx.auth = &ctx.server->auth_defaults;
+int master_settings_read(const char *path,
+ struct master_server_settings **set_r)
+{
+ struct master_server_settings *set;
- if (!settings_read(path, NULL, parse_setting, parse_section, &ctx))
- return FALSE;
+ p_clear(settings_pool);
+ set = p_new(settings_pool, struct master_server_settings, 1);
+
+ master_default_settings.mail_executable = NULL;
+ master_default_settings.login_executable = NULL;
+ if (config_exec(path, "", &set->defaults) < 0)
+ return -1;
+ set->defaults->protocol = MAIL_PROTOCOL_ANY;
+ set->defaults->server = set;
+
+ master_default_settings.mail_executable = PKG_LIBEXECDIR"/imap";
+ master_default_settings.login_executable = PKG_LIBEXECDIR"/imap-login";
+ if (config_exec(path, "imap", &set->imap) < 0)
+ return -1;
+ set->imap->protocol = MAIL_PROTOCOL_IMAP;
+ set->imap->server = set;
+
+ master_default_settings.mail_executable = PKG_LIBEXECDIR"/pop3";
+ master_default_settings.login_executable = PKG_LIBEXECDIR"/pop3-login";
+ if (config_exec(path, "pop3", &set->pop3) < 0)
+ return -1;
+ set->pop3->protocol = MAIL_PROTOCOL_POP3;
+ set->pop3->server = set;
+
+ *set_r = set;
+ return 0;
+}
- if (ctx.level != 0) {
- i_error("Missing '}'");
+bool master_settings_check(struct master_server_settings *set,
+ bool nochecks, bool nofixes)
+{
+ struct master_auth_settings *const *auths;
+ unsigned int i, count;
+ pool_t temp;
+
+ if ((*set->imap->protocols == '\0' ||
+ *set->pop3->protocols == '\0') && !nochecks) {
+ i_error("protocols: No protocols given in configuration file");
return FALSE;
}
-
- /* If server sections were defined, skip the root */
- if (ctx.root->next != NULL)
- ctx.root = ctx.root->next;
-
- if (!nochecks && !nofixes) {
- ctx.root->defaults = settings_is_active(ctx.root->imap) ?
- ctx.root->imap : ctx.root->pop3;
-
- path = t_strconcat(ctx.root->defaults->base_dir,
- "/master.pid", NULL);
- pid_file_check_running(path);
+ /* --exec-mail is used if nochecks=TRUE. Allow it regardless
+ of what's in protocols setting. */
+ if (!settings_is_active(set->imap) && !nochecks) {
+ if (strcmp(set->imap->protocols, "none") == 0) {
+ set->imap->protocol = MAIL_PROTOCOL_ANY;
+ if (!settings_fix(set->imap, nochecks, nofixes))
+ return FALSE;
+ }
+ set->imap = NULL;
+ } else {
+ if (!settings_fix(set->imap, nochecks, nofixes))
+ return FALSE;
}
- prev = NULL;
- for (server = ctx.root; server != NULL; server = server->next) {
- if ((*server->imap->protocols == '\0' ||
- *server->pop3->protocols == '\0') && !nochecks) {
- i_error("protocols: No protocols given "
- "in configuration file");
+ if (!settings_is_active(set->pop3) && !nochecks)
+ set->pop3 = NULL;
+ else {
+ if (!settings_fix(set->pop3, nochecks, nofixes))
return FALSE;
- }
- /* --exec-mail is used if nochecks=TRUE. Allow it regardless
- of what's in protocols setting. */
- if (!settings_is_active(server->imap) && !nochecks) {
- if (strcmp(server->imap->protocols, "none") == 0) {
- server->imap->protocol = MAIL_PROTOCOL_ANY;
- if (!settings_fix(server->imap, nochecks,
- nofixes))
- return FALSE;
- server->defaults = server->imap;
- }
- server->imap = NULL;
- } else {
- if (!settings_fix(server->imap, nochecks, nofixes))
- return FALSE;
- server->defaults = server->imap;
- }
+ }
- if (!settings_is_active(server->pop3) && !nochecks)
- server->pop3 = NULL;
- else {
- if (!settings_fix(server->pop3, nochecks, nofixes))
- return FALSE;
- if (server->defaults == NULL)
- server->defaults = server->pop3;
+ if (!settings_fix(set->defaults, nochecks, nofixes))
+ return FALSE;
+
+ if (!nochecks) {
+ auths = array_get(&set->defaults->auths, &count);
+ if (count == 0) {
+ i_error("Missing auth section");
+ return FALSE;
}
- if (server->defaults == NULL) {
- if (prev == NULL)
- ctx.root = server->next;
- else
- prev->next = server->next;
- } else {
- auth = server->auths;
- if (auth == NULL) {
- i_error("Missing auth section for server %s",
- server->name);
+ for (i = 0; i < count; i++) {
+ if (!auth_settings_verify(set->defaults, auths[i]))
return FALSE;
- }
-
- if (!nochecks) {
- for (; auth != NULL; auth = auth->next) {
- if (!auth_settings_verify(auth))
- return FALSE;
- }
- ns = server->namespaces;
- for (; ns != NULL; ns = ns->next) {
- if (!namespace_settings_verify(server, ns))
- return FALSE;
- }
- }
- prev = server;
}
}
- if (ctx.root == NULL) {
- /* We aren't actually checking them separately, but if it
- contains only invalid protocols we'll get here.. */
- i_error("Invalid protocols given in configuration file");
- return FALSE;
- }
-
if (!nochecks)
- settings_warn_needed_fds(ctx.root);
+ settings_warn_needed_fds(set);
/* settings ok, swap them */
temp = settings_pool;
settings_pool = settings2_pool;
settings2_pool = temp;
- settings_root = ctx.root;
+ master_set = set;
return TRUE;
}
-static void settings_dump(const struct setting_def *def, const void **sets,
- const char **set_names, unsigned int count,
- bool nondefaults, unsigned int indent)
+void master_settings_export_to_env(const struct master_settings *set)
{
- const char **str;
- unsigned int i;
-
- str = t_new(const char *, count);
- for (; def->name != NULL; def++) {
- bool same = TRUE;
-
- switch (def->type) {
- case SET_STR: {
- const char *const *strp;
-
- for (i = 0; i < count; i++) {
- strp = CONST_PTR_OFFSET(sets[i], def->offset);
- str[i] = *strp != NULL ? *strp : "";
- }
- break;
- }
- case SET_INT: {
- const unsigned int *n;
-
- for (i = 0; i < count; i++) {
- n = CONST_PTR_OFFSET(sets[i], def->offset);
- str[i] = dec2str(*n);
- }
- break;
- }
- case SET_BOOL: {
- const bool *b;
-
- for (i = 0; i < count; i++) {
- b = CONST_PTR_OFFSET(sets[i], def->offset);
- str[i] = *b ? "yes" : "no";
- }
- break;
- }
- }
-
- for (i = 2; i < count; i++) {
- if (strcmp(str[i], str[i-1]) != 0)
- same = FALSE;
- }
- if (same) {
- if (!nondefaults || strcmp(str[0], str[1]) != 0) {
- for (i = 0; i < indent; i++)
- putc(' ', stdout);
- printf("%s: %s\n", def->name, str[1]);
- }
- } else {
- for (i = 0; i < indent; i++)
- putc(' ', stdout);
- for (i = 1; i < count; i++) {
- printf("%s(%s): %s\n", def->name,
- set_names[i], str[i]);
- }
- }
- }
-}
-
-static void
-namespace_settings_dump(struct namespace_settings *ns, bool nondefaults)
-{
- const void *sets[2];
-
- sets[0] = t_malloc0(sizeof(struct namespace_settings));
- for (; ns != NULL; ns = ns->next) {
- printf("namespace:\n");
- sets[1] = ns;
- settings_dump(namespace_setting_defs, sets, NULL, 2,
- nondefaults, 2);
- }
-}
-
-static void auth_settings_dump(struct auth_settings *auth, bool nondefaults)
-{
- const struct auth_passdb_settings *passdb;
- const struct auth_userdb_settings *userdb;
- const struct auth_socket_settings *socket_set;
- const void *sets[2], *sets2[2];
- const void *empty_defaults;
-
- empty_defaults = t_malloc0(sizeof(struct auth_passdb_settings) +
- sizeof(struct auth_userdb_settings) +
- sizeof(struct auth_socket_settings));
-
- sets[0] = &default_auth_settings;
- sets2[0] = empty_defaults;
-
- for (; auth != NULL; auth = auth->next) {
- printf("auth %s:\n", auth->name);
- sets[1] = auth;
- settings_dump(auth_setting_defs, sets, NULL, 2, nondefaults, 2);
-
- passdb = auth->passdbs;
- for (; passdb != NULL; passdb = passdb->next) {
- printf(" passdb:\n");
- sets2[1] = passdb;
- settings_dump(auth_passdb_setting_defs, sets2, NULL, 2,
- nondefaults, 4);
- }
-
- userdb = auth->userdbs;
- for (; userdb != NULL; userdb = userdb->next) {
- printf(" userdb:\n");
- sets2[1] = userdb;
- settings_dump(auth_userdb_setting_defs, sets2, NULL, 2,
- nondefaults, 4);
- }
-
- socket_set = auth->sockets;
- for (; socket_set != NULL; socket_set = socket_set->next) {
- printf(" socket:\n");
- sets2[1] = socket_set;
- settings_dump(auth_socket_setting_defs, sets2, NULL, 2,
- nondefaults, 4);
-
- if (socket_set->client.used) {
- printf(" client:\n");
- sets2[1] = &socket_set->client;
- settings_dump(socket_setting_defs, sets2, NULL,
- 2, nondefaults, 6);
- }
-
- if (socket_set->master.used) {
- printf(" master:\n");
- sets2[1] = &socket_set->master;
- settings_dump(socket_setting_defs, sets2, NULL,
- 2, nondefaults, 6);
- }
- }
- }
-}
-
-static void plugin_settings_dump(const struct settings *set)
-{
- const char *const *envs;
+ const char *const *sets;
unsigned int i, count;
- envs = array_get(&set->plugin_envs, &count);
- i_assert((count % 2) == 0);
-
- if (count == 0)
- return;
-
- printf("plugin:\n");
- for (i = 0; i < count; i += 2)
- printf(" %s: %s\n", envs[i], envs[i+1]);
-}
-
-static void dict_settings_dump(const struct server_settings *set)
-{
- const char *const *dicts;
- unsigned int i, count;
-
- dicts = array_get(&set->dicts, &count);
- i_assert((count % 2) == 0);
-
- if (count == 0)
- return;
-
- printf("dict:\n");
- for (i = 0; i < count; i += 2)
- printf(" %s: %s\n", dicts[i], dicts[i+1]);
-}
-
-void master_settings_dump(struct server_settings *set, bool nondefaults)
-{
- const void *sets[4];
- const char *set_names[4];
- unsigned int count;
-
- sets[0] = &default_settings;
- sets[1] = set->defaults;
-
- set_names[0] = NULL;
- set_names[1] = "default";
-
- count = 2;
- if (set->imap != NULL) {
- sets[count] = set->imap;
- set_names[count] = "imap";
- count++;
- }
- if (set->pop3 != NULL) {
- sets[count] = set->pop3;
- set_names[count] = "pop3";
- count++;
- }
- settings_dump(setting_defs, sets, set_names, count, nondefaults, 0);
- namespace_settings_dump(set->namespaces, nondefaults);
- auth_settings_dump(set->auths, nondefaults);
- plugin_settings_dump(set->defaults);
- dict_settings_dump(set);
+ sets = array_get(&set->all_settings, &count);
+ for (i = 0; i < count; i++)
+ env_put(sets[i]);
}
void master_settings_init(void)
#include "network.h"
+#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf"
+
enum mail_protocol {
MAIL_PROTOCOL_ANY,
MAIL_PROTOCOL_IMAP,
};
ARRAY_DEFINE_TYPE(listener, struct listener);
-struct settings {
- struct server_settings *server;
- enum mail_protocol protocol;
+struct master_auth_socket_unix_settings {
+ const char *path;
+};
+
+struct master_auth_socket_settings {
+ const char *type;
+
+ ARRAY_DEFINE(masters, struct master_auth_socket_unix_settings *);
+};
+
+struct master_auth_settings {
+ const char *name;
+ const char *executable;
+ const char *user;
+ const char *chroot;
+
+ unsigned int count;
+ unsigned int process_size;
+
+ const char *mechanisms;
+ bool debug;
+
+ ARRAY_DEFINE(sockets, struct master_auth_socket_settings *);
+
+ /* .. */
+ uid_t uid;
+ gid_t gid;
+};
+struct master_settings {
/* common */
const char *base_dir;
const char *log_path;
const char *ssl_listen;
const char *ssl;
- const char *ssl_ca_file;
- const char *ssl_cert_file;
const char *ssl_key_file;
- const char *ssl_key_password;
unsigned int ssl_parameters_regenerate;
- const char *ssl_cipher_list;
- const char *ssl_cert_username_field;
- bool ssl_verify_client_cert;
- bool disable_plaintext_auth;
- bool verbose_ssl;
- bool shutdown_clients;
bool nfs_check;
bool version_ignore;
const char *login_dir;
const char *login_executable;
const char *login_user;
- const char *login_greeting;
- const char *login_log_format_elements;
- const char *login_log_format;
bool login_process_per_connection;
bool login_chroot;
- const char *login_trusted_networks;
+ bool disable_plaintext_auth;
unsigned int login_process_size;
unsigned int login_processes_count;
unsigned int login_max_processes_count;
- unsigned int login_max_connections;
/* mail */
const char *valid_chroot_dirs;
const char *mail_uid;
const char *mail_gid;
+ const char *mail_plugins;
+ const char *imap_capability;
+
const char *mail_location;
- const char *mail_cache_fields;
- const char *mail_never_cache_fields;
- unsigned int mail_cache_min_mail_count;
- unsigned int mailbox_idle_check_interval;
bool mail_debug;
- bool mail_full_filesystem_access;
- unsigned int mail_max_keyword_length;
- bool mail_save_crlf;
- bool mmap_disable;
- bool dotlock_use_excl;
- bool fsync_disable;
- bool mail_nfs_storage;
bool mail_nfs_index;
- bool mailbox_list_index_disable;
- const char *lock_method;
- bool maildir_stat_dirs;
- bool maildir_copy_with_hardlinks;
- bool maildir_copy_preserve_filename;
- const char *mbox_read_locks;
- const char *mbox_write_locks;
- unsigned int mbox_lock_timeout;
- unsigned int mbox_dotlock_change_timeout;
- unsigned int mbox_min_index_size;
- bool mbox_dirty_syncs;
- bool mbox_very_dirty_syncs;
- bool mbox_lazy_writes;
- unsigned int dbox_rotate_size;
- unsigned int dbox_rotate_min_size;
- unsigned int dbox_rotate_days;
unsigned int umask;
bool mail_drop_priv_before_exec;
const char *mail_executable;
unsigned int mail_process_size;
- const char *mail_plugins;
- const char *mail_plugin_dir;
const char *mail_log_prefix;
unsigned int mail_log_max_lines_per_sec;
- /* imap */
- unsigned int imap_max_line_length;
- const char *imap_capability;
- const char *imap_client_workarounds;
- const char *imap_logout_format;
- const char *imap_id_send;
- const char *imap_id_log;
-
- /* pop3 */
- bool pop3_no_flag_updates;
- bool pop3_enable_last;
- bool pop3_reuse_xuidl;
- bool pop3_lock_session;
- const char *pop3_uidl_format;
- const char *pop3_client_workarounds;
- const char *pop3_logout_format;
-
/* dict */
const char *dict_db_config;
unsigned int dict_process_count;
+ ARRAY_DEFINE(auths, struct master_auth_settings *);
+
+ ARRAY_DEFINE(dicts, const char *);
+ ARRAY_DEFINE(plugin_envs, const char *);
+
+#ifndef CONFIG_BINARY
/* .. */
+ struct master_server_settings *server;
+ enum mail_protocol protocol;
+
ARRAY_TYPE(listener) listens;
ARRAY_TYPE(listener) ssl_listens;
gid_t mail_gid_t, mail_priv_gid_t;
const char *imap_generated_capability;
-
- ARRAY_DEFINE(plugin_envs, const char *);
-};
-
-struct socket_settings {
- const char *path;
- unsigned int mode;
- const char *user;
- const char *group;
-
- unsigned int used:1;
-};
-
-struct auth_socket_settings {
- struct auth_settings *parent;
- struct auth_socket_settings *next;
-
- const char *type;
- struct socket_settings master;
- struct socket_settings client;
-};
-
-struct auth_passdb_settings {
- struct auth_settings *parent;
- struct auth_passdb_settings *next;
-
- const char *driver;
- const char *args;
- bool deny;
- bool pass;
- bool master;
-};
-
-struct auth_userdb_settings {
- struct auth_settings *parent;
- struct auth_userdb_settings *next;
-
- const char *driver;
- const char *args;
-};
-
-struct auth_settings {
- struct server_settings *parent;
- struct auth_settings *next;
-
- const char *name;
- const char *mechanisms;
- const char *realms;
- const char *default_realm;
- unsigned int cache_size;
- unsigned int cache_ttl;
- unsigned int cache_negative_ttl;
- const char *executable;
- const char *user;
- const char *chroot;
- const char *username_chars;
- const char *username_translation;
- const char *username_format;
- const char *master_user_separator;
- const char *anonymous_username;
- const char *krb5_keytab;
- const char *gssapi_hostname;
- const char *winbind_helper_path;
- unsigned int failure_delay;
-
- bool verbose, debug, debug_passwords;
- bool ssl_require_client_cert;
- bool ssl_username_from_cert;
- bool use_winbind;
-
- unsigned int count;
- unsigned int worker_max_count;
- unsigned int process_size;
-
- /* .. */
- uid_t uid;
- gid_t gid;
- struct auth_passdb_settings *passdbs;
- struct auth_userdb_settings *userdbs;
- struct auth_socket_settings *sockets;
-};
-
-struct namespace_settings {
- struct server_settings *parent;
- struct namespace_settings *next;
-
- const char *type;
- const char *separator;
- const char *prefix;
- const char *location;
- const char *alias_for;
-
- bool inbox;
- bool hidden;
- const char *list;
- bool subscriptions;
+ ARRAY_TYPE(const_string) all_settings;
+#endif
};
-struct server_settings {
- struct server_settings *next;
-
- const char *name;
- struct settings *defaults;
- struct settings *imap;
- struct settings *pop3;
- struct auth_settings *auths;
- struct auth_settings auth_defaults;
- struct namespace_settings *namespaces;
-
- ARRAY_DEFINE(dicts, const char *);
+struct master_server_settings {
+ struct master_settings *defaults;
+ struct master_settings *imap;
+ struct master_settings *pop3;
gid_t login_gid;
};
-extern struct server_settings *settings_root;
-
-bool master_settings_read(const char *path, bool nochecks, bool nofixes);
+extern struct master_server_settings *master_set;
+extern struct setting_parser_info master_setting_parser_info;
-void master_settings_dump(struct server_settings *set, bool nondefaults);
+int master_settings_read(const char *path,
+ struct master_server_settings **set_r);
+bool master_settings_check(struct master_server_settings *set,
+ bool nochecks, bool nofixes);
+void master_settings_export_to_env(const struct master_settings *set);
void master_settings_init(void);
void master_settings_deinit(void);
if (dup2(log_fd, 2) < 0)
i_fatal("dup2(stderr) failed: %m");
- child_process_init_env();
+ child_process_init_env(master_set->defaults);
client_process_exec(t_strconcat(binpath, " "SSL_PARAMETERS_PERM_PATH,
NULL), "");
i_fatal_status(FATAL_EXEC, "execv(%s) failed: %m", binpath);
i_free_and_null(generating_path);
}
-static bool check_parameters_file_set(struct settings *set)
+static bool check_parameters_file_set(struct master_settings *set)
{
const char *path;
struct stat st, st2;
void ssl_check_parameters_file(void)
{
- struct server_settings *server;
-
if (generating_path != NULL)
return;
- for (server = settings_root; server != NULL; server = server->next) {
- if (server->defaults != NULL &&
- !check_parameters_file_set(server->defaults))
- break;
- }
+ (void)check_parameters_file_set(master_set->defaults);
}
static void check_parameters_file_timeout(void *context ATTR_UNUSED)
i_fatal("ACL backend initialization failed");
flags = mailbox_list_get_flags(list);
- if ((flags & MAILBOX_LIST_FLAG_FULL_FS_ACCESS) != 0) {
+ if (list->mail_set->mail_full_filesystem_access) {
/* not necessarily, but safer to do this for now. */
i_fatal("mail_full_filesystem_access=yes is "
"incompatible with ACLs");
"INBOX");
if (path == NULL) {
/* in-memory indexes */
- if ((box->storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+ if (box->storage->set->mail_debug)
i_info("fts squat: Disabled with in-memory indexes");
return NULL;
}
mailbox_get_name(box));
if (*path == '\0') {
/* in-memory indexes */
- if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
+ if (storage->set->mail_debug)
i_info("fts squat: Disabled with in-memory indexes");
return NULL;
}
mailbox_get_status(box, STATUS_UIDVALIDITY, &status);
- if ((storage->flags & (MAIL_STORAGE_FLAG_MMAP_DISABLE |
- MAIL_STORAGE_FLAG_MMAP_NO_WRITE)) != 0)
+ if (storage->set->mmap_disable || storage->set->mmap_no_write)
flags |= SQUAT_INDEX_FLAG_MMAP_DISABLE;
- if ((storage->flags & MAIL_STORAGE_FLAG_NFS_FLUSH_INDEX) != 0)
+ if (storage->set->mail_nfs_index)
flags |= SQUAT_INDEX_FLAG_NFS_FLUSH;
- if ((storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0)
+ if (storage->set->dotlock_use_excl)
flags |= SQUAT_INDEX_FLAG_DOTLOCK_USE_EXCL;
backend = i_new(struct squat_fts_backend, 1);
fbox->backend_fast = backend;
}
}
- if ((box->storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0 &&
+ if (box->storage->set->mail_debug &&
fbox->backend_substr == NULL && fbox->backend_fast == NULL)
i_info("fts: No backends enabled by the fts setting");
}
const char *imap_acl_plugin_version = PACKAGE_VERSION;
+static void (*next_hook_client_created)(struct client **client);
static bool acl_anyone_allow = FALSE;
static struct mailbox *
return TRUE;
}
+static void imap_acl_client_created(struct client **client)
+{
+ str_append((*client)->capability_string, " ACL RIGHTS=texk");
+
+ if (next_hook_client_created != NULL)
+ next_hook_client_created(client);
+}
+
void imap_acl_plugin_init(void)
{
const char *env;
if (env != NULL)
acl_anyone_allow = strcmp(env, "allow") == 0;
- str_append(capability_string, " ACL RIGHTS=texk");
-
command_register("LISTRIGHTS", cmd_listrights, 0);
command_register("GETACL", cmd_getacl, 0);
command_register("MYRIGHTS", cmd_myrights, 0);
command_register("SETACL", cmd_setacl, 0);
command_register("DELETEACL", cmd_deleteacl, 0);
+
+ next_hook_client_created = hook_client_created;
+ hook_client_created = imap_acl_client_created;
}
void imap_acl_plugin_deinit(void)
command_unregister("SETACL");
command_unregister("DELETEACL");
command_unregister("LISTRIGHTS");
+
+ hook_client_created = next_hook_client_created;
}
#define QUOTA_USER_SEPARATOR ':'
const char *imap_quota_plugin_version = PACKAGE_VERSION;
+static void (*next_hook_client_created)(struct client **client);
static const char *
imap_quota_root_get_name(struct mail_user *user, struct mail_user *owner,
return TRUE;
}
+static void imap_quota_client_created(struct client **client)
+{
+ str_append((*client)->capability_string, " QUOTA");
+
+ if (next_hook_client_created != NULL)
+ next_hook_client_created(client);
+}
+
void imap_quota_plugin_init(void)
{
command_register("GETQUOTAROOT", cmd_getquotaroot, 0);
command_register("GETQUOTA", cmd_getquota, 0);
command_register("SETQUOTA", cmd_setquota, 0);
- str_append(capability_string, " QUOTA");
+
+ next_hook_client_created = hook_client_created;
+ hook_client_created = imap_quota_client_created;
}
void imap_quota_plugin_deinit(void)
command_unregister("GETQUOTAROOT");
command_unregister("GETQUOTA");
command_unregister("SETQUOTA");
+
+ hook_client_created = next_hook_client_created;
}
/* use ~/mbox as the INBOX */
name = mstorage->snarf_inbox_path;
use_snarfing = TRUE;
- storage->flags |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
- list->flags |= MAILBOX_LIST_FLAG_FULL_FS_ACCESS;
+ storage->set->mail_full_filesystem_access = TRUE;
} else if (errno != ENOENT) {
mail_storage_set_critical(storage,
"stat(%s) failed: %m",
const char *data, struct mail_storage *storage,
const char **layout_r, const char **error_r)
{
- bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+ bool debug = storage->set->mail_debug;
*layout_r = "fs";
storage, &storage->list_module_ctx);
/* finish list init after we've overridden vfuncs */
- mailbox_list_init(_storage->list, _storage->ns, &list_set,
- mail_storage_get_list_flags(_storage->flags));
+ mailbox_list_init(_storage->list, _storage->ns, &list_set, 0);
return 0;
}
MEMBER(mailbox_is_file) FALSE,
{
+ NULL,
virtual_class_init,
virtual_class_deinit,
virtual_alloc,
pop3_login_LDADD = \
../login-common/liblogin-common.a \
../lib-auth/libauth.a \
+ ../lib-settings/libsettings.a \
../lib/liblib.a \
$(SSL_LIBS)
if (ssl_initialized && !client->common.tls)
str_append(str, "STLS\r\n");
- if (!disable_plaintext_auth || client->common.secured)
+ if (!login_settings->disable_plaintext_auth || client->common.secured)
str_append(str, "USER\r\n");
str_append(str, "SASL");
c) we allow insecure authentication
*/
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
- (client->common.secured || !disable_plaintext_auth ||
+ (client->common.secured ||
+ !login_settings->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0)) {
str_append_c(str, ' ');
str_append(str, mech[i].name);
master_user = *args + 7;
else if (strncmp(*args, "user=", 5) == 0) {
/* already handled in login-common */
- } else if (auth_debug) {
+ } else if (login_settings->auth_debug) {
i_info("Ignoring unknown passdb extra field: %s",
*args);
}
const struct auth_mech_desc *mech;
const char *mech_name, *p;
- if (!client->common.secured && ssl_required) {
- if (verbose_auth) {
+ if (!client->common.secured &&
+ strcmp(login_settings->ssl, "required") == 0) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"SSL required for authentication");
}
mech = auth_client_get_available_mechs(auth_client, &count);
for (i = 0; i < count; i++) {
if ((mech[i].flags & MECH_SEC_PRIVATE) == 0 &&
- (client->common.secured || disable_plaintext_auth ||
+ (client->common.secured ||
+ login_settings->disable_plaintext_auth ||
(mech[i].flags & MECH_SEC_PLAINTEXT) == 0))
client_send_line(client, mech[i].name);
}
static bool check_plaintext_auth(struct pop3_client *client)
{
- if (client->common.secured || !disable_plaintext_auth)
+ if (client->common.secured ||
+ !login_settings->disable_plaintext_auth)
return TRUE;
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common, "Login failed: "
"Plaintext authentication disabled");
}
const char *p;
if (client->apop_challenge == NULL) {
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common,
"APOP failed: APOP not enabled");
}
/* <username> <md5 sum in hex> */
p = strchr(args, ' ');
if (p == NULL || strlen(p+1) != 32) {
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common,
"APOP failed: Invalid parameters");
}
buffer_append_c(apop_data, '\0');
if (hex_to_binary(p+1, apop_data) < 0) {
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
client_syslog(&client->common, "APOP failed: "
"Invalid characters in MD5 response");
}
{
const char *addr;
- if (!verbose_proctitle || !process_per_connection)
+ if (!login_settings->verbose_proctitle ||
+ !login_settings->login_process_per_connection)
return;
addr = net_ip2addr(&client->common.ip);
void client_destroy_oldest(void)
{
+ unsigned int max_connections = login_settings->login_max_connections;
struct client *client;
struct pop3_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
unsigned int i, destroy_count;
client->io = io_add(client->common.fd, IO_READ, client_input, client);
client->apop_challenge = get_apop_challenge(client);
- client_send_line(client, t_strconcat("+OK ", greeting,
+ client_send_line(client, t_strconcat("+OK ",
+ login_settings->login_greeting,
client->apop_challenge != NULL ?
" " : NULL,
client->apop_challenge, NULL));
else
client_send_line(client, line);
- if (verbose_auth) {
+ if (login_settings->verbose_auth) {
str = t_str_new(128);
str_printfa(str, "proxy(%s): Login failed to %s:%u",
client->common.virtual_user,
AM_CPPFLAGS = \
-I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
-I$(top_srcdir)/src/lib-dict \
-I$(top_srcdir)/src/lib-mail \
-I$(top_srcdir)/src/lib-storage \
libs = \
$(STORAGE_LIBS) \
../lib-dict/libdict.a \
+ ../lib-settings/libsettings.a \
$(unused_objects)
pop3_LDADD = \
pop3_SOURCES = \
client.c \
commands.c \
- main.c
+ main.c \
+ pop3-settings.c
headers = \
capability.h \
client.h \
commands.h \
- common.h
+ common.h \
+ pop3-settings.h
if INSTALL_HEADERS
pkginc_libdir=$(pkgincludedir)/src/pop3
return FALSE;
}
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+ const struct pop3_settings *set)
{
struct mail_storage *storage;
const char *inbox;
net_set_nonblock(fd_out, TRUE);
client = i_new(struct client, 1);
+ client->set = set;
client->fd_in = fd_in;
client->fd_out = fd_out;
client->input = i_stream_create_fd(fd_in, MAX_INBUF_SIZE, FALSE);
storage = client->inbox_ns->storage;
flags = MAILBOX_OPEN_POP3_SESSION;
- if (no_flag_updates)
+ if (set->pop3_no_flag_updates)
flags |= MAILBOX_OPEN_KEEP_RECENT;
- if (lock_session)
+ if (set->pop3_lock_session)
flags |= MAILBOX_OPEN_KEEP_LOCKED;
client->mailbox = mailbox_open(&storage, "INBOX", NULL, flags);
if (client->mailbox == NULL) {
tab[8].value = dec2str(client->output->offset);
str = t_str_new(128);
- var_expand(str, logout_format, tab);
+ var_expand(str, client->set->pop3_logout_format, tab);
return str_c(str);
}
unsigned char *deleted_bitmask;
+ /* settings: */
+ const struct pop3_settings *set;
+ enum client_workarounds workarounds;
+ enum uidl_keys uidl_keymask;
+
unsigned int disconnected:1;
unsigned int deleted:1;
unsigned int waiting_input:1;
/* Create new client with specified input/output handles. socket specifies
if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user,
+ const struct pop3_settings *set);
void client_destroy(struct client *client, const char *reason);
/* Disconnect client connection */
#include "var-expand.h"
#include "message-size.h"
#include "mail-storage.h"
+#include "mail-storage-settings.h"
#include "mail-search-build.h"
#include "capability.h"
#include "commands.h"
add = '.';
break;
} else if (data[i] == '\0' &&
- (client_workarounds &
+ (client->workarounds &
WORKAROUND_OUTLOOK_NO_NULS) != 0) {
add = 0x80;
break;
(void)o_stream_send(client->output, "\r\n", 2);
}
- if (!ctx->in_body && (client_workarounds & WORKAROUND_OE_NS_EOH) != 0) {
+ if (!ctx->in_body &&
+ (client->workarounds & WORKAROUND_OE_NS_EOH) != 0) {
/* Add the missing end of headers line. */
(void)o_stream_send(client->output, "\r\n", 2);
}
return ret;
}
- if (body_lines == (uoff_t)-1 && !no_flag_updates) {
+ if (body_lines == (uoff_t)-1 && !client->set->pop3_no_flag_updates) {
if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
/* mark the message seen with RETR command */
(void)mail_update_flags(ctx->mail,
client->deleted_size = 0;
}
- if (enable_last_command) {
+ if (client->set->pop3_enable_last) {
/* remove all \Seen flags (as specified by RFC 1460) */
search_args = pop3_search_build(client, 0);
search_ctx = mailbox_search_init(client->trans,
unsigned int message;
};
-static void pop3_get_uid(struct cmd_uidl_context *ctx,
+static void pop3_get_uid(struct client *client, struct cmd_uidl_context *ctx,
struct var_expand_table *tab, string_t *str)
{
char uid_str[MAX_INT_STRLEN];
return;
}
- if (reuse_xuidl &&
+ if (client->set->pop3_reuse_xuidl &&
mail_get_first_header(ctx->mail, "X-UIDL", &uidl) > 0) {
str_append(str, uidl);
return;
}
- if ((uidl_keymask & UIDL_UID) != 0) {
+ if ((client->uidl_keymask & UIDL_UID) != 0) {
i_snprintf(uid_str, sizeof(uid_str), "%u",
ctx->mail->uid);
tab[1].value = uid_str;
}
- if ((uidl_keymask & UIDL_MD5) != 0) {
+ if ((client->uidl_keymask & UIDL_MD5) != 0) {
if (mail_get_special(ctx->mail, MAIL_FETCH_HEADER_MD5,
&tab[2].value) < 0 ||
*tab[2].value == '\0') {
i_fatal("UIDL: Header MD5 not found");
}
}
- if ((uidl_keymask & UIDL_FILE_NAME) != 0) {
+ if ((client->uidl_keymask & UIDL_FILE_NAME) != 0) {
if (mail_get_special(ctx->mail,
MAIL_FETCH_UIDL_FILE_NAME,
&tab[3].value) < 0 ||
i_fatal("UIDL: File name not found");
}
}
- var_expand(str, uidl_format, tab);
+ var_expand(str, client->set->pop3_uidl_format, tab);
}
static bool list_uids_iter(struct client *client, struct cmd_uidl_context *ctx)
str_truncate(str, 0);
str_printfa(str, ctx->message == 0 ? "%u " : "+OK %u ",
ctx->mail->seq);
- pop3_get_uid(ctx, tab, str);
+ pop3_get_uid(client, ctx, tab, str);
ret = client_send_line(client, "%s", str_c(str));
if (ret < 0)
ctx->message = message;
wanted_fields = 0;
- if ((uidl_keymask & UIDL_MD5) != 0)
+ if ((client->uidl_keymask & UIDL_MD5) != 0)
wanted_fields |= MAIL_FETCH_HEADER_MD5;
ctx->search_ctx = mailbox_search_init(client->trans, search_args, NULL);
case 'L':
if (strcmp(name, "LIST") == 0)
return cmd_list(client, args);
- if (strcmp(name, "LAST") == 0 && enable_last_command)
+ if (strcmp(name, "LAST") == 0 && client->set->pop3_enable_last)
return cmd_last(client, args);
break;
case 'N':
#ifndef COMMON_H
#define COMMON_H
-#include "lib.h"
-#include "client.h"
-
enum client_workarounds {
WORKAROUND_OUTLOOK_NO_NULS = 0x01,
WORKAROUND_OE_NS_EOH = 0x02
UIDL_FILE_NAME = 0x08
};
+#include "lib.h"
+#include "client.h"
+#include "pop3-settings.h"
+
extern struct ioloop *ioloop;
-extern enum client_workarounds client_workarounds;
-extern bool enable_last_command, no_flag_updates, reuse_xuidl, lock_session;
-extern const char *uidl_format, *logout_format;
-extern enum uidl_keys uidl_keymask;
extern void (*hook_client_created)(struct client **client);
static char log_prefix[128]; /* syslog() needs this to be permanent */
static struct io *log_io = NULL;
-enum client_workarounds client_workarounds = 0;
-bool enable_last_command = FALSE;
-bool no_flag_updates = FALSE;
-bool reuse_xuidl = FALSE;
-bool lock_session = FALSE;
-const char *uidl_format, *logout_format;
-enum uidl_keys uidl_keymask;
-
static void sig_die(int signo, void *context ATTR_UNUSED)
{
/* warn about being killed because of some signal, except SIGINT (^C)
io_loop_stop(ioloop);
}
-static void parse_workarounds(void)
+static enum client_workarounds
+parse_workarounds(const struct pop3_settings *set)
{
- struct client_workaround_list *list;
- const char *env, *const *str;
-
- env = getenv("POP3_CLIENT_WORKAROUNDS");
- if (env == NULL)
- return;
+ enum client_workarounds client_workarounds = 0;
+ struct client_workaround_list *list;
+ const char *const *str;
- for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
+ str = t_strsplit_spaces(set->pop3_client_workarounds, " ,");
+ for (; *str != NULL; str++) {
list = client_workaround_list;
for (; list->name != NULL; list++) {
if (strcasecmp(*str, list->name) == 0) {
if (list->name == NULL)
i_fatal("Unknown client workaround: %s", *str);
}
+ return client_workarounds;
}
static enum uidl_keys parse_uidl_keymask(const char *format)
i_set_failure_timestamp_format(getenv("LOGSTAMP"));
}
-static void drop_privileges(void)
+static void main_preinit(const struct pop3_settings **set_r,
+ const struct mail_user_settings **user_set_r)
{
const char *version;
/* Log file or syslog opening probably requires roots */
open_logfile();
- /* Load the plugins before chrooting. Their init() is called later. */
- if (getenv("MAIL_PLUGINS") != NULL) {
- const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
+ mail_storage_init();
+ mail_storage_register_all();
+ mailbox_list_register_all();
- if (plugin_dir == NULL)
- plugin_dir = MODULEDIR"/pop3";
- modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
- TRUE, version);
- }
+ /* read settings after registering storages so they can have their
+ own setting definitions too */
+ pop3_settings_read(set_r, user_set_r);
+
+ /* Load the plugins before chrooting. Their init() is called later. */
+ modules = *(*set_r)->mail_plugins == '\0' ? NULL :
+ module_dir_load((*set_r)->mail_plugin_dir,
+ (*set_r)->mail_plugins, TRUE, version);
restrict_access_by_env(!IS_STANDALONE());
}
-static bool main_init(void)
+static bool main_init(const struct pop3_settings *set,
+ const struct mail_user_settings *user_set)
{
struct mail_user *user;
struct client *client;
- const char *str;
+ const char *str, *error;
bool ret = TRUE;
lib_signals_init();
if (getenv("USER") == NULL)
i_fatal("USER environment missing");
- if (getenv("DEBUG") != NULL) {
+ if (set->mail_debug) {
i_info("Effective uid=%s, gid=%s",
dec2str(geteuid()), dec2str(getegid()));
}
- if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
+ if (set->shutdown_clients) {
/* If master dies, the log fd gets closed and we'll quit */
log_io = io_add(STDERR_FILENO, IO_ERROR,
log_error_callback, NULL);
dict_drivers_register_builtin();
mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
- mail_storage_init();
- mail_storage_register_all();
- mailbox_list_register_all();
clients_init();
module_dir_init(modules);
- parse_workarounds();
- enable_last_command = getenv("POP3_ENABLE_LAST") != NULL;
- no_flag_updates = getenv("POP3_NO_FLAG_UPDATES") != NULL;
- reuse_xuidl = getenv("POP3_REUSE_XUIDL") != NULL;
- lock_session = getenv("POP3_LOCK_SESSION") != NULL;
-
- uidl_format = getenv("POP3_UIDL_FORMAT");
- if (uidl_format == NULL || *uidl_format == '\0')
- uidl_format = "%08Xu%08Xv";
- logout_format = getenv("POP3_LOGOUT_FORMAT");
- if (logout_format == NULL)
- logout_format = "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s";
- uidl_keymask = parse_uidl_keymask(uidl_format);
- if (uidl_keymask == 0)
- i_fatal("pop3_uidl_format setting doesn't contain any "
- "%% variables.");
-
- user = mail_user_init(getenv("USER"));
+ user = mail_user_alloc(getenv("USER"), user_set);
mail_user_set_home(user, getenv("HOME"));
- if (mail_namespaces_init(user) < 0)
- i_fatal("Namespace initialization failed");
+ if (mail_user_init(user, &error) < 0)
+ i_fatal("Mail user initialization failed: %s", error);
+ if (mail_namespaces_init(user, &error) < 0)
+ i_fatal("Namespace initialization failed: %s", error);
- client = client_create(0, 1, user);
+ client = client_create(0, 1, user, set);
if (client == NULL)
return FALSE;
+ client->workarounds = parse_workarounds(set);
+ client->uidl_keymask = parse_uidl_keymask(set->pop3_uidl_format);
+ if (client->uidl_keymask == 0) {
+ i_fatal("pop3_uidl_format setting doesn't contain any "
+ "%% variables.");
+ }
if (!IS_STANDALONE())
client_send_line(client, "+OK Logged in.");
int main(int argc ATTR_UNUSED, char *argv[], char *envp[])
{
+ const struct pop3_settings *set;
+ const struct mail_user_settings *user_set;
+
#ifdef DEBUG
- if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
+ if (!IS_STANDALONE() && getenv("GDB") == NULL)
fd_debug_verify_leaks(3, 1024);
#endif
if (IS_STANDALONE() && getuid() == 0 &&
/* NOTE: we start rooted, so keep the code minimal until
restrict_access_by_env() is called */
lib_init();
- drop_privileges();
+ main_preinit(&set, &user_set);
process_title_init(argv, envp);
ioloop = io_loop_create();
- if (main_init())
+ if (main_init(set, user_set))
io_loop_run(ioloop);
main_deinit();
--- /dev/null
+/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "mail-storage-settings.h"
+#include "pop3-settings.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#undef DEF
+#undef DEFLIST
+#define DEF(type, name) \
+ { type, #name, offsetof(struct pop3_settings, name), NULL }
+#define DEFLIST(field, name, defines) \
+ { SET_DEFLIST, name, offsetof(struct pop3_settings, field), defines }
+
+static struct setting_define pop3_setting_defines[] = {
+ DEF(SET_BOOL, mail_debug),
+ DEF(SET_BOOL, shutdown_clients),
+ DEF(SET_BOOL, verbose_proctitle),
+
+ DEF(SET_STR, mail_plugins),
+ DEF(SET_STR, mail_plugin_dir),
+ DEF(SET_STR_VARS, mail_log_prefix),
+
+ DEF(SET_BOOL, pop3_no_flag_updates),
+ DEF(SET_BOOL, pop3_enable_last),
+ DEF(SET_BOOL, pop3_reuse_xuidl),
+ DEF(SET_BOOL, pop3_lock_session),
+ DEF(SET_STR, pop3_client_workarounds),
+ DEF(SET_STR, pop3_logout_format),
+ DEF(SET_STR, pop3_uidl_format),
+
+ SETTING_DEFINE_LIST_END
+};
+
+static struct pop3_settings pop3_default_settings = {
+ MEMBER(mail_debug) FALSE,
+ MEMBER(shutdown_clients) FALSE,
+ MEMBER(verbose_proctitle) FALSE,
+
+ MEMBER(mail_plugins) "",
+ MEMBER(mail_plugin_dir) MODULEDIR"/pop3",
+ MEMBER(mail_log_prefix) "%Us(%u): ",
+
+ MEMBER(pop3_no_flag_updates) FALSE,
+ MEMBER(pop3_enable_last) FALSE,
+ MEMBER(pop3_reuse_xuidl) FALSE,
+ MEMBER(pop3_lock_session) FALSE,
+ MEMBER(pop3_client_workarounds) NULL,
+ MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
+ MEMBER(pop3_uidl_format) "%08Xu%08Xv"
+};
+
+struct setting_parser_info pop3_setting_parser_info = {
+ MEMBER(defines) pop3_setting_defines,
+ MEMBER(defaults) &pop3_default_settings,
+
+ MEMBER(parent) NULL,
+ MEMBER(dynamic_parsers) NULL,
+
+ MEMBER(parent_offset) (size_t)-1,
+ MEMBER(type_offset) (size_t)-1,
+ MEMBER(struct_size) sizeof(struct pop3_settings)
+};
+
+static pool_t settings_pool = NULL;
+
+void pop3_settings_read(const struct pop3_settings **set_r,
+ const struct mail_user_settings **user_set_r)
+{
+ static const struct setting_parser_info *roots[] = {
+ &pop3_setting_parser_info,
+ &mail_user_setting_parser_info
+ };
+ struct setting_parser_context *parser;
+ void **sets;
+
+ if (settings_pool == NULL)
+ settings_pool = pool_alloconly_create("pop3 settings", 1024);
+ else
+ p_clear(settings_pool);
+
+ mail_storage_namespace_defines_init(settings_pool);
+
+ parser = settings_parser_init_list(settings_pool,
+ roots, N_ELEMENTS(roots),
+ SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS);
+
+ settings_parse_set_expanded(parser, TRUE);
+ if (settings_parse_environ(parser) < 0) {
+ i_fatal("Error reading configuration: %s",
+ settings_parser_get_error(parser));
+ }
+
+ sets = settings_parser_get_list(parser);
+ *set_r = sets[0];
+ *user_set_r = sets[1];
+ settings_parser_deinit(&parser);
+}
--- /dev/null
+#ifndef POP3_SETTINGS_H
+#define POP3_SETTINGS_H
+
+struct mail_user_settings;
+
+struct pop3_settings {
+ bool mail_debug;
+ bool shutdown_clients;
+ bool verbose_proctitle;
+
+ const char *mail_plugins;
+ const char *mail_plugin_dir;
+ const char *mail_log_prefix;
+
+ /* pop3: */
+ bool pop3_no_flag_updates;
+ bool pop3_enable_last;
+ bool pop3_reuse_xuidl;
+ bool pop3_lock_session;
+ const char *pop3_client_workarounds;
+ const char *pop3_logout_format;
+ const char *pop3_uidl_format;
+};
+
+void pop3_settings_read(const struct pop3_settings **set_r,
+ const struct mail_user_settings **user_set_r);
+
+#endif