From: Timo Sirainen Date: Fri, 10 Apr 2009 00:24:51 +0000 (-0400) Subject: Added lib-master and mail-storage-service code that makes it easier to build new... X-Git-Tag: 2.0.alpha1~993 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8d3278a82b964217d95c340ec6f82037cdc59d19;p=thirdparty%2Fdovecot%2Fcore.git Added lib-master and mail-storage-service code that makes it easier to build new Dovecot binaries. Currently only the standalone applications (e.g. deliver) uses this. --HG-- branch : HEAD --- diff --git a/configure.in b/configure.in index 3750e44db5..f37af3b13a 100644 --- a/configure.in +++ b/configure.in @@ -2380,6 +2380,7 @@ src/lib-dict/Makefile src/lib-imap/Makefile src/lib-index/Makefile src/lib-mail/Makefile +src/lib-master/Makefile src/lib-ntlm/Makefile src/lib-otp/Makefile src/lib-dovecot/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index a4e52731af..89915e2749 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,6 +12,7 @@ LIBDOVECOT_SUBDIRS = \ lib-charset \ lib-mail \ lib-imap \ + lib-master \ lib-dict \ lib-settings @@ -24,7 +25,6 @@ SUBDIRS = \ lib-ntlm \ lib-otp \ auth \ - config \ dict \ master \ login-common \ @@ -32,6 +32,7 @@ SUBDIRS = \ imap \ $(POP3D) \ $(DELIVER) \ + config \ tests \ util \ plugins diff --git a/src/deliver/Makefile.am b/src/deliver/Makefile.am index 3a727abbc5..c3d2d0add5 100644 --- a/src/deliver/Makefile.am +++ b/src/deliver/Makefile.am @@ -4,20 +4,15 @@ pkglibexec_PROGRAMS = deliver 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-index \ - -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ -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)"\" + -DPKG_RUNDIR=\""$(rundir)"\" deliver_LDFLAGS = -export-dynamic @@ -30,7 +25,6 @@ deliver_LDADD = $(libs) deliver_DEPENDENCIES = $(libs) deliver_SOURCES = \ - auth-client.c \ deliver.c \ deliver-settings.c \ duplicate.c \ @@ -38,7 +32,6 @@ deliver_SOURCES = \ smtp-client.c headers = \ - auth-client.h \ deliver.h \ deliver-settings.h \ duplicate.h \ diff --git a/src/deliver/deliver-settings.c b/src/deliver/deliver-settings.c index ea74a3e968..858008f87d 100644 --- a/src/deliver/deliver-settings.c +++ b/src/deliver/deliver-settings.c @@ -11,6 +11,8 @@ #include #include +static bool deliver_settings_check(void *_set, pool_t pool, const char **error_r); + #undef DEF #undef DEFLIST #define DEF(type, name) \ @@ -19,27 +21,11 @@ { 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_STR, mail_plugins), - DEF(SET_STR, mail_plugin_dir), - - DEF(SET_STR, mail_uid), - DEF(SET_STR, mail_gid), - DEF(SET_STR, mail_chroot), - DEF(SET_STR, mail_access_groups), - 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), @@ -49,28 +35,12 @@ static struct setting_define deliver_setting_defines[] = { }; 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(mail_plugins) "", - MEMBER(mail_plugin_dir) MODULEDIR, - - MEMBER(mail_uid) "", - MEMBER(mail_gid) "", - MEMBER(mail_chroot) "", - MEMBER(mail_access_groups) "", - 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 }; @@ -84,82 +54,22 @@ struct setting_parser_info deliver_setting_parser_info = { MEMBER(parent_offset) (size_t)-1, MEMBER(type_offset) (size_t)-1, - MEMBER(struct_size) sizeof(struct deliver_settings) + MEMBER(struct_size) sizeof(struct deliver_settings), +#ifdef CONFIG_BINARY + MEMBER(check_func) NULL +#else + MEMBER(check_func) deliver_settings_check +#endif }; -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(struct deliver_settings **set_r, - struct mail_user_settings **user_set_r) +static bool deliver_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_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); + struct deliver_settings *set = _set; - 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_environ(parser) < 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"); + if (*set->postmaster_address == '\0') { + *error_r = "postmaster_address setting not given"; + return FALSE; } - - *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; - + return TRUE; } diff --git a/src/deliver/deliver-settings.h b/src/deliver/deliver-settings.h index 998a859142..92a8d50fa3 100644 --- a/src/deliver/deliver-settings.h +++ b/src/deliver/deliver-settings.h @@ -4,38 +4,17 @@ 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; - - const char *mail_plugins; - const char *mail_plugin_dir; - - const char *mail_uid; - const char *mail_gid; - const char *mail_chroot; - const char *mail_access_groups; - - /* 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(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); +extern struct setting_parser_info deliver_setting_parser_info; #endif diff --git a/src/deliver/deliver.c b/src/deliver/deliver.c index 0a12100250..b58580e975 100644 --- a/src/deliver/deliver.c +++ b/src/deliver/deliver.c @@ -1,49 +1,32 @@ /* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ -/* This is getting pretty horrible. Especially the config file parsing. - Dovecot v2.0 should have a config file handling process which should help - with this.. */ - #include "lib.h" #include "lib-signals.h" -#include "file-lock.h" -#include "array.h" #include "ioloop.h" -#include "hostpid.h" -#include "home-expand.h" #include "env-util.h" #include "fd-set-nonblock.h" #include "istream.h" #include "istream-seekable.h" -#include "module-dir.h" #include "str.h" #include "str-sanitize.h" #include "strescape.h" #include "var-expand.h" #include "rfc822-parser.h" #include "message-address.h" +#include "imap-utf7.h" +#include "master-service.h" +#include "mail-storage-service.h" #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" #include "duplicate.h" #include "mbox-from.h" -#include "../master/syslog-util.h" -#include "../master/syslog-util.c" /* ugly, ugly.. */ #include "deliver.h" #include #include -#include -#include #include -#include -#define DEFAULT_CONFIG_FILE SYSCONFDIR"/dovecot.conf" -#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail" #define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON" /* After buffer grows larger than this, create a temporary file to /tmp @@ -55,7 +38,7 @@ static const char *wanted_headers[] = { NULL }; -struct deliver_settings *deliver_set; +const struct deliver_settings *deliver_set; deliver_mail_func_t *deliver_mail = NULL; bool mailbox_autosubscribe; bool mailbox_autocreate; @@ -66,21 +49,7 @@ static const char *default_mailbox_name = NULL; static bool saved_mail = FALSE; static char *explicit_envelope_sender = NULL; -static struct module *modules; -static struct ioloop *ioloop; - -static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED) -{ - /* warn about being killed because of some signal, except SIGINT (^C) - which is too common at least while testing :) */ - if (si->si_signo != SIGINT) { - i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)", - si->si_signo, dec2str(si->si_pid), - dec2str(si->si_uid), - lib_signal_code_to_str(si->si_signo, si->si_code)); - } - io_loop_stop(current_ioloop); -} +static struct master_service *service; static const char *deliver_get_address(struct mail *mail, const char *header) { @@ -402,32 +371,6 @@ static void failure_exit_callback(int *status) *status = EX_TEMPFAIL; } -static void open_logfile(const char *username) -{ - const char *prefix, *log_path; - - prefix = t_strdup_printf("deliver(%s): ", username); - log_path = home_expand(deliver_set->log_path); - if (*log_path == '\0') { - int 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); - } else { - /* log to file or stderr */ - i_set_failure_file(log_path, prefix); - } - - log_path = home_expand(deliver_set->info_log_path); - if (*log_path != '\0') - i_set_info_file(log_path); - - i_set_failure_timestamp_format(deliver_set->log_timestamp); -} - static void print_help(void) { printf( @@ -435,51 +378,11 @@ static void print_help(void) " [-f ] [-m ] [-n] [-s] [-e] [-k]\n"); } -void deliver_env_clean(bool preserve_home) -{ - const char *tz, *home; - - tz = getenv("TZ"); - if (tz != NULL) - tz = t_strconcat("TZ=", tz, NULL); - home = preserve_home ? getenv("HOME") : NULL; - if (home != NULL) - home = t_strconcat("HOME=", home, NULL); - - /* Note that if the original environment was set with env_put(), the - environment strings will be invalid after env_clean(). That's why - we t_strconcat() them above. */ - env_clean(); - - if (tz != NULL) env_put(tz); - if (home != NULL) env_put(home); -} - -static void plugin_get_home(void) -{ - const char *const *envs; - unsigned int i, count; - - /* 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; - } - } - } -} - int main(int argc, char *argv[]) { - const char *config_path = DEFAULT_CONFIG_FILE; + enum mail_storage_service_flags service_flags = 0; const char *mailbox = "INBOX"; - const char *home, *destaddr, *user, *errstr, *path, *orig_user; - ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT; - struct setting_parser_context *parser; + const char *destaddr, *user, *errstr, *path, *getopt_str; struct mail_user *mail_user, *raw_mail_user; struct mail_namespace *raw_ns; struct mail_namespace_settings raw_ns_set; @@ -489,18 +392,12 @@ int main(int argc, char *argv[]) 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; char cwd[PATH_MAX]; uid_t process_euid; bool stderr_rejection = FALSE; - bool keep_environment = FALSE; - bool user_auth = FALSE; - bool doveconf_env; time_t mtime; - int i, ret; - pool_t userdb_pool = NULL; + int ret, c; string_t *str; enum mail_error error; @@ -524,123 +421,87 @@ int main(int argc, char *argv[]) i_set_failure_exit_callback(failure_exit_callback); - lib_init(); - ioloop = io_loop_create(); - - lib_signals_init(); - lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL); - lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL); - lib_signals_ignore(SIGPIPE, TRUE); - lib_signals_ignore(SIGALRM, FALSE); + service = master_service_init("lda", MASTER_SERVICE_FLAG_STANDALONE, + argc, argv); #ifdef SIGXFSZ lib_signals_ignore(SIGXFSZ, TRUE); #endif - deliver_set = i_new(struct deliver_settings, 1); mailbox_autocreate = TRUE; - - destaddr = user = path = NULL; - for (i = 1; i < argc; i++) { - if (strcmp(argv[i], "-a") == 0) { + destaddr = path = NULL; + + user = getenv("USER"); + getopt_str = t_strconcat("a:d:p:ekm:nsf:", + master_service_getopt_string(), NULL); + while ((c = getopt(argc, argv, getopt_str)) > 0) { + switch (c) { + case 'a': /* destination address */ - i++; - if (i == argc) - i_fatal_status(EX_USAGE, "Missing -a argument"); - destaddr = argv[i]; - } else if (strcmp(argv[i], "-d") == 0) { + destaddr = optarg; + break; + case 'd': /* destination user */ - i++; - if (i == argc) - i_fatal_status(EX_USAGE, "Missing -d argument"); - user = argv[i]; - user_auth = TRUE; - } else if (strcmp(argv[i], "-p") == 0) { + user = optarg; + service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; + break; + case 'p': /* input path */ - i++; - if (i == argc) - i_fatal_status(EX_USAGE, "Missing -p argument"); - path = argv[i]; + path = optarg; if (*path != '/') { /* expand relative paths before we chdir */ if (getcwd(cwd, sizeof(cwd)) == NULL) i_fatal("getcwd() failed: %m"); path = t_strconcat(cwd, "/", path, NULL); } - } else if (strcmp(argv[i], "-e") == 0) { + break; + case 'e': stderr_rejection = TRUE; - } else if (strcmp(argv[i], "-c") == 0) { - /* config file path */ - i++; - if (i == argc) { - i_fatal_status(EX_USAGE, - "Missing config file path argument"); - } - config_path = argv[i]; - } else if (strcmp(argv[i], "-k") == 0) { - keep_environment = TRUE; - } else if (strcmp(argv[i], "-m") == 0) { - /* destination mailbox */ - i++; - if (i == argc) - i_fatal_status(EX_USAGE, "Missing -m argument"); - /* Ignore -m "". This allows doing -m ${extension} + break; + case 'm': + /* destination mailbox. + Ignore -m "". This allows doing -m ${extension} in Postfix to handle user+mailbox */ - if (*argv[i] != '\0') { + if (*optarg != '\0') { str = t_str_new(256); - if (imap_utf8_to_utf7(argv[i], str) < 0) { + if (imap_utf8_to_utf7(optarg, str) < 0) { i_fatal("Mailbox name not UTF-8: %s", mailbox); } mailbox = str_c(str); } - } else if (strcmp(argv[i], "-n") == 0) { + break; + case 'n': mailbox_autocreate = FALSE; - } else if (strcmp(argv[i], "-s") == 0) { + break; + case 's': mailbox_autosubscribe = TRUE; - } else if (strcmp(argv[i], "-f") == 0) { + break; + case 'f': /* envelope sender address */ - i++; - if (i == argc) - i_fatal_status(EX_USAGE, "Missing -f argument"); explicit_envelope_sender = - i_strdup(address_sanitize(argv[i])); - } else if (argv[i][0] != '\0') { - print_help(); - i_fatal_status(EX_USAGE, - "Unknown argument: %s", argv[i]); + i_strdup(address_sanitize(optarg)); + break; + default: + if (!master_service_parse_option(service, c, optarg)) { + print_help(); + i_fatal_status(EX_USAGE, + "Unknown argument: %c", c); + } + break; } } - - doveconf_env = getenv("DOVECONF_ENV") != NULL; - if (user == NULL) - user = getenv("USER"); - if (!keep_environment && !doveconf_env) { - deliver_env_clean(!user_auth); - env_put(t_strconcat("USER=", user, NULL)); - } - if (!doveconf_env) { - /* currently we need to be executed via doveconf. */ -#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf" - const char **conf_argv; - - conf_argv = i_new(const char *, 6 + (argc + 1) + 1); - conf_argv[0] = DOVECOT_CONFIG_BIN_PATH; - conf_argv[1] = "-s"; - conf_argv[2] = "lda"; - conf_argv[3] = "-c"; - conf_argv[4] = config_path; - conf_argv[5] = "--exec"; - memcpy(conf_argv+6, argv, (argc+1) * sizeof(argv[0])); - execv(conf_argv[0], (char **)conf_argv); - i_fatal_status(EX_CONFIG, "execv(%s) failed: %m", conf_argv[0]); + if (optind != argc) { + print_help(); + i_fatal_status(EX_USAGE, "Unknown argument: %s", argv[optind]); } process_euid = geteuid(); - if (user_auth) + if ((service_flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) ; else if (process_euid != 0) { /* we're non-root. get our username and possibly our home. */ struct passwd *pw; + const char *home; home = getenv("HOME"); if (user != NULL && home != NULL) { @@ -659,96 +520,18 @@ int main(int argc, char *argv[]) "destination user parameter (-d user) not given"); } - mail_storage_init(); - mail_storage_register_all(); - mailbox_list_register_all(); - - parser = deliver_settings_read(&deliver_set, &user_set); - open_logfile(user); - - mail_set = mail_user_set_get_driver_settings(user_set, "MAIL"); - if (deliver_set->mail_plugins == '\0') - modules = NULL; - else { - const char *version; - - 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) { - userdb_pool = pool_alloconly_create("userdb lookup replys", 512); - orig_user = user; - ret = auth_client_lookup_and_restrict(deliver_set->auth_socket_path, - mail_set->mail_debug, - &user, process_euid, - userdb_pool, - &extra_fields); - if (ret != 0) - return ret; - - if (strcmp(user, orig_user) != 0) { - /* auth lookup changed the user. */ - if (mail_set->mail_debug) - i_info("userdb changed username to %s", user); - i_set_failure_prefix(t_strdup_printf("deliver(%s): ", - user)); - } - /* if user was changed, it was allocated from userdb_pool - which we'll free soon. */ - user = t_strdup(user); - } - - if (userdb_pool != NULL) { - settings_parse_set_expanded(parser, TRUE); - deliver_settings_add(parser, &extra_fields); - pool_unref(&userdb_pool); - } - - 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. */ - if (home != NULL) { - if (chdir(home) < 0) { - if (errno != ENOENT) - i_error("chdir(%s) failed: %m", home); - else if (mail_set->mail_debug) - i_info("Home dir not found: %s", home); - } - } - - env_put(t_strconcat("USER=", user, NULL)); - (void)umask(0077); - - dict_drivers_register_builtin(); - duplicate_init(mail_set); - mail_users_init(deliver_set->auth_socket_path, mail_set->mail_debug); - - module_dir_init(modules); - - mail_user = mail_user_alloc(user, user_set); - mail_user_set_home(mail_user, home); - mail_user_set_vars(mail_user, geteuid(), "deliver", NULL, NULL); - if (mail_user_init(mail_user, &errstr) < 0) - i_fatal("Mail user initialization failed: %s", errstr); - if (mail_namespaces_init(mail_user, &errstr) < 0) - i_fatal("Namespace initialization failed: %s", errstr); + service_flags |= MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT; + mail_user = mail_storage_service_init_user(service, user, + &deliver_setting_parser_info, service_flags); + deliver_set = mail_storage_service_get_settings(service); + duplicate_init(mail_user_set_get_storage_set(mail_user->set)); /* create a separate mail user for the internal namespace */ - raw_mail_user = mail_user_alloc(user, user_set); + raw_mail_user = mail_user_alloc(user, mail_user->unexpanded_set); mail_user_set_home(raw_mail_user, "/"); if (mail_user_init(raw_mail_user, &errstr) < 0) i_fatal("Raw user initialization failed: %s", errstr); - settings_parser_deinit(&parser); - memset(&raw_ns_set, 0, sizeof(raw_ns_set)); raw_ns_set.location = "/tmp"; @@ -866,17 +649,9 @@ int main(int argc, char *argv[]) mail_user_unref(&mail_user); mail_user_unref(&raw_mail_user); - - module_dir_unload(&modules); - mail_storage_deinit(); - mail_users_deinit(); - duplicate_deinit(); - dict_drivers_unregister_builtin(); - lib_signals_deinit(); - - io_loop_destroy(&ioloop); - lib_deinit(); + mail_storage_service_deinit_user(); + master_service_deinit(&service); return EX_OK; } diff --git a/src/deliver/deliver.h b/src/deliver/deliver.h index 398326c3eb..5c4bafd48f 100644 --- a/src/deliver/deliver.h +++ b/src/deliver/deliver.h @@ -11,7 +11,7 @@ #include "mail-storage.h" #include "deliver-settings.h" -extern struct deliver_settings *deliver_set; +extern const struct deliver_settings *deliver_set; extern bool mailbox_autosubscribe; extern bool mailbox_autocreate; extern bool tried_default_save; @@ -23,8 +23,6 @@ typedef int deliver_mail_func_t(struct mail_namespace *namespaces, extern deliver_mail_func_t *deliver_mail; -void deliver_env_clean(bool preserve_home); - /* Save a mail into given mailbox with given flags and keywords. */ int deliver_save(struct mail_namespace *namespaces, struct mail_storage **storage_r, const char *mailbox, diff --git a/src/deliver/smtp-client.c b/src/deliver/smtp-client.c index 4cb89f6fe8..fb3ad80ba9 100644 --- a/src/deliver/smtp-client.c +++ b/src/deliver/smtp-client.c @@ -2,6 +2,7 @@ #include "lib.h" #include "deliver.h" +#include "master-service.h" #include "smtp-client.h" #include @@ -46,7 +47,7 @@ smtp_client_run_sendmail(const char *destination, if (dup2(fd, STDIN_FILENO) < 0) i_fatal("dup2() failed: %m"); - deliver_env_clean(TRUE); + master_service_env_clean(TRUE); (void)execv(sendmail_path, (void *)argv); i_fatal("execv(%s) failed: %m", sendmail_path); diff --git a/src/dict/main.c b/src/dict/main.c index 7273af9d90..816d6bc489 100644 --- a/src/dict/main.c +++ b/src/dict/main.c @@ -58,6 +58,7 @@ static void drop_privileges(void) sql_drivers_register_all(); restrict_access_by_env(NULL, FALSE); + restrict_access_allow_coredumps(TRUE); } static void main_init(void) diff --git a/src/imap/Makefile.am b/src/imap/Makefile.am index 9ca4086e8b..dbc6c17497 100644 --- a/src/imap/Makefile.am +++ b/src/imap/Makefile.am @@ -9,9 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ - -I$(top_srcdir)/src/lib-storage \ - -DPKG_RUNDIR=\""$(rundir)"\" \ - -DMODULEDIR=\""$(moduledir)"\" + -I$(top_srcdir)/src/lib-storage imap_LDFLAGS = -export-dynamic diff --git a/src/imap/imap-settings.c b/src/imap/imap-settings.c index cb8582f9ca..f90d1ae5ff 100644 --- a/src/imap/imap-settings.c +++ b/src/imap/imap-settings.c @@ -9,8 +9,6 @@ #include #include -static bool imap_settings_check(void *_set, pool_t pool, const char **error_r); - #undef DEF #undef DEFLIST #define DEF(type, name) \ @@ -19,16 +17,10 @@ static bool imap_settings_check(void *_set, pool_t pool, const char **error_r); { SET_DEFLIST, name, offsetof(struct imap_settings, field), defines } static struct setting_define imap_setting_defines[] = { - DEF(SET_STR, base_dir), - DEF(SET_STR, auth_socket_path), - 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_UINT, imap_max_line_length), DEF(SET_STR, imap_capability), DEF(SET_STR, imap_client_workarounds), @@ -40,16 +32,10 @@ static struct setting_define imap_setting_defines[] = { }; static struct imap_settings imap_default_settings = { - MEMBER(base_dir) PKG_RUNDIR, - MEMBER(auth_socket_path) "auth-master", - MEMBER(mail_debug) FALSE, MEMBER(shutdown_clients) FALSE, MEMBER(verbose_proctitle) FALSE, - MEMBER(mail_plugins) "", - MEMBER(mail_plugin_dir) MODULEDIR, - /* 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. */ @@ -71,40 +57,11 @@ struct setting_parser_info imap_setting_parser_info = { MEMBER(parent_offset) (size_t)-1, MEMBER(type_offset) (size_t)-1, MEMBER(struct_size) sizeof(struct imap_settings), - MEMBER(check_func) imap_settings_check + MEMBER(check_func) NULL }; static pool_t settings_pool = NULL; -static void fix_base_path(struct imap_settings *set, const char **str) -{ - if (*str != NULL && **str != '\0' && **str != '/') { - *str = p_strconcat(settings_pool, - set->base_dir, "/", *str, NULL); - } -} - -/* */ -static bool imap_settings_check(void *_set, pool_t pool ATTR_UNUSED, - const char **error_r) -{ - struct imap_settings *set = _set; - -#ifndef CONFIG_BINARY - fix_base_path(set, &set->auth_socket_path); -#endif - - if (*set->mail_plugins != '\0' && - access(set->mail_plugin_dir, R_OK | X_OK) < 0) { - *error_r = t_strdup_printf( - "mail_plugin_dir: access(%s) failed: %m", - set->mail_plugin_dir); - return FALSE; - } - return TRUE; -} -/* */ - static void parse_expand_vars(struct setting_parser_context *parser, const char *value) { @@ -143,7 +100,8 @@ void imap_settings_read(const struct imap_settings **set_r, else p_clear(settings_pool); - mail_storage_namespace_defines_init(settings_pool); + settings_parser_info_update(settings_pool, + mail_storage_get_dynamic_parsers()); parser = settings_parser_init_list(settings_pool, roots, N_ELEMENTS(roots), diff --git a/src/imap/imap-settings.h b/src/imap/imap-settings.h index 5226d13844..3d7fd2170c 100644 --- a/src/imap/imap-settings.h +++ b/src/imap/imap-settings.h @@ -4,16 +4,10 @@ struct mail_user_settings; struct imap_settings { - const char *base_dir; - const char *auth_socket_path; - bool mail_debug; bool shutdown_clients; bool verbose_proctitle; - const char *mail_plugins; - const char *mail_plugin_dir; - /* imap: */ unsigned int imap_max_line_length; const char *imap_capability; diff --git a/src/imap/main.c b/src/imap/main.c index 212afc0e2d..7225b0bbc8 100644 --- a/src/imap/main.c +++ b/src/imap/main.c @@ -155,9 +155,9 @@ static void main_preinit(const struct imap_settings **set_r, 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); + modules = *(*user_set_r)->mail_plugins == '\0' ? NULL : + module_dir_load((*user_set_r)->mail_plugin_dir, + (*user_set_r)->mail_plugins, TRUE, version); restrict_access_by_env(getenv("HOME"), !IS_STANDALONE()); restrict_access_allow_coredumps(TRUE); @@ -202,13 +202,12 @@ static void main_init(const struct imap_settings *set, log_error_callback, NULL); } + module_dir_init(modules); dict_drivers_register_builtin(); - mail_users_init(set->auth_socket_path, set->mail_debug); + mail_users_init(user_set->auth_socket_path, set->mail_debug); clients_init(); commands_init(); - module_dir_init(modules); - user = mail_user_alloc(username, user_set); mail_user_set_home(user, home); if (mail_user_init(user, &error) < 0) diff --git a/src/lib-auth/auth-master.h b/src/lib-auth/auth-master.h index 4198fa27fd..27219dbdc4 100644 --- a/src/lib-auth/auth-master.h +++ b/src/lib-auth/auth-master.h @@ -1,8 +1,6 @@ #ifndef AUTH_MASTER_H #define AUTH_MASTER_H -#define AUTH_SERVICE_INTERNAL "internal" - struct auth_user_reply { uid_t uid; gid_t gid; diff --git a/src/lib-dovecot/Makefile.am b/src/lib-dovecot/Makefile.am index df6f56ebb0..83894b1c6f 100644 --- a/src/lib-dovecot/Makefile.am +++ b/src/lib-dovecot/Makefile.am @@ -9,6 +9,7 @@ libs = \ ../lib-mail/libmail.la \ ../lib-auth/libauth.la \ ../lib-charset/libcharset.la \ + ../lib-master/libmaster.la \ ../lib/liblib.la libdovecot_la_LIBADD = \ diff --git a/src/lib-master/Makefile.am b/src/lib-master/Makefile.am new file mode 100644 index 0000000000..a0afbe0b8d --- /dev/null +++ b/src/lib-master/Makefile.am @@ -0,0 +1,19 @@ +noinst_LTLIBRARIES = libmaster.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-settings \ + -DSYSCONFDIR=\""$(sysconfdir)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DPKG_RUNDIR=\""$(rundir)"\" + +libmaster_la_SOURCES = \ + master-service.c \ + master-service-settings.c \ + syslog-util.c + +noinst_HEADERS = \ + master-service.h \ + master-service-private.h \ + master-service-settings.h \ + syslog-util.h diff --git a/src/lib-master/master-service-private.h b/src/lib-master/master-service-private.h new file mode 100644 index 0000000000..ac500e6194 --- /dev/null +++ b/src/lib-master/master-service-private.h @@ -0,0 +1,27 @@ +#ifndef MASTER_SERVICE_PRIVATE_H +#define MASTER_SERVICE_PRIVATE_H + +#include "master-service.h" + +struct master_service { + struct ioloop *ioloop; + + char *name; + enum master_service_flags flags; + + int argc; + char **argv; + + const char *version_string; + const char *config_path; + int syslog_facility; + + pool_t set_pool; + const struct master_service_settings *set; + struct setting_parser_context *set_parser; + + unsigned int keep_environment:1; + unsigned int log_directly:1; +}; + +#endif diff --git a/src/lib-master/master-service-settings.c b/src/lib-master/master-service-settings.c new file mode 100644 index 0000000000..58332eb06f --- /dev/null +++ b/src/lib-master/master-service-settings.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "settings-parser.h" +#include "master-service-private.h" +#include "master-service-settings.h" + +#include +#include +#include + +#define DOVECOT_CONFIG_BIN_PATH BINDIR"/doveconf" + +#undef DEF +#define DEF(type, name) \ + { type, #name, offsetof(struct master_service_settings, name), NULL } + +static struct setting_define master_service_setting_defines[] = { + 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), + + SETTING_DEFINE_LIST_END +}; + +static struct master_service_settings master_service_default_settings = { + MEMBER(log_path) "", + MEMBER(info_log_path) "", + MEMBER(log_timestamp) DEFAULT_FAILURE_STAMP_FORMAT, + MEMBER(syslog_facility) "mail", + MEMBER(version_ignore) FALSE +}; + +struct setting_parser_info master_service_setting_parser_info = { + MEMBER(defines) master_service_setting_defines, + MEMBER(defaults) &master_service_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 master_service_settings) +}; + +static void ATTR_NORETURN +master_service_exec_config(struct master_service *service, bool preserve_home) +{ + const char **conf_argv; + + if (!service->keep_environment) + master_service_env_clean(preserve_home); + + /* @UNSAFE */ + conf_argv = t_new(const char *, 6 + (service->argc + 1) + 1); + conf_argv[0] = DOVECOT_CONFIG_BIN_PATH; + conf_argv[1] = "-s"; + conf_argv[2] = service->name; + conf_argv[3] = "-c"; + conf_argv[4] = service->config_path; + conf_argv[5] = "--exec"; + memcpy(conf_argv+6, service->argv, + (service->argc+1) * sizeof(conf_argv[0])); + execv(conf_argv[0], (char **)conf_argv); + i_fatal("execv(%s) failed: %m", conf_argv[0]); +} + +int master_service_settings_read(struct master_service *service, + const struct setting_parser_info *roots[], + const struct dynamic_settings_parser *dyn_parsers, + bool preserve_home, const char **error_r) +{ + ARRAY_DEFINE(all_roots, const struct setting_parser_info *); + const struct setting_parser_info *tmp_root; + struct setting_parser_context *parser; + const char *error; + void **sets; + unsigned int i; + + if (getenv("DOVECONF_ENV") == NULL) + master_service_exec_config(service, preserve_home); + + if (service->set_pool != NULL) + p_clear(service->set_pool); + else { + service->set_pool = + pool_alloconly_create("master service settings", 4096); + } + + if (dyn_parsers != NULL) + settings_parser_info_update(service->set_pool, dyn_parsers); + + p_array_init(&all_roots, service->set_pool, 8); + tmp_root = &master_service_setting_parser_info; + array_append(&all_roots, &tmp_root, 1); + for (i = 0; roots[i] != NULL; i++) + array_append(&all_roots, &roots[i], 1); + + parser = settings_parser_init_list(service->set_pool, + array_idx(&all_roots, 0), array_count(&all_roots), + SETTINGS_PARSER_FLAG_IGNORE_UNKNOWN_KEYS); + + if (settings_parse_environ(parser) < 0) { + *error_r = settings_parser_get_error(parser); + return -1; + } + + if (settings_parser_check(parser, service->set_pool, &error) < 0) { + *error_r = t_strdup_printf("Invalid settings: %s", error); + return -1; + } + + sets = settings_parser_get_list(parser); + service->set = sets[0]; + service->set_parser = parser; + + if (service->set->version_ignore && + (service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0) { + /* running standalone. we want to ignore plugin versions. */ + service->version_string = NULL; + } + + /* if we change any settings afterwards, they're in expanded form. + especially all settings from userdb are already expanded. */ + settings_parse_set_expanded(service->set_parser, TRUE); + return 0; +} + +const struct master_service_settings * +master_service_settings_get(struct master_service *service) +{ + void **sets; + + sets = settings_parser_get_list(service->set_parser); + return sets[0]; +} + +void **master_service_settings_get_others(struct master_service *service) +{ + return settings_parser_get_list(service->set_parser) + 1; +} diff --git a/src/lib-master/master-service-settings.h b/src/lib-master/master-service-settings.h new file mode 100644 index 0000000000..439a6b82bc --- /dev/null +++ b/src/lib-master/master-service-settings.h @@ -0,0 +1,23 @@ +#ifndef MASTER_SERVICE_SETTINGS_H +#define MASTER_SERVICE_SETTINGS_H + +struct setting_parser_info; +struct dynamic_settings_parser; + +struct master_service_settings { + const char *log_path; + const char *info_log_path; + const char *log_timestamp; + const char *syslog_facility; + bool version_ignore; +}; + +int master_service_settings_read(struct master_service *service, + const struct setting_parser_info *roots[], + const struct dynamic_settings_parser *dyn_parsers, + bool preserve_home, const char **error_r); +const struct master_service_settings * +master_service_settings_get(struct master_service *service); +void **master_service_settings_get_others(struct master_service *service); + +#endif diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c new file mode 100644 index 0000000000..eaedf3745d --- /dev/null +++ b/src/lib-master/master-service.c @@ -0,0 +1,219 @@ +/* Copyright (C) 2005-2009 Timo Sirainen */ + +#include "lib.h" +#include "lib-signals.h" +#include "ioloop.h" +#include "env-util.h" +#include "home-expand.h" +#include "restrict-access.h" +#include "fd-close-on-exec.h" +#include "syslog-util.h" +#include "master-service-private.h" +#include "master-service-settings.h" + +#include +#include +#include + +#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf" + +/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */ +#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE" + +/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */ +#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION" + +const char *master_service_getopt_string(void) +{ + return "c:Lk"; +} + +static void sig_die(const siginfo_t *si, void *context) +{ + struct master_service *service = context; + + /* warn about being killed because of some signal, except SIGINT (^C) + which is too common at least while testing :) */ + if (si->si_signo != SIGINT) { + i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)", + si->si_signo, dec2str(si->si_pid), + dec2str(si->si_uid), + lib_signal_code_to_str(si->si_signo, si->si_code)); + } + io_loop_stop(service->ioloop); +} + +static void master_service_verify_version(struct master_service *service) +{ + if (service->version_string != NULL && + strcmp(service->version_string, PACKAGE_VERSION) != 0) { + i_fatal("Dovecot version mismatch: " + "Master is v%s, %s is v"PACKAGE_VERSION" " + "(if you don't care, set version_ignore=yes)", + service->name, service->version_string); + } +} + +struct master_service * +master_service_init(const char *name, enum master_service_flags flags, + int argc, char *argv[]) +{ + struct master_service *service; + + i_assert(name != NULL); + + /* NOTE: we start rooted, so keep the code minimal until + restrict_access_by_env() is called */ + lib_init(); + /* Set a logging prefix temporarily. This will be ignored once the log + is properly initialized */ + i_set_failure_prefix(t_strdup_printf("%s(init): ", name)); + + if (getenv("LOG_TO_MASTER") == NULL) + flags |= MASTER_SERVICE_FLAG_STANDALONE; + + service = i_new(struct master_service, 1); + service->argc = argc; + service->argv = argv; + service->name = i_strdup(name); + service->flags = flags; + service->ioloop = io_loop_create(); + service->config_path = getenv(MASTER_CONFIG_FILE_ENV); + if (service->config_path == NULL) + service->config_path = DEFAULT_CONFIG_FILE_PATH; + + if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) + service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV); + else + service->version_string = PACKAGE_VERSION; + + /* set up some kind of logging until we know exactly how and where + we want to log */ + if (getenv("LOG_TO_MASTER") != NULL) + i_set_failure_internal(); + if (getenv("USER") != NULL) { + i_set_failure_prefix(t_strdup_printf("%s(%s): ", + name, getenv("USER"))); + } else { + i_set_failure_prefix(t_strdup_printf("%s: ", name)); + } + + /* set default signal handlers */ + lib_signals_init(); + lib_signals_ignore(SIGPIPE, TRUE); + lib_signals_ignore(SIGALRM, FALSE); + lib_signals_set_handler(SIGINT, TRUE, sig_die, service); + lib_signals_set_handler(SIGTERM, TRUE, sig_die, service); + + master_service_verify_version(service); + return service; +} + +void master_service_init_log(struct master_service *service, const char *prefix) +{ + const char *path; + + if (getenv("LOG_TO_MASTER") != NULL && !service->log_directly) { + /* logging via master process */ + i_set_failure_internal(); + i_set_failure_prefix(prefix); + return; + } + + if (*service->set->log_path == '\0') { + /* log to syslog */ + int facility; + + if (!syslog_facility_find(service->set->syslog_facility, + &facility)) + facility = LOG_MAIL; + i_set_failure_syslog("dovecot", LOG_NDELAY, facility); + i_set_failure_prefix(prefix); + } else { + /* log to file or stderr */ + path = home_expand(service->set->log_path); + i_set_failure_file(path, prefix); + } + + path = home_expand(service->set->info_log_path); + if (*path != '\0') + i_set_info_file(path); + i_set_failure_timestamp_format(service->set->log_timestamp); +} + +bool master_service_parse_option(struct master_service *service, + int opt, const char *arg) +{ + switch (opt) { + case 'c': + service->config_path = arg; + break; + case 'k': + service->keep_environment = TRUE; + break; + case 'L': + service->log_directly = TRUE; + break; + default: + return FALSE; + } + return TRUE; +} + +void master_service_env_clean(bool preserve_home) +{ + const char *user, *tz, *home; + + user = getenv("USER"); + if (user != NULL) + user = t_strconcat("USER=", user, NULL); + tz = getenv("TZ"); + if (tz != NULL) + tz = t_strconcat("TZ=", tz, NULL); + home = preserve_home ? getenv("HOME") : NULL; + if (home != NULL) + home = t_strconcat("HOME=", home, NULL); + + /* Note that if the original environment was set with env_put(), the + environment strings will be invalid after env_clean(). That's why + we t_strconcat() them above. */ + env_clean(); + + if (user != NULL) env_put(user); + if (tz != NULL) env_put(tz); + if (home != NULL) env_put(home); +} + +const char *master_service_get_config_path(struct master_service *service) +{ + return service->config_path; +} + +const char *master_service_get_version_string(struct master_service *service) +{ + return service->version_string; +} + +void master_service_run(struct master_service *service) +{ + io_loop_run(service->ioloop); +} + +void master_service_stop(struct master_service *service) +{ + io_loop_stop(service->ioloop); +} + +void master_service_deinit(struct master_service **_service) +{ + struct master_service *service = *_service; + + *_service = NULL; + lib_signals_deinit(); + io_loop_destroy(&service->ioloop); + + i_free(service->name); + i_free(service); + + lib_deinit(); +} diff --git a/src/lib-master/master-service.h b/src/lib-master/master-service.h new file mode 100644 index 0000000000..c7839d11b1 --- /dev/null +++ b/src/lib-master/master-service.h @@ -0,0 +1,46 @@ +#ifndef MASTER_SERVICE_H +#define MASTER_SERVICE_H + +#include "network.h" + +enum master_service_flags { + /* stdin/stdout already contains a client which we want to serve */ + MASTER_SERVICE_FLAG_STD_CLIENT = 0x01, + /* this process is currently running standalone without a master */ + MASTER_SERVICE_FLAG_STANDALONE = 0x02 +}; + +struct master_service; + +const char *master_service_getopt_string(void); + +/* Start service initialization. */ +struct master_service * +master_service_init(const char *name, enum master_service_flags flags, + int argc, char *argv[]); +/* Parser command line option. Returns TRUE if processed. */ +bool master_service_parse_option(struct master_service *service, + int opt, const char *arg); + +/* Clean environment from everything except TZ, USER and optionally HOME. */ +void master_service_env_clean(bool preserve_home); + +/* Initialize logging. */ +void master_service_init_log(struct master_service *service, + const char *prefix); + +/* Returns configuration file path. */ +const char *master_service_get_config_path(struct master_service *service); +/* Returns PACKAGE_VERSION or NULL if version_ignore=yes. This function is + useful mostly as parameter to module_dir_load(). */ +const char *master_service_get_version_string(struct master_service *service); + +/* Start the service. Blocks until finished */ +void master_service_run(struct master_service *service); +/* Stop a running service. */ +void master_service_stop(struct master_service *service); + +/* Deinitialize the service. */ +void master_service_deinit(struct master_service **service); + +#endif diff --git a/src/lib-master/syslog-util.c b/src/lib-master/syslog-util.c new file mode 100644 index 0000000000..3d9a075e04 --- /dev/null +++ b/src/lib-master/syslog-util.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "syslog-util.h" +#include + +struct syslog_facility_list syslog_facilities[] = { +#ifdef LOG_AUTH + { "auth", LOG_AUTH }, +#endif +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif +#ifdef LOG_CRON + { "cron", LOG_CRON }, +#endif +#ifdef LOG_DAEMON + { "daemon", LOG_DAEMON }, +#endif +#ifdef LOG_FTP + { "ftp", LOG_FTP }, +#endif +#ifdef LOG_KERN + { "kern", LOG_KERN }, +#endif +#ifdef LOG_LPR + { "lpr", LOG_LPR }, +#endif +#ifdef LOG_MAIL + { "mail", LOG_MAIL }, +#endif +#ifdef LOG_NEWS + { "news", LOG_NEWS }, +#endif +#ifdef LOG_SYSLOG + { "syslog", LOG_SYSLOG }, +#endif +#ifdef LOG_UUCP + { "uucp", LOG_UUCP }, +#endif + { "user", LOG_USER }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + + { NULL, 0 } +}; + +bool syslog_facility_find(const char *name, int *facility_r) +{ + int i; + + for (i = 0; syslog_facilities[i].name != NULL; i++) { + if (strcmp(syslog_facilities[i].name, name) == 0) { + *facility_r = syslog_facilities[i].facility; + return TRUE; + } + } + return FALSE; +} diff --git a/src/lib-master/syslog-util.h b/src/lib-master/syslog-util.h new file mode 100644 index 0000000000..68e1250b20 --- /dev/null +++ b/src/lib-master/syslog-util.h @@ -0,0 +1,14 @@ +#ifndef SYSLOG_UTIL_H +#define SYSLOG_UTIL_H + +struct syslog_facility_list { + const char *name; + int facility; +}; + +extern struct syslog_facility_list syslog_facilities[]; + +/* Returns TRUE if found. */ +bool syslog_facility_find(const char *name, int *facility_r); + +#endif diff --git a/src/lib-settings/settings-parser.c b/src/lib-settings/settings-parser.c index 2f012aec94..af93f8ba41 100644 --- a/src/lib-settings/settings-parser.c +++ b/src/lib-settings/settings-parser.c @@ -899,10 +899,10 @@ void settings_parse_save_input(struct setting_parser_context *ctx, } static void -info_update_real(pool_t pool, struct setting_parser_info *parent, - const struct dynamic_settings_parser *parsers) +info_update_real(pool_t pool, const struct dynamic_settings_parser *parsers) { /* @UNSAFE */ + struct setting_parser_info *parent; ARRAY_DEFINE(defines, struct setting_define); ARRAY_TYPE(dynamic_settings_parser) dynamic_parsers; struct dynamic_settings_parser new_parser; @@ -912,6 +912,8 @@ info_update_real(pool_t pool, struct setting_parser_info *parent, unsigned int i, j; size_t offset, new_struct_size; + parent = parsers[0].info->parent; + t_array_init(&defines, 128); /* add existing defines */ for (j = 0; parent->defines[j].key != NULL; j++) @@ -971,12 +973,11 @@ info_update_real(pool_t pool, struct setting_parser_info *parent, 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) +void settings_parser_info_update(pool_t pool, + const struct dynamic_settings_parser *parsers) { - T_BEGIN { - info_update_real(pool, parent, parsers); + if (parsers[0].name != NULL) T_BEGIN { + info_update_real(pool, parsers); } T_END; } diff --git a/src/lib-settings/settings-parser.h b/src/lib-settings/settings-parser.h index 0efe10add3..f3447529ea 100644 --- a/src/lib-settings/settings-parser.h +++ b/src/lib-settings/settings-parser.h @@ -143,11 +143,10 @@ bool settings_vars_have_key(const struct setting_parser_info *info, void *set, 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); + dynamic_settings_list structures to their parent. All must have the same + parent. The new structures are allocated from the given pool. */ +void settings_parser_info_update(pool_t pool, + const struct dynamic_settings_parser *parsers); /* Return pointer to beginning of settings for given name, or NULL if there is no such registered name. */ diff --git a/src/lib-sql/Makefile.am b/src/lib-sql/Makefile.am index 74996324a1..79946c7560 100644 --- a/src/lib-sql/Makefile.am +++ b/src/lib-sql/Makefile.am @@ -28,7 +28,6 @@ sql_drivers = @sql_drivers@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ - -DMODULEDIR=\""$(moduledir)"\" \ $(SQL_CFLAGS) dist_sources = \ diff --git a/src/lib-storage/Makefile.am b/src/lib-storage/Makefile.am index 41778895d0..4abc221710 100644 --- a/src/lib-storage/Makefile.am +++ b/src/lib-storage/Makefile.am @@ -5,11 +5,14 @@ pkglib_LTLIBRARIES = libdovecot-storage.la AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-auth \ + -I$(top_srcdir)/src/lib-dict \ + -I$(top_srcdir)/src/lib-master \ -I$(top_srcdir)/src/lib-settings \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ - -DPKG_RUNDIR=\""$(rundir)"\" + -DPKG_RUNDIR=\""$(rundir)"\" \ + -DMODULEDIR=\""$(moduledir)"\" libdovecot_storage_la_SOURCES = \ mail.c \ @@ -19,6 +22,7 @@ libdovecot_storage_la_SOURCES = \ mail-search.c \ mail-search-build.c \ mail-storage.c \ + mail-storage-service.c \ mail-storage-settings.c \ mail-user.c \ mailbox-list.c \ @@ -46,6 +50,7 @@ headers = \ mail-thread.h \ mail-storage.h \ mail-storage-private.h \ + mail-storage-service.h \ mail-storage-settings.h \ mail-user.h \ mailbox-list.h \ diff --git a/src/lib-storage/mail-namespace.c b/src/lib-storage/mail-namespace.c index 204c42b334..cf846598db 100644 --- a/src/lib-storage/mail-namespace.c +++ b/src/lib-storage/mail-namespace.c @@ -217,7 +217,7 @@ int mail_namespaces_init(struct mail_user *user, const char **error_r) namespaces = NULL; ns_p = &namespaces; - mail_set = mail_user_set_get_driver_settings(user->set, "MAIL"); + mail_set = mail_user_set_get_storage_set(user->set); if (array_is_created(&user->set->namespaces)) ns_set = array_get(&user->set->namespaces, &count); else { @@ -313,7 +313,7 @@ struct mail_namespace *mail_namespaces_init_empty(struct mail_user *user) 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"); + ns->mail_set = mail_user_set_get_storage_set(user->set); user->namespaces = ns; return ns; } diff --git a/src/lib-storage/mail-storage-service.c b/src/lib-storage/mail-storage-service.c new file mode 100644 index 0000000000..7ce54b6ab4 --- /dev/null +++ b/src/lib-storage/mail-storage-service.c @@ -0,0 +1,525 @@ +/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "dict.h" +#include "module-dir.h" +#include "restrict-access.h" +#include "settings-parser.h" +#include "auth-master.h" +#include "master-service-private.h" +#include "master-service-settings.h" +#include "mail-user.h" +#include "mail-namespace.h" +#include "mail-storage.h" +#include "mail-storage-service.h" + +#include +#include +#include +#include + +struct mail_storage_service_multi_ctx { + struct master_service *service; + enum mail_storage_service_flags flags; + + unsigned int modules_initialized:1; +}; + +static struct module *modules = NULL; + +static void +master_service_set(struct master_service *service, + const char *key, const char *value) +{ + const char *str; + + str = t_strconcat(key, "=", value, NULL); + if (settings_parse_line(service->set_parser, str) < 0) { + i_fatal("Invalid userdb input '%s': %s", str, + settings_parser_get_error(service->set_parser)); + } +} + +static bool validate_chroot(const struct mail_user_settings *user_set, + const char *dir) +{ + const char *const *chroot_dirs; + + if (*dir == '\0') + return FALSE; + + if (*user_set->valid_chroot_dirs == '\0') + return FALSE; + + chroot_dirs = t_strsplit(user_set->valid_chroot_dirs, ":"); + while (*chroot_dirs != NULL) { + if (**chroot_dirs != '\0' && + strncmp(dir, *chroot_dirs, strlen(*chroot_dirs)) == 0) + return TRUE; + chroot_dirs++; + } + return FALSE; +} + +static int +user_reply_handle(struct master_service *service, + const struct mail_user_settings *user_set, + const struct auth_user_reply *reply, + const char **system_groups_user_r, const char **error_r) +{ + const char *const *str, *p, *line; + unsigned int i, count; + int ret = 0; + + *system_groups_user_r = NULL; + + if (reply->uid != (uid_t)-1) { + if (reply->uid == 0) { + *error_r = "userdb returned 0 as uid"; + return -1; + } + master_service_set(service, "mail_uid", dec2str(reply->uid)); + } + if (reply->gid != (uid_t)-1) + master_service_set(service, "mail_gid", dec2str(reply->gid)); + + if (reply->home != NULL) + master_service_set(service, "mail_home", reply->home); + + if (reply->chroot != NULL) { + if (!validate_chroot(user_set, reply->chroot)) { + *error_r = t_strdup_printf( + "userdb returned invalid chroot directory: %s " + "(see valid_chroot_dirs setting)", + reply->chroot); + return -1; + } + master_service_set(service, "mail_chroot", reply->chroot); + } + + str = array_get(&reply->extra_fields, &count); + for (i = 0; i < count && ret == 0; i++) T_BEGIN { + line = str[i]; + if (strncmp(line, "system_groups_user=", 19) == 0) { + *system_groups_user_r = line + 19; + continue; + } + if (strncmp(line, "mail=", 5) == 0) + line = t_strconcat("mail_location=", line + 5, NULL); + else if ((p = strchr(str[i], '=')) == NULL) + line = t_strconcat(str[i], "=yes", NULL); + else + line = str[i]; + ret = settings_parse_line(service->set_parser, line); + } T_END; + + if (ret < 0) { + *error_r = t_strdup_printf("Invalid userdb input '%s': %s", + str[i], settings_parser_get_error(service->set_parser)); + } + return ret; +} + +static int +service_auth_userdb_lookup(struct master_service *service, bool debug, + const struct mail_user_settings *user_set, + const char **user, const char **system_groups_user_r, + const char **error_r) +{ + struct auth_master_connection *conn; + struct auth_user_reply reply; + const char *system_groups_user, *orig_user = *user; + unsigned int len; + pool_t pool; + int ret; + + pool = pool_alloconly_create("userdb lookup", 1024); + conn = auth_master_init(user_set->auth_socket_path, debug); + ret = auth_master_user_lookup(conn, *user, service->name, + pool, &reply); + if (ret > 0) { + len = reply.chroot == NULL ? 0 : strlen(reply.chroot); + + *user = t_strdup(reply.user); + if (user_reply_handle(service, user_set, &reply, + &system_groups_user, error_r) < 0) + ret = -1; + *system_groups_user_r = t_strdup(system_groups_user); + } else { + if (ret == 0) + *error_r = "unknown user"; + else + *error_r = "userdb lookup failed"; + *system_groups_user_r = NULL; + } + + if (ret > 0 && strcmp(*user, orig_user) != 0) { + if (mail_user_set_get_storage_set(user_set)->mail_debug) + i_info("changed username to %s", *user); + i_set_failure_prefix(t_strdup_printf("%s(%s): ", service->name, + *user)); + } + + auth_master_deinit(&conn); + pool_unref(&pool); + return ret; +} + +static bool parse_uid(const char *str, uid_t *uid_r) +{ + struct passwd *pw; + char *p; + + if (*str >= '0' && *str <= '9') { + *uid_r = (uid_t)strtoul(str, &p, 10); + if (*p == '\0') + return TRUE; + } + + pw = getpwnam(str); + if (pw == NULL) + return FALSE; + + *uid_r = pw->pw_uid; + return TRUE; +} + +static bool parse_gid(const char *str, gid_t *gid_r) +{ + struct group *gr; + char *p; + + if (*str >= '0' && *str <= '9') { + *gid_r = (gid_t)strtoul(str, &p, 10); + if (*p == '\0') + return TRUE; + } + + gr = getgrnam(str); + if (gr == NULL) + return FALSE; + + *gid_r = gr->gr_gid; + return TRUE; +} + +static void +service_drop_privileges(const struct mail_user_settings *set, + const char *system_groups_user, + bool disallow_root, bool keep_setuid_root) +{ + struct restrict_access_settings rset; + uid_t current_euid, setuid_uid = 0; + + current_euid = geteuid(); + restrict_access_init(&rset); + if (*set->mail_uid != '\0') { + if (!parse_uid(set->mail_uid, &rset.uid)) + i_fatal("Unknown mail_uid user: %s", set->mail_uid); + if (rset.uid < (uid_t)set->first_valid_uid || + (set->last_valid_uid != 0 && + rset.uid > (uid_t)set->last_valid_uid)) { + i_fatal("Mail access for users with UID %s " + "not permitted (see first_valid_uid in config file).", + dec2str(rset.uid)); + } + } + if (*set->mail_gid != '\0') { + if (!parse_gid(set->mail_gid, &rset.gid)) + i_fatal("Unknown mail_gid group: %s", set->mail_gid); + if (rset.gid < (gid_t)set->first_valid_gid || + (set->last_valid_gid != 0 && + rset.gid > (gid_t)set->last_valid_gid)) { + i_fatal("Mail access for users with GID %s " + "not permitted (see first_valid_gid in config file).", + dec2str(rset.gid)); + } + } + if (*set->mail_privileged_group != '\0') { + if (!parse_uid(set->mail_privileged_group, &rset.privileged_gid)) + i_fatal("Unknown mail_gid group: %s", set->mail_gid); + } + if (*set->mail_access_groups != '\0') + rset.extra_groups = set->mail_access_groups; + + rset.first_valid_gid = set->first_valid_gid; + rset.last_valid_gid = set->last_valid_gid; + /* we can't chroot if we want to switch between users. there's not + much point either (from security point of view) */ + rset.chroot_dir = *set->mail_chroot == '\0' || keep_setuid_root ? + NULL : set->mail_chroot; + rset.system_groups_user = system_groups_user; + + if (disallow_root && + (rset.uid == 0 || (rset.uid == (uid_t)-1 && current_euid == 0))) + i_fatal("Mail access not allowed for root"); + + if (keep_setuid_root && current_euid != rset.uid) { + if (current_euid != 0) { + /* we're changing the UID, switch back to root first */ + if (seteuid(0) < 0) + i_fatal("seteuid(0) failed: %m"); + } + setuid_uid = rset.uid; + rset.uid = (uid_t)-1; + } + restrict_access(&rset, *set->mail_home == '\0' ? NULL : set->mail_home, + disallow_root); + if (keep_setuid_root) { + if (seteuid(setuid_uid) < 0) + i_fatal("seteuid(%s) failed: %m", dec2str(setuid_uid)); + } +} + +static void +mail_storage_service_init_settings(struct master_service *service, + const struct setting_parser_info *set_root, + bool preserve_home) +{ + const struct setting_parser_info *set_roots[3]; + const char *error; + + (void)umask(0077); + + mail_storage_init(); + mail_storage_register_all(); + mailbox_list_register_all(); + + set_roots[0] = &mail_user_setting_parser_info; + set_roots[1] = set_root; + set_roots[2] = NULL; + + /* read settings after registering storages so they can have their + own setting definitions too */ + if (master_service_settings_read(service, set_roots, + mail_storage_get_dynamic_parsers(), + preserve_home, &error) < 0) + i_fatal("Error reading configuration: %s", error); +} + +static int +mail_storage_service_init_post(struct master_service *service, const char *user, + const struct mail_user_settings *user_set, + struct mail_user **mail_user_r, + const char **error_r) +{ + const struct mail_storage_settings *mail_set; + struct mail_user *mail_user; + const char *home; + + mail_set = mail_user_set_get_storage_set(user_set); + + /* If possible chdir to home directory, so that core file + could be written in case we crash. */ + home = user_set->mail_home; + if (*home != '\0') { + if (chdir(home) < 0) { + if (errno != ENOENT) + i_error("chdir(%s) failed: %m", home); + else if (mail_set->mail_debug) + i_info("Home dir not found: %s", home); + } + } + + mail_user = mail_user_alloc(user, user_set); + if (*home != '\0') + mail_user_set_home(mail_user, home); + mail_user_set_vars(mail_user, geteuid(), service->name, NULL, NULL); + if (mail_user_init(mail_user, error_r) < 0 || + mail_namespaces_init(mail_user, error_r) < 0) { + *error_r = t_strdup(*error_r); + mail_user_unref(&mail_user); + return -1; + } + *mail_user_r = mail_user; + return 0; +} + +struct mail_user * +mail_storage_service_init_user(struct master_service *service, const char *user, + const struct setting_parser_info *set_root, + enum mail_storage_service_flags flags) +{ + const struct master_service_settings *set; + const struct mail_user_settings *user_set; + const struct mail_storage_settings *mail_set; + struct mail_user *mail_user; + void **sets; + const char *orig_user, *home, *system_groups_user, *error; + unsigned int len; + bool userdb_lookup; + + userdb_lookup = (flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0; + mail_storage_service_init_settings(service, set_root, !userdb_lookup); + + /* now that we've read settings, we can set up logging */ + master_service_init_log(service, + t_strdup_printf("%s(%s): ", service->name, user)); + + set = master_service_settings_get(service); + sets = master_service_settings_get_others(service); + user_set = sets[0]; + mail_set = mail_user_set_get_storage_set(user_set); + + if (userdb_lookup) { + /* userdb lookup may change settings, do it as soon as + possible. */ + orig_user = user; + if (service_auth_userdb_lookup(service, mail_set->mail_debug, + user_set, &user, + &system_groups_user, + &error) <= 0) { + i_fatal("%s", error); + } + } else { + home = getenv("HOME"); + system_groups_user = NULL; + if (*user_set->mail_home == '\0' && home != NULL) + master_service_set(service, "mail_home", home); + } + home = user_set->mail_home; + + len = strlen(user_set->mail_chroot); + if (len > 2 && strcmp(user_set->mail_chroot + len - 2, "/.") == 0 && + strncmp(home, user_set->mail_chroot, len - 2) == 0) { + /* If chroot ends with "/.", strip chroot dir from home dir */ + home += len - 2; + master_service_set(service, "mail_home", home); + } + + modules = *user_set->mail_plugins == '\0' ? NULL : + module_dir_load(user_set->mail_plugin_dir, + user_set->mail_plugins, TRUE, + master_service_get_version_string(service)); + + service_drop_privileges(user_set, system_groups_user, + (flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0, FALSE); + /* privileges are now dropped */ + + dict_drivers_register_builtin(); + module_dir_init(modules); + mail_users_init(user_set->auth_socket_path, mail_set->mail_debug); + if (mail_storage_service_init_post(service, user, user_set, + &mail_user, &error) < 0) + i_fatal("%s", error); + return mail_user; +} + +void mail_storage_service_deinit_user(void) +{ + module_dir_unload(&modules); + mail_storage_deinit(); + mail_users_deinit(); + dict_drivers_unregister_builtin(); +} + +struct mail_storage_service_multi_ctx * +mail_storage_service_multi_init(struct master_service *service, + const struct setting_parser_info *set_root, + enum mail_storage_service_flags flags) +{ + struct mail_storage_service_multi_ctx *ctx; + const struct master_service_settings *set; + const struct mail_user_settings *user_set; + const struct mail_storage_settings *mail_set; + void **sets; + + ctx = i_new(struct mail_storage_service_multi_ctx, 1); + ctx->service = service; + ctx->flags = flags; + + mail_storage_service_init_settings(service, set_root, FALSE); + + /* do all the global initialization. delay initializing plugins until + we drop privileges the first time. */ + master_service_init_log(service, + t_strdup_printf("%s: ", service->name)); + + set = master_service_settings_get(service); + sets = master_service_settings_get_others(service); + user_set = sets[0]; + mail_set = mail_user_set_get_storage_set(user_set); + + modules = *user_set->mail_plugins == '\0' ? NULL : + module_dir_load(user_set->mail_plugin_dir, + user_set->mail_plugins, TRUE, + master_service_get_version_string(service)); + + dict_drivers_register_builtin(); + mail_users_init(user_set->auth_socket_path, mail_set->mail_debug); + return ctx; +} + +int mail_storage_service_multi_next(struct mail_storage_service_multi_ctx *ctx, + const char *user, + struct mail_user **mail_user_r, + const char **error_r) +{ + const struct mail_user_settings *user_set; + const struct mail_storage_settings *mail_set; + const char *orig_user, *system_groups_user; + void **sets; + unsigned int len; + int ret; + + sets = master_service_settings_get_others(ctx->service); + user_set = sets[0]; + mail_set = mail_user_set_get_storage_set(user_set); + + if ((ctx->flags & MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP) != 0) { + orig_user = user; + ret = service_auth_userdb_lookup(ctx->service, + mail_set->mail_debug, + user_set, &user, + &system_groups_user, + error_r); + if (ret <= 0) + return ret; + } else { + system_groups_user = NULL; + } + + service_drop_privileges(user_set, system_groups_user, + (ctx->flags & MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT) != 0, TRUE); + + if (!ctx->modules_initialized) { + /* privileges dropped for the first time. initialize the + modules now to avoid code running as root. */ + module_dir_init(modules); + ctx->modules_initialized = TRUE; + } + + /* we couldn't do chrooting, so if chrooting was enabled fix + the home directory */ + len = strlen(user_set->mail_chroot); + if (len > 2 && strcmp(user_set->mail_chroot + len - 2, "/.") == 0 && + strncmp(user_set->mail_home, user_set->mail_chroot, len - 2) == 0) { + /* home dir already contains the chroot dir */ + } else if (len > 0) { + master_service_set(ctx->service, "mail_home", + t_strconcat(user_set->mail_chroot, "/", + user_set->mail_home, NULL)); + } + if (mail_storage_service_init_post(ctx->service, user, + user_set, mail_user_r, error_r) < 0) + return -1; + return 1; +} + +void mail_storage_service_multi_deinit(struct mail_storage_service_multi_ctx **_ctx) +{ + struct mail_storage_service_multi_ctx *ctx = *_ctx; + + *_ctx = NULL; + i_free(ctx); + mail_storage_service_deinit_user(); +} + +void *mail_storage_service_get_settings(struct master_service *service) +{ + void **sets; + + sets = master_service_settings_get_others(service); + return sets[1]; +} diff --git a/src/lib-storage/mail-storage-service.h b/src/lib-storage/mail-storage-service.h new file mode 100644 index 0000000000..2e6a035631 --- /dev/null +++ b/src/lib-storage/mail-storage-service.h @@ -0,0 +1,31 @@ +#ifndef MAIL_STORAGE_SERVICE_H +#define MAIL_STORAGE_SERVICE_H + +enum mail_storage_service_flags { + MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT = 0x01, + MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP = 0x02 +}; + +struct setting_parser_info; + +struct mail_user * +mail_storage_service_init_user(struct master_service *service, const char *user, + const struct setting_parser_info *set_root, + enum mail_storage_service_flags flags); +void mail_storage_service_deinit_user(void); + +struct mail_storage_service_multi_ctx * +mail_storage_service_multi_init(struct master_service *service, + const struct setting_parser_info *set_root, + enum mail_storage_service_flags flags); +/* Returns 1 if ok, 0 if user wasn't found, -1 if error. */ +int mail_storage_service_multi_next(struct mail_storage_service_multi_ctx *ctx, + const char *user, + struct mail_user **mail_user_r, + const char **error_r); +void mail_storage_service_multi_deinit(struct mail_storage_service_multi_ctx **ctx); + +/* Return the settings pointed to by set_root parameter in _init() */ +void *mail_storage_service_get_settings(struct master_service *service); + +#endif diff --git a/src/lib-storage/mail-storage-settings.c b/src/lib-storage/mail-storage-settings.c index 42ed2c13fa..c5befd02c0 100644 --- a/src/lib-storage/mail-storage-settings.c +++ b/src/lib-storage/mail-storage-settings.c @@ -11,8 +11,11 @@ #include +#define MAIL_STORAGE_SET_DRIVER_NAME "MAIL" + static bool mail_storage_settings_check(void *_set, pool_t pool, const char **error_r); static bool namespace_settings_check(void *_set, pool_t pool, const char **error_r); +static bool mail_user_settings_check(void *_set, pool_t pool, const char **error_r); #undef DEF #define DEF(type, name) \ @@ -127,6 +130,25 @@ struct setting_parser_info mail_namespace_setting_parser_info = { offsetof(struct mail_user_settings, field), defines } static struct setting_define mail_user_setting_defines[] = { + DEF(SET_STR, base_dir), + DEF(SET_STR, auth_socket_path), + + DEF(SET_STR, mail_uid), + DEF(SET_STR, mail_gid), + DEF(SET_STR_VARS, mail_home), + DEF(SET_STR, mail_chroot), + DEF(SET_STR, mail_access_groups), + DEF(SET_STR, mail_privileged_group), + DEF(SET_STR, valid_chroot_dirs), + + 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_plugins), + DEF(SET_STR, mail_plugin_dir), + DEFLIST(namespaces, "namespace", &mail_namespace_setting_parser_info), { SET_STRLIST, "plugin", offsetof(struct mail_user_settings, plugin_envs), NULL }, @@ -134,6 +156,25 @@ static struct setting_define mail_user_setting_defines[] = { }; static struct mail_user_settings mail_user_default_settings = { + MEMBER(base_dir) PKG_RUNDIR, + MEMBER(auth_socket_path) "auth-master", + + MEMBER(mail_uid) "", + MEMBER(mail_gid) "", + MEMBER(mail_home) "", + MEMBER(mail_chroot) "", + MEMBER(mail_access_groups) "", + MEMBER(mail_privileged_group) "", + MEMBER(valid_chroot_dirs) "", + + MEMBER(first_valid_uid) 500, + MEMBER(last_valid_uid) 0, + MEMBER(first_valid_gid) 1, + MEMBER(last_valid_gid) 0, + + MEMBER(mail_plugins) "", + MEMBER(mail_plugin_dir) MODULEDIR, + MEMBER(namespaces) ARRAY_INIT, MEMBER(plugin_envs) ARRAY_INIT }; @@ -147,7 +188,8 @@ struct setting_parser_info mail_user_setting_parser_info = { MEMBER(parent_offset) (size_t)-1, MEMBER(type_offset) (size_t)-1, - MEMBER(struct_size) sizeof(struct mail_user_settings) + MEMBER(struct_size) sizeof(struct mail_user_settings), + MEMBER(check_func) mail_user_settings_check }; const void * @@ -165,6 +207,13 @@ mail_user_set_get_driver_settings(const struct mail_user_settings *set, return dset; } +const struct mail_storage_settings * +mail_user_set_get_storage_set(const struct mail_user_settings *set) +{ + return mail_user_set_get_driver_settings(set, + MAIL_STORAGE_SET_DRIVER_NAME); +} + const void *mail_storage_get_driver_settings(struct mail_storage *storage) { return mail_user_set_get_driver_settings(storage->ns->user->set, @@ -189,7 +238,7 @@ mail_storage_settings_to_index_flags(const struct mail_storage_settings *set) return index_flags; } -void mail_storage_namespace_defines_init(pool_t pool) +const struct dynamic_settings_parser *mail_storage_get_dynamic_parsers(void) { struct dynamic_settings_parser *parsers; struct mail_storage *const *storages; @@ -197,7 +246,7 @@ void mail_storage_namespace_defines_init(pool_t pool) storages = array_get(&mail_storage_classes, &count); parsers = t_new(struct dynamic_settings_parser, count + 1); - parsers[0].name = "MAIL"; + parsers[0].name = MAIL_STORAGE_SET_DRIVER_NAME; parsers[0].info = &mail_storage_setting_parser_info; for (i = 0, j = 1; i < count; i++) { @@ -208,8 +257,14 @@ void mail_storage_namespace_defines_init(pool_t pool) parsers[j].info = storages[i]->v.get_setting_parser_info(); j++; } + return parsers; +} - settings_parser_info_update(pool, parsers[j-1].info->parent, parsers); +static void +fix_base_path(struct mail_user_settings *set, pool_t pool, const char **str) +{ + if (*str != NULL && **str != '\0' && **str != '/') + *str = p_strconcat(pool, set->base_dir, "/", *str, NULL); } /* */ @@ -269,4 +324,23 @@ static bool namespace_settings_check(void *_set, pool_t pool ATTR_UNUSED, } return TRUE; } + +static bool mail_user_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_r) +{ + struct mail_user_settings *set = _set; + +#ifndef CONFIG_BINARY + fix_base_path(set, pool, &set->auth_socket_path); +#endif + + if (*set->mail_plugins != '\0' && + access(set->mail_plugin_dir, R_OK | X_OK) < 0) { + *error_r = t_strdup_printf( + "mail_plugin_dir: access(%s) failed: %m", + set->mail_plugin_dir); + return FALSE; + } + return TRUE; +} /* */ diff --git a/src/lib-storage/mail-storage-settings.h b/src/lib-storage/mail-storage-settings.h index 286ccad5cc..d6f24d66f7 100644 --- a/src/lib-storage/mail-storage-settings.h +++ b/src/lib-storage/mail-storage-settings.h @@ -40,6 +40,23 @@ struct mail_namespace_settings { }; struct mail_user_settings { + const char *base_dir; + const char *auth_socket_path; + + const char *mail_uid; + const char *mail_gid; + const char *mail_home; + const char *mail_chroot; + const char *mail_access_groups; + const char *mail_privileged_group; + const char *valid_chroot_dirs; + + unsigned int first_valid_uid, last_valid_uid; + unsigned int first_valid_gid, last_valid_gid; + + const char *mail_plugins; + const char *mail_plugin_dir; + ARRAY_DEFINE(namespaces, struct mail_namespace_settings *); ARRAY_DEFINE(plugin_envs, const char *); }; @@ -52,11 +69,13 @@ 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 struct mail_storage_settings * +mail_user_set_get_storage_set(const struct mail_user_settings *set); 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); +const struct dynamic_settings_parser *mail_storage_get_dynamic_parsers(void); #endif diff --git a/src/lib-storage/mail-user.c b/src/lib-storage/mail-user.c index 9a749ae0d9..9e898ca489 100644 --- a/src/lib-storage/mail-user.c +++ b/src/lib-storage/mail-user.c @@ -8,6 +8,7 @@ #include "var-expand.h" #include "settings-parser.h" #include "auth-master.h" +#include "master-service.h" #include "mail-storage-settings.h" #include "mail-namespace.h" #include "mail-storage.h" @@ -35,7 +36,7 @@ struct mail_user *mail_user_alloc(const char *username, i_assert(username != NULL); i_assert(*username != '\0'); - pool = pool_alloconly_create("mail user", 2048); + pool = pool_alloconly_create("mail user", 4096); user = p_new(pool, struct mail_user, 1); user->pool = pool; user->refcount = 1; @@ -97,7 +98,7 @@ int mail_user_init(struct mail_user *user, const char **error_r) if (mail_user_expand_plugins_envs(user, error_r) < 0) return -1; - mail_set = mail_user_set_get_driver_settings(user->set, "MAIL"); + mail_set = mail_user_set_get_storage_set(user->set); user->mail_debug = mail_set->mail_debug; user->initialized = TRUE; @@ -248,8 +249,7 @@ int mail_user_get_home(struct mail_user *user, const char **home_r) userdb_pool = pool_alloconly_create("userdb lookup", 512); ret = auth_master_user_lookup(auth_master_conn, user->username, - AUTH_SERVICE_INTERNAL, - userdb_pool, &reply); + "lib-storage", userdb_pool, &reply); if (ret < 0) *home_r = NULL; else { @@ -264,18 +264,23 @@ int mail_user_get_home(struct mail_user *user, const char **home_r) } const char *mail_user_plugin_getenv(struct mail_user *user, const char *name) +{ + return mail_user_set_plugin_getenv(user->set, name); +} + +const char *mail_user_set_plugin_getenv(const struct mail_user_settings *set, + const char *name) { const char *const *envs; - unsigned int i, count, name_len = strlen(name); + unsigned int i, count; - if (!array_is_created(&user->set->plugin_envs)) + if (!array_is_created(&set->plugin_envs)) return NULL; - envs = array_get(&user->set->plugin_envs, &count); - for (i = 0; i < count; i++) { - if (strncmp(envs[i], name, name_len) == 0 && - envs[i][name_len] == '=') - return envs[i] + name_len + 1; + envs = array_get(&set->plugin_envs, &count); + for (i = 0; i < count; i += 2) { + if (strcmp(envs[i], name) == 0) + return envs[i+1]; } return NULL; } @@ -313,14 +318,6 @@ const char *mail_user_get_temp_prefix(struct mail_user *user) void mail_users_init(const char *auth_socket_path, bool debug) { - const char *base_dir; - - if (auth_socket_path == NULL) { - base_dir = getenv("BASE_DIR"); - if (base_dir == NULL) - base_dir = PKG_RUNDIR; - auth_socket_path = t_strconcat(base_dir, "/auth-master", NULL); - } auth_master_conn = auth_master_init(auth_socket_path, debug); } diff --git a/src/lib-storage/mail-user.h b/src/lib-storage/mail-user.h index bfd97f72ec..7dd9991ad5 100644 --- a/src/lib-storage/mail-user.h +++ b/src/lib-storage/mail-user.h @@ -91,6 +91,8 @@ int mail_user_get_home(struct mail_user *user, const char **home_r); const char *mail_user_get_temp_prefix(struct mail_user *user); /* If name exists in plugin_envs, return its value. */ const char *mail_user_plugin_getenv(struct mail_user *user, const char *name); +const char *mail_user_set_plugin_getenv(const struct mail_user_settings *set, + const char *name); /* Add more namespaces to user's namespaces. The ->next pointers may be changed, so the namespaces pointer will be updated to user->namespaces. */ diff --git a/src/master/Makefile.am b/src/master/Makefile.am index f307fef386..c3306f90c1 100644 --- a/src/master/Makefile.am +++ b/src/master/Makefile.am @@ -6,12 +6,12 @@ pkglibexec_PROGRAMS = ssl-build-param AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DPKG_RUNDIR=\""$(rundir)"\" \ -DPKG_STATEDIR=\""$(statedir)"\" \ -DPKG_LIBEXECDIR=\""$(pkglibexecdir)"\" \ -DBINDIR=\""$(bindir)"\" \ - -DMODULEDIR=\""$(moduledir)"\" \ -DSSLDIR=\""$(ssldir)\"" dovecot_LDADD = \ @@ -31,7 +31,6 @@ dovecot_SOURCES = \ mail-process.c \ master-settings.c \ main.c \ - syslog-util.c \ ssl-init.c \ sysinfo-get.c @@ -49,7 +48,6 @@ noinst_HEADERS = \ mail-process.h \ master-login-interface.h \ master-settings.h \ - syslog-util.h \ ssl-init.h \ sysinfo-get.h diff --git a/src/master/child-process.c b/src/master/child-process.c index 0851ee7b1a..dafbee020c 100644 --- a/src/master/child-process.c +++ b/src/master/child-process.c @@ -6,7 +6,6 @@ #include "hash.h" #include "str.h" #include "env-util.h" -#include "syslog-util.h" #include "child-process.h" #include @@ -44,8 +43,6 @@ void child_process_remove(pid_t pid) void child_process_init_env(const struct master_settings *set) { - int facility; - /* remove all environment, we don't need them */ env_clean(); @@ -54,11 +51,6 @@ void child_process_init_env(const struct master_settings *set) if (env_tz != NULL) env_put(t_strconcat("TZ=", env_tz, NULL)); - if (master_set == NULL || - !syslog_facility_find(set->syslog_facility, &facility)) - facility = LOG_MAIL; - env_put(t_strdup_printf("SYSLOG_FACILITY=%d", facility)); - if (master_set != NULL && !set->version_ignore) env_put("DOVECOT_VERSION="PACKAGE_VERSION); #ifdef DEBUG diff --git a/src/plugins/convert/Makefile.am b/src/plugins/convert/Makefile.am index a8296266c0..5a25bf63b7 100644 --- a/src/plugins/convert/Makefile.am +++ b/src/plugins/convert/Makefile.am @@ -2,11 +2,10 @@ pkglibexecdir = $(libexecdir)/dovecot AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ - -I$(top_srcdir)/src/lib-settings \ + -I$(top_srcdir)/src/lib-master \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-index \ -I$(top_srcdir)/src/lib-storage \ - -I$(top_srcdir)/src/lib-storage/index \ -DPKG_RUNDIR=\""$(rundir)"\" lib20_convert_plugin_la_LDFLAGS = -module -avoid-version @@ -19,14 +18,12 @@ lib20_convert_plugin_la_SOURCES = \ convert-plugin.c noinst_HEADERS = \ - convert-settings.h \ convert-storage.h \ convert-plugin.h pkglibexec_PROGRAMS = convert-tool convert_tool_SOURCES = \ - convert-settings.c \ convert-tool.c common_objects = \ diff --git a/src/plugins/convert/convert-settings.c b/src/plugins/convert/convert-settings.c deleted file mode 100644 index 16eafce499..0000000000 --- a/src/plugins/convert/convert-settings.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "settings-parser.h" -#include "mail-storage-settings.h" -#include "convert-settings.h" - -#include -#include - -#undef DEF -#define DEF(type, name) \ - { type, #name, offsetof(struct convert_settings, name), NULL } - -static struct setting_define convert_setting_defines[] = { - DEF(SET_STR, base_dir), - DEF(SET_STR, auth_socket_path), - - { SET_STRLIST, "plugin", offsetof(struct convert_settings, plugin_envs), NULL }, - - SETTING_DEFINE_LIST_END -}; - -static struct convert_settings convert_default_settings = { - MEMBER(base_dir) PKG_RUNDIR, - MEMBER(auth_socket_path) "auth-master" -}; - -struct setting_parser_info convert_setting_parser_info = { - MEMBER(defines) convert_setting_defines, - MEMBER(defaults) &convert_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 convert_settings) -}; - -static pool_t settings_pool = NULL; - -static void fix_base_path(struct convert_settings *set, const char **str) -{ - if (*str != NULL && **str != '\0' && **str != '/') { - *str = p_strconcat(settings_pool, - set->base_dir, "/", *str, NULL); - } -} - -void convert_settings_read(const struct convert_settings **set_r, - const struct mail_user_settings **user_set_r) -{ - static const struct setting_parser_info *roots[] = { - &convert_setting_parser_info, - &mail_user_setting_parser_info - }; - struct setting_parser_context *parser; - struct convert_settings *set; - void **sets; - - if (settings_pool == NULL) - settings_pool = pool_alloconly_create("convert 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_environ(parser) < 0) { - i_fatal("Error reading configuration: %s", - settings_parser_get_error(parser)); - } - - sets = settings_parser_get_list(parser); - set = sets[0]; - fix_base_path(set, &set->auth_socket_path); - - *set_r = set; - *user_set_r = sets[1]; - settings_parser_deinit(&parser); -} diff --git a/src/plugins/convert/convert-settings.h b/src/plugins/convert/convert-settings.h deleted file mode 100644 index 8bb2e1e49f..0000000000 --- a/src/plugins/convert/convert-settings.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CONVERT_SETTINGS_H -#define CONVERT_SETTINGS_H - -struct mail_user_settings; - -struct convert_settings { - const char *base_dir; - const char *auth_socket_path; - - ARRAY_DEFINE(plugin_envs, const char *); -}; - -void convert_settings_read(const struct convert_settings **set_r, - const struct mail_user_settings **user_set_r); - -#endif diff --git a/src/plugins/convert/convert-tool.c b/src/plugins/convert/convert-tool.c index 1fb51548b6..0ba2de2f4b 100644 --- a/src/plugins/convert/convert-tool.c +++ b/src/plugins/convert/convert-tool.c @@ -1,64 +1,58 @@ /* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "ioloop.h" -#include "randgen.h" -#include "lib-signals.h" +#include "env-util.h" +#include "master-service.h" #include "mail-namespace.h" -#include "mail-storage-private.h" -#include "convert-settings.h" +#include "mail-storage.h" +#include "mail-storage-service.h" #include "convert-storage.h" #include +#include #define USAGE_STRING \ "Usage: \n" \ " [skip_broken_mailboxes] [skip_dotfiles] [alt_hierarchy_char=]" -int main(int argc, const char *argv[]) +int main(int argc, char *argv[]) { - struct ioloop *ioloop; + struct master_service *service; struct mail_user *user; - const struct convert_settings *set; - const struct mail_user_settings *user_set; - const struct mail_storage_settings *mail_set; - struct convert_plugin_settings set2; + struct convert_plugin_settings set; struct mail_namespace *dest_ns; struct mail_namespace_settings ns_set; const char *error; - int i, ret = 0; + int i, c, ret = 0; - lib_init(); - lib_signals_init(); - random_init(); - mail_storage_init(); - mail_storage_register_all(); - mailbox_list_register_all(); + service = master_service_init("convert-tool", + MASTER_SERVICE_FLAG_STANDALONE, + argc, argv); - convert_settings_read(&set, &user_set); - mail_set = mail_user_set_get_driver_settings(user_set, "MAIL"); - mail_users_init(set->auth_socket_path, mail_set->mail_debug); - - if (argc <= 4) + while ((c = getopt(argc, argv, master_service_getopt_string())) > 0) { + if (!master_service_parse_option(service, c, optarg)) + i_fatal(USAGE_STRING); + } + if (argc - optind < 4) i_fatal(USAGE_STRING); - ioloop = io_loop_create(); + env_put(t_strconcat("HOME=", argv[optind+1], NULL)); - memset(&set2, 0, sizeof(set2)); - for (i = 5; i < argc; i++) { + memset(&set, 0, sizeof(set)); + for (i = optind + 4; i < argc; i++) { if (strcmp(argv[i], "skip_broken_mailboxes") != 0) - set2.skip_broken_mailboxes = TRUE; + set.skip_broken_mailboxes = TRUE; else if (strcmp(argv[i], "skip_dotdirs") != 0) - set2.skip_dotdirs = TRUE; + set.skip_dotdirs = TRUE; else if (strncmp(argv[i], "alt_hierarchy_char=", 19) != 0) - set2.alt_hierarchy_char = argv[i][19]; + set.alt_hierarchy_char = argv[i][19]; + else + i_fatal(USAGE_STRING); } - user = mail_user_alloc(argv[1], user_set); - mail_user_set_home(user, argv[2]); - mail_user_set_vars(user, geteuid(), "convert", NULL, NULL); - if (mail_user_init(user, &error) < 0) - i_fatal("Mail user initialization failed: %s", error); + master_service_init_log(service, + t_strdup_printf("convert-tool(%s): ", argv[optind])); + user = mail_storage_service_init_user(service, argv[optind], NULL, 0); memset(&ns_set, 0, sizeof(ns_set)); ns_set.location = argv[4]; @@ -71,19 +65,16 @@ int main(int argc, const char *argv[]) "mail storage with data '%s': %s", argv[4], error); } - ret = convert_storage(argv[3], dest_ns, &set2); + ret = convert_storage(argv[3], dest_ns, &set); if (ret > 0) i_info("Successfully converted"); else if (ret == 0) i_error("Source storage not found"); else i_error("Internal failure"); - mail_user_unref(&user); - io_loop_destroy(&ioloop); - mail_storage_deinit(); - mail_users_deinit(); - lib_signals_deinit(); - lib_deinit(); + mail_user_unref(&user); + mail_storage_service_deinit_user(); + master_service_deinit(&service); return ret <= 0 ? 1 : 0; } diff --git a/src/plugins/expire/Makefile.am b/src/plugins/expire/Makefile.am index 4a4e7a0c60..0877b17bfe 100644 --- a/src/plugins/expire/Makefile.am +++ b/src/plugins/expire/Makefile.am @@ -3,8 +3,9 @@ pkglibexecdir = $(libexecdir)/dovecot 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-settings \ + -I$(top_srcdir)/src/lib-master \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ @@ -22,22 +23,18 @@ lib20_expire_plugin_la_SOURCES = \ expire-plugin.c noinst_HEADERS = \ - auth-client.h \ expire-env.h \ - expire-plugin.h \ - expire-settings.h + expire-plugin.h pkglibexec_PROGRAMS = expire-tool expire_tool_SOURCES = \ - auth-client.c \ - expire-settings.c \ expire-tool.c libs = \ $(top_builddir)/src/lib-storage/libdovecot-storage.la \ $(top_builddir)/src/lib-dovecot/libdovecot.la -expire_tool_LDADD = $(libs) +expire_tool_LDADD = $(libs) expire-env.o expire_tool_DEPENDENCIES = $(libs) diff --git a/src/plugins/expire/auth-client.c b/src/plugins/expire/auth-client.c index bdae7424fc..86ee2dff26 100644 --- a/src/plugins/expire/auth-client.c +++ b/src/plugins/expire/auth-client.c @@ -82,7 +82,7 @@ int auth_client_put_user_env(struct auth_master_connection *conn, int ret; pool = pool_alloconly_create("userdb lookup", 512); - ret = auth_master_user_lookup(conn, user, AUTH_SERVICE_INTERNAL, + ret = auth_master_user_lookup(conn, user, MASTER_SERVICE_INTERNAL, pool, &reply); if (ret > 0) auth_set_env(user, &reply); diff --git a/src/plugins/expire/expire-settings.c b/src/plugins/expire/expire-settings.c deleted file mode 100644 index 818085b06f..0000000000 --- a/src/plugins/expire/expire-settings.c +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "settings-parser.h" -#include "mail-storage-settings.h" -#include "expire-settings.h" - -#include -#include - -#undef DEF -#define DEF(type, name) \ - { type, #name, offsetof(struct expire_settings, name), NULL } - -static struct setting_define expire_setting_defines[] = { - DEF(SET_STR, base_dir), - DEF(SET_STR, auth_socket_path), - - { SET_STRLIST, "plugin", offsetof(struct expire_settings, plugin_envs), NULL }, - - SETTING_DEFINE_LIST_END -}; - -static struct expire_settings expire_default_settings = { - MEMBER(base_dir) PKG_RUNDIR, - MEMBER(auth_socket_path) "auth-master" -}; - -struct setting_parser_info expire_setting_parser_info = { - MEMBER(defines) expire_setting_defines, - MEMBER(defaults) &expire_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 expire_settings) -}; - -static pool_t settings_pool = NULL; - -static void fix_base_path(struct expire_settings *set, const char **str) -{ - if (*str != NULL && **str != '\0' && **str != '/') { - *str = p_strconcat(settings_pool, - set->base_dir, "/", *str, NULL); - } -} - -static void -parse_expand_vars(struct setting_parser_context *parser, const char *value) -{ - const char *const *expanded; - - expanded = t_strsplit(value, " "); - settings_parse_set_keys_expandeded(parser, settings_pool, expanded); - /* settings from userdb are in the VARS_EXPANDED list. for each - unknown setting in the list assume it's a plugin setting. */ - for (; *expanded != NULL; expanded++) { - if (settings_parse_is_valid_key(parser, *expanded)) - continue; - - value = getenv(t_str_ucase(*expanded)); - if (value == NULL) - continue; - - settings_parse_line(parser, t_strconcat("plugin/", *expanded, - "=", value, NULL)); - } -} - -void expire_settings_read(const struct expire_settings **set_r, - const struct mail_user_settings **user_set_r) -{ - static const struct setting_parser_info *roots[] = { - &expire_setting_parser_info, - &mail_user_setting_parser_info - }; - struct setting_parser_context *parser; - struct expire_settings *set; - const char *value; - void **sets; - - if (settings_pool == NULL) - settings_pool = pool_alloconly_create("expire 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_environ(parser) < 0) { - i_fatal("Error reading configuration: %s", - settings_parser_get_error(parser)); - } - - value = getenv("VARS_EXPANDED"); - if (value != NULL) - parse_expand_vars(parser, value); - - sets = settings_parser_get_list(parser); - set = sets[0]; - fix_base_path(set, &set->auth_socket_path); - - *set_r = set; - *user_set_r = sets[1]; - settings_parser_deinit(&parser); -} diff --git a/src/plugins/expire/expire-settings.h b/src/plugins/expire/expire-settings.h deleted file mode 100644 index 46e5c576e9..0000000000 --- a/src/plugins/expire/expire-settings.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CONVERT_SETTINGS_H -#define CONVERT_SETTINGS_H - -struct mail_user_settings; - -struct expire_settings { - const char *base_dir; - const char *auth_socket_path; - - ARRAY_DEFINE(plugin_envs, const char *); -}; - -void expire_settings_read(const struct expire_settings **set_r, - const struct mail_user_settings **user_set_r); - -#endif diff --git a/src/plugins/expire/expire-tool.c b/src/plugins/expire/expire-tool.c index e0c832c258..92a51b2c1c 100644 --- a/src/plugins/expire/expire-tool.c +++ b/src/plugins/expire/expire-tool.c @@ -1,73 +1,27 @@ /* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "ioloop.h" #include "env-util.h" -#include "file-lock.h" -#include "randgen.h" -#include "lib-signals.h" #include "dict.h" +#include "master-service.h" +#include "master-service-settings.h" #include "mail-index.h" #include "mail-search-build.h" #include "mail-storage.h" +#include "mail-storage-service.h" #include "mail-namespace.h" #include "auth-client.h" #include "auth-master.h" #include "expire-env.h" -#include "expire-settings.h" #include -/* ugly, but automake doesn't like having it built as both static and - dynamic object.. */ -#include "expire-env.c" - struct expire_context { - struct auth_master_connection *auth_conn; - - char *user; + struct mail_storage_service_multi_ctx *multi; struct mail_user *mail_user; - const struct expire_settings *set; bool testrun; }; -static int user_init(struct expire_context *ctx, const char *user) -{ - const struct mail_user_settings *user_set; - const char *error; - int ret; - - env_clean(); - if ((ret = auth_client_put_user_env(ctx->auth_conn, user)) <= 0) { - if (ret < 0) - return ret; - - /* user no longer exists */ - return 0; - } - - expire_settings_read(&ctx->set, &user_set); - - ctx->mail_user = mail_user_alloc(user, user_set); - mail_user_set_home(ctx->mail_user, getenv("HOME")); - mail_user_set_vars(ctx->mail_user, geteuid(), "expire", NULL, NULL); - if (mail_user_init(ctx->mail_user, &error) < 0) { - i_error("Mail user initialization failed: %s", error); - return -1; - } - if (mail_namespaces_init(ctx->mail_user, &error) < 0) { - i_error("Namespace initialization failed: %s", error); - return -1; - } - return 1; -} - -static void user_deinit(struct expire_context *ctx) -{ - mail_user_unref(&ctx->mail_user); - i_free_and_null(ctx->user); -} - static int mailbox_delete_old_mails(struct expire_context *ctx, const char *user, const char *mailbox, @@ -89,15 +43,20 @@ mailbox_delete_old_mails(struct expire_context *ctx, const char *user, *oldest_r = 0; - if (ctx->user != NULL && strcmp(user, ctx->user) != 0) - user_deinit(ctx); - if (ctx->user == NULL) { - if ((ret = user_init(ctx, user)) <= 0) { - if (ctx->testrun) - i_info("User lookup failed: %s", user); + if (ctx->mail_user != NULL && + strcmp(user, ctx->mail_user->username) != 0) + mail_user_unref(&ctx->mail_user); + if (ctx->mail_user == NULL) { + i_set_failure_prefix(t_strdup_printf("expire-tool(%s): ", + user)); + ret = mail_storage_service_multi_next(ctx->multi, user, + &ctx->mail_user, &errstr); + if (ret <= 0) { + if (ret < 0 || ctx->testrun) + i_error("User init failed: %s", errstr); return ret; } - ctx->user = i_strdup(user); + i_info("success: %s %d", ctx->mail_user->username, (int)geteuid()); } ns_mailbox = mailbox; @@ -190,61 +149,40 @@ mailbox_delete_old_mails(struct expire_context *ctx, const char *user, return ret < 0 ? -1 : 0; } -static const char *expire_getenv(struct expire_context *ctx, const char *name) -{ - const char *const *envs; - unsigned int i, count, name_len = strlen(name); - - if (!array_is_created(&ctx->set->plugin_envs)) - return NULL; - - envs = array_get(&ctx->set->plugin_envs, &count); - for (i = 0; i < count; i++) { - if (strncmp(envs[i], name, name_len) == 0 && - envs[i][name_len] == '=') - return envs[i] + name_len + 1; - } - return NULL; -} - -static void expire_run(bool testrun) +static void expire_run(struct master_service *service, bool testrun) { struct expire_context ctx; struct dict *dict = NULL; - struct dict_transaction_context *trans; const struct mail_user_settings *user_set; - const struct mail_storage_settings *mail_set; + void **sets; + struct dict_transaction_context *trans; struct dict_iterate_context *iter; struct expire_env *env; time_t oldest; unsigned int expunge_secs, altmove_secs; - const char *p, *key, *value; - const char *userp, *mailbox; + const char *p, *key, *value, *expire, *expire_altmove, *expire_dict; + const char *userp = NULL, *mailbox; int ret; - dict_drivers_register_builtin(); - mail_storage_init(); - mail_storage_register_all(); - mailbox_list_register_all(); - memset(&ctx, 0, sizeof(ctx)); - expire_settings_read(&ctx.set, &user_set); - mail_set = mail_user_set_get_driver_settings(user_set, "MAIL"); - mail_users_init(ctx.set->auth_socket_path, mail_set->mail_debug); + ctx.multi = mail_storage_service_multi_init(service, NULL, + MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP); + + sets = master_service_settings_get_others(service); + user_set = sets[0]; - if (expire_getenv(&ctx, "EXPIRE") == NULL && - expire_getenv(&ctx, "EXPIRE_ALTMOVE") == NULL) + expire = mail_user_set_plugin_getenv(user_set, "expire"); + expire_altmove = mail_user_set_plugin_getenv(user_set, "expire_altmove"); + expire_dict = mail_user_set_plugin_getenv(user_set, "expire_dict"); + + if (expire == NULL && expire_altmove == NULL) i_fatal("expire and expire_altmove settings not set"); - if (expire_getenv(&ctx, "EXPIRE_DICT") == NULL) + if (expire_dict == NULL) i_fatal("expire_dict setting not set"); ctx.testrun = testrun; - ctx.auth_conn = auth_master_init(ctx.set->auth_socket_path, - mail_set->mail_debug); - env = expire_env_init(expire_getenv(&ctx, "EXPIRE"), - expire_getenv(&ctx, "EXPIRE_ALTMOVE")); - dict = dict_init(expire_getenv(&ctx, "EXPIRE_DICT"), - DICT_DATA_TYPE_UINT32, ""); + env = expire_env_init(expire, expire_altmove); + dict = dict_init(expire_dict, DICT_DATA_TYPE_UINT32, ""); if (dict == NULL) i_fatal("dict_init() failed"); @@ -321,6 +259,9 @@ static void expire_run(bool testrun) } } } + if (testrun && userp == NULL) + i_info("No entries in dictionary"); + dict_iterate_deinit(&iter); if (!testrun) dict_transaction_commit(&trans); @@ -328,37 +269,39 @@ static void expire_run(bool testrun) dict_transaction_rollback(&trans); dict_deinit(&dict); - if (ctx.user != NULL) - user_deinit(&ctx); - auth_master_deinit(&ctx.auth_conn); - - mail_storage_deinit(); - mail_users_deinit(); - dict_drivers_unregister_builtin(); + if (ctx.mail_user != NULL) + mail_user_unref(&ctx.mail_user); + mail_storage_service_multi_deinit(&ctx.multi); } -int main(int argc ATTR_UNUSED, const char *argv[]) +int main(int argc, char *argv[]) { - struct ioloop *ioloop; + struct master_service *service; + const char *getopt_str; bool test = FALSE; + int c; - lib_init(); - lib_signals_init(); - random_init(); + service = master_service_init("expire-tool", + MASTER_SERVICE_FLAG_STANDALONE, + argc, argv); - while (argv[1] != NULL) { - if (strcmp(argv[1], "--test") == 0) + getopt_str = t_strconcat("t", master_service_getopt_string(), NULL); + while ((c = getopt(argc, argv, getopt_str)) > 0) { + switch (c) { + case 't': test = TRUE; - else - i_fatal("Unknown parameter: %s", argv[1]); - argv++; + break; + default: + if (!master_service_parse_option(service, c, optarg)) + i_fatal("Unknown parameter: -%c", c); + break; + } } + if (optind != argc) + i_fatal("Unknown parameter: %s", argv[optind]); - ioloop = io_loop_create(); - expire_run(test); - io_loop_destroy(&ioloop); + expire_run(service, test); - lib_signals_deinit(); - lib_deinit(); + master_service_deinit(&service); return 0; } diff --git a/src/pop3/Makefile.am b/src/pop3/Makefile.am index 8e9324ea8a..bd702a379a 100644 --- a/src/pop3/Makefile.am +++ b/src/pop3/Makefile.am @@ -7,9 +7,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-settings \ -I$(top_srcdir)/src/lib-dict \ -I$(top_srcdir)/src/lib-mail \ - -I$(top_srcdir)/src/lib-storage \ - -DPKG_RUNDIR=\""$(rundir)"\" \ - -DMODULEDIR=\""$(moduledir)"\" + -I$(top_srcdir)/src/lib-storage pop3_LDFLAGS = -export-dynamic diff --git a/src/pop3/main.c b/src/pop3/main.c index ec5c5e184a..a9286b17d8 100644 --- a/src/pop3/main.c +++ b/src/pop3/main.c @@ -173,9 +173,9 @@ static void main_preinit(const struct pop3_settings **set_r, 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); + modules = *(*user_set_r)->mail_plugins == '\0' ? NULL : + module_dir_load((*user_set_r)->mail_plugin_dir, + (*user_set_r)->mail_plugins, TRUE, version); restrict_access_by_env(getenv("HOME"), !IS_STANDALONE()); restrict_access_allow_coredumps(TRUE); @@ -214,7 +214,7 @@ static bool main_init(const struct pop3_settings *set, } dict_drivers_register_builtin(); - mail_users_init(set->auth_socket_path, set->mail_debug); + mail_users_init(user_set->auth_socket_path, set->mail_debug); clients_init(); module_dir_init(modules); diff --git a/src/pop3/pop3-settings.c b/src/pop3/pop3-settings.c index f4c948bde9..f74e55daeb 100644 --- a/src/pop3/pop3-settings.c +++ b/src/pop3/pop3-settings.c @@ -9,8 +9,6 @@ #include #include -static bool pop3_settings_check(void *_set, pool_t pool, const char **error_r); - #undef DEF #undef DEFLIST #define DEF(type, name) \ @@ -19,16 +17,10 @@ static bool pop3_settings_check(void *_set, pool_t pool, const char **error_r); { SET_DEFLIST, name, offsetof(struct pop3_settings, field), defines } static struct setting_define pop3_setting_defines[] = { - DEF(SET_STR, base_dir), - DEF(SET_STR, auth_socket_path), - 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_BOOL, pop3_no_flag_updates), DEF(SET_BOOL, pop3_enable_last), DEF(SET_BOOL, pop3_reuse_xuidl), @@ -41,16 +33,10 @@ static struct setting_define pop3_setting_defines[] = { }; static struct pop3_settings pop3_default_settings = { - MEMBER(base_dir) PKG_RUNDIR, - MEMBER(auth_socket_path) "auth-master", - MEMBER(mail_debug) FALSE, MEMBER(shutdown_clients) FALSE, MEMBER(verbose_proctitle) FALSE, - MEMBER(mail_plugins) "", - MEMBER(mail_plugin_dir) MODULEDIR, - MEMBER(pop3_no_flag_updates) FALSE, MEMBER(pop3_enable_last) FALSE, MEMBER(pop3_reuse_xuidl) FALSE, @@ -70,40 +56,11 @@ struct setting_parser_info pop3_setting_parser_info = { MEMBER(parent_offset) (size_t)-1, MEMBER(type_offset) (size_t)-1, MEMBER(struct_size) sizeof(struct pop3_settings), - MEMBER(check_func) pop3_settings_check + MEMBER(check_func) NULL }; static pool_t settings_pool = NULL; -static void fix_base_path(struct pop3_settings *set, const char **str) -{ - if (*str != NULL && **str != '\0' && **str != '/') { - *str = p_strconcat(settings_pool, - set->base_dir, "/", *str, NULL); - } -} - -/* */ -static bool pop3_settings_check(void *_set, pool_t pool ATTR_UNUSED, - const char **error_r) -{ - struct pop3_settings *set = _set; - -#ifndef CONFIG_BINARY - fix_base_path(set, &set->auth_socket_path); -#endif - - if (*set->mail_plugins != '\0' && - access(set->mail_plugin_dir, R_OK | X_OK) < 0) { - *error_r = t_strdup_printf( - "mail_plugin_dir: access(%s) failed: %m", - set->mail_plugin_dir); - return FALSE; - } - return TRUE; -} -/* */ - static void parse_expand_vars(struct setting_parser_context *parser, const char *value) { @@ -142,7 +99,8 @@ void pop3_settings_read(const struct pop3_settings **set_r, else p_clear(settings_pool); - mail_storage_namespace_defines_init(settings_pool); + settings_parser_info_update(settings_pool, + mail_storage_get_dynamic_parsers()); parser = settings_parser_init_list(settings_pool, roots, N_ELEMENTS(roots), diff --git a/src/pop3/pop3-settings.h b/src/pop3/pop3-settings.h index 12df00cc1a..30bb7b62df 100644 --- a/src/pop3/pop3-settings.h +++ b/src/pop3/pop3-settings.h @@ -4,16 +4,10 @@ struct mail_user_settings; struct pop3_settings { - const char *base_dir; - const char *auth_socket_path; - bool mail_debug; bool shutdown_clients; bool verbose_proctitle; - const char *mail_plugins; - const char *mail_plugin_dir; - /* pop3: */ bool pop3_no_flag_updates; bool pop3_enable_last; diff --git a/src/util/Makefile.am b/src/util/Makefile.am index d4d7b14183..968626a925 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -10,14 +10,17 @@ pkglibexec_PROGRAMS = \ maildirlock \ threadview -sbin_PROGRAMS = dovecotpw +sbin_PROGRAMS = dovecotpw doveadm AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-auth \ + -I$(top_srcdir)/src/lib-dict \ + -I$(top_srcdir)/src/lib-master \ -I$(top_srcdir)/src/lib-mail \ -I$(top_srcdir)/src/lib-imap \ -I$(top_srcdir)/src/lib-index \ - -I$(top_srcdir)/src/lib-storage/index/maildir \ + -I$(top_srcdir)/src/lib-storage \ -I$(top_srcdir)/src/auth rawlog_LDADD = \ @@ -70,3 +73,10 @@ dovecotpw_LDADD = \ dovecotpw_SOURCES = \ dovecotpw.c + +doveadm_LDADD = \ + ../lib-dovecot/libdovecot.la \ + ../lib-storage/libdovecot-storage.la +doveadm_SOURCES = \ + doveadm.c +