# HG changeset patch # User Timo Sirainen # Date 1297295666 -7200 # Node ID cec7fa92ff4886a058d4fe2830ee90e85e7bb59c # Parent 98f13cc1e6496bfbe5eb6f9dfa6e0eeb7855264e Added import_environment setting. This also cleans up different places in code where TZ and other environments are preserved. If it's not in the import_environment setting, it's not preserved. diff -r 98f13cc1e649 -r cec7fa92ff48 src/doveadm/doveadm.c --- a/src/doveadm/doveadm.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/doveadm/doveadm.c Thu Feb 10 01:54:26 2011 +0200 @@ -234,6 +234,7 @@ memset(&input, 0, sizeof(input)); input.roots = set_roots; input.module = "doveadm"; + input.preserve_user = TRUE; input.preserve_home = TRUE; if (master_service_settings_read(master_service, &input, &output, &error) < 0) diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-lda/smtp-client.c --- a/src/lib-lda/smtp-client.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-lda/smtp-client.c Thu Feb 10 01:54:26 2011 +0200 @@ -51,7 +51,7 @@ if (dup2(fd, STDIN_FILENO) < 0) i_fatal("dup2() failed: %m"); - master_service_env_clean(TRUE); + master_service_env_clean(); execv_const(sendmail_path, argv); } diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-master/master-interface.h --- a/src/lib-master/master-interface.h Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-master/master-interface.h Thu Feb 10 01:54:26 2011 +0200 @@ -59,6 +59,10 @@ if dovecot was started with -p parameter. */ #define MASTER_SSL_KEY_PASSWORD_ENV "SSL_KEY_PASSWORD" +/* getenv(DOVECOT_PRESERVE_ENVS_ENV) returns a space separated list of + environments that should be preserved. */ +#define DOVECOT_PRESERVE_ENVS_ENV "DOVECOT_PRESERVE_ENVS" + /* Write pipe to anvil. */ #define MASTER_ANVIL_FD 3 /* Anvil reads new log fds from this fd */ diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-master/master-service-settings.c --- a/src/lib-master/master-service-settings.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-master/master-service-settings.c Thu Feb 10 01:54:26 2011 +0200 @@ -90,12 +90,22 @@ const struct master_service_settings_input *input) { const char **conf_argv, *binary_path = service->argv[0]; + const char *home = NULL, *user = NULL; unsigned int i, argv_max_count; (void)t_binary_abspath(&binary_path); - if (!service->keep_environment) - master_service_env_clean(input->preserve_home); + if (!service->keep_environment && !input->preserve_environment) { + if (input->preserve_home) + home = getenv("HOME"); + if (input->preserve_user) + user = getenv("USER"); + master_service_env_clean(); + if (home != NULL) + env_put(t_strconcat("HOME=", home, NULL)); + if (user != NULL) + env_put(t_strconcat("USER=", user, NULL)); + } if (input->use_sysexits) env_put("USE_SYSEXITS=1"); diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-master/master-service-settings.h --- a/src/lib-master/master-service-settings.h Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-master/master-service-settings.h Thu Feb 10 01:54:26 2011 +0200 @@ -21,6 +21,8 @@ struct master_service_settings_input { const struct setting_parser_info *const *roots; const char *config_path; + bool preserve_environment; + bool preserve_user; bool preserve_home; bool never_exec; bool use_sysexits; diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-master/master-service.c --- a/src/lib-master/master-service.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-master/master-service.c Thu Feb 10 01:54:26 2011 +0200 @@ -391,22 +391,16 @@ master_status_update(service); } -void master_service_env_clean(bool preserve_home) +void master_service_env_clean(void) { - static const char *preserve_envs[] = { - "HOME", /* keep as the first element */ - "USER", - "TZ", -#ifdef DEBUG - "GDB", -#endif -#ifdef HAVE_SYSTEMD - "LISTEN_PID", - "LISTEN_FDS", -#endif - NULL - }; - env_clean_except(preserve_envs + (preserve_home ? 0 : 1)); + const char *value = getenv(DOVECOT_PRESERVE_ENVS_ENV); + + if (value == NULL || *value == '\0') + env_clean(); + else T_BEGIN { + value = t_strconcat(value, " "DOVECOT_PRESERVE_ENVS_ENV, NULL); + env_clean_except(t_strsplit_spaces(value, " ")); + } T_END; } void master_service_set_client_limit(struct master_service *service, diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-master/master-service.h --- a/src/lib-master/master-service.h Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-master/master-service.h Thu Feb 10 01:54:26 2011 +0200 @@ -59,8 +59,9 @@ before calling this. */ void master_service_init_finish(struct master_service *service); -/* Clean environment from everything except TZ, USER and optionally HOME. */ -void master_service_env_clean(bool preserve_home); +/* Clean environment from everything except the ones listed in + DOVECOT_PRESERVE_ENVS environment. */ +void master_service_env_clean(void); /* Initialize logging. */ void master_service_init_log(struct master_service *service, diff -r 98f13cc1e649 -r cec7fa92ff48 src/lib-storage/mail-storage-service.c --- a/src/lib-storage/mail-storage-service.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/lib-storage/mail-storage-service.c Thu Feb 10 01:54:26 2011 +0200 @@ -652,6 +652,7 @@ memset(&set_input, 0, sizeof(set_input)); set_input.roots = ctx->set_roots; + set_input.preserve_user = TRUE; /* settings reader may exec doveconf, which is going to clear environment, and if we're not doing a userdb lookup we want to use $HOME */ diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/main.c --- a/src/master/main.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/main.c Thu Feb 10 01:54:26 2011 +0200 @@ -48,7 +48,6 @@ static char *pidfile_path; static failure_callback_t *orig_fatal_callback; static failure_callback_t *orig_error_callback; -static const char *child_process_env[3]; /* @UNSAFE */ static const struct setting_parser_info *set_roots[] = { &master_setting_parser_info, @@ -314,8 +313,7 @@ sets = master_service_settings_get_others(master_service); set = sets[0]; - if (services_create(set, child_process_env, - &new_services, &error) < 0) { + if (services_create(set, &new_services, &error) < 0) { /* new configuration is invalid, keep the old */ i_error("Config reload failed: %s", error); return; @@ -377,12 +375,39 @@ input.roots = set_roots; input.module = "master"; input.parse_full_config = TRUE; + input.preserve_environment = TRUE; if (master_service_settings_read(master_service, &input, &output, &error) < 0) i_fatal("Error reading configuration: %s", error); return master_service_settings_get_others(master_service)[0]; } +static void master_set_import_environment(const struct master_settings *set) +{ + const char *const *envs, *key, *value; + ARRAY_TYPE(const_string) keys; + + if (*set->import_environment == '\0') + return; + + t_array_init(&keys, 8); + envs = t_strsplit_spaces(set->import_environment, " "); + for (; *envs != NULL; envs++) { + value = strchr(*envs, '='); + if (value == NULL) + key = *envs; + else { + key = t_strdup_until(*envs, value); + env_put(*envs); + } + array_append(&keys, &key, 1); + } + (void)array_append_space(&keys); + + value = t_strarray_join(array_idx(&keys, 0), " "); + env_put(t_strconcat(DOVECOT_PRESERVE_ENVS_ENV"=", value, NULL)); +} + static void main_log_startup(void) { #define STARTUP_STRING PACKAGE_NAME" v"DOVECOT_VERSION_FULL" starting up" @@ -598,18 +623,8 @@ int main(int argc, char *argv[]) { - static const char *preserve_envs[] = { - /* AIX depends on TZ to get the timezone correctly. */ - "TZ", -#ifdef HAVE_SYSTEMD - "LISTEN_PID", - "LISTEN_FDS", -#endif - NULL - }; struct master_settings *set; - unsigned int child_process_env_idx = 0; - const char *error, *env_tz, *doveconf_arg = NULL; + const char *error, *doveconf_arg = NULL; failure_callback_t *orig_info_callback, *orig_debug_callback; bool foreground = FALSE, ask_key_pass = FALSE; bool doubleopts[argc]; @@ -618,8 +633,6 @@ #ifdef DEBUG if (getenv("GDB") == NULL) fd_debug_verify_leaks(3, 1024); - else - child_process_env[child_process_env_idx++] = "GDB=1"; #endif /* drop -- prefix from all --args. ugly, but the only way that it works with standard getopt() in all OSes.. */ @@ -740,23 +753,16 @@ master_settings_do_fixes(set); fatal_log_check(set); - /* clean up the environment */ - env_clean_except(preserve_envs); - - env_tz = getenv("TZ"); - if (env_tz != NULL) { - child_process_env[child_process_env_idx++] = - t_strconcat("TZ=", env_tz, NULL); - } - i_assert(child_process_env_idx < - sizeof(child_process_env) / sizeof(child_process_env[0])); - child_process_env[child_process_env_idx] = NULL; + T_BEGIN { + master_set_import_environment(set); + } T_END; + master_service_env_clean(); /* create service structures from settings. if there are any errors in service configuration we'll catch it here. */ service_pids_init(); service_anvil_global_init(); - if (services_create(set, child_process_env, &services, &error) < 0) + if (services_create(set, &services, &error) < 0) i_fatal("%s", error); services->config->config_file_path = get_full_config_path(services); diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/master-settings.c --- a/src/master/master-settings.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/master-settings.c Thu Feb 10 01:54:26 2011 +0200 @@ -170,6 +170,7 @@ static const struct setting_define master_setting_defines[] = { DEF(SET_STR, base_dir), DEF(SET_STR, libexec_dir), + DEF(SET_STR, import_environment), DEF(SET_STR, protocols), DEF(SET_STR, listen), DEF(SET_ENUM, ssl), @@ -192,9 +193,23 @@ SETTING_DEFINE_LIST_END }; +/* */ +#ifdef HAVE_SYSTEMD +# define ENV_SYSTEMD " LISTEN_PID LISTEN_FDS" +#else +# define ENV_SYSTEMD "" +#endif +#ifdef DEBUG +# define ENV_GDB " GDB" +#else +# define ENV_GDB "" +#endif +/* */ + static const struct master_settings master_default_settings = { .base_dir = PKG_RUNDIR, .libexec_dir = PKG_LIBEXECDIR, + .import_environment = "TZ" ENV_SYSTEMD ENV_GDB, .protocols = "imap pop3 lmtp", .listen = "*, ::", .ssl = "yes:no:required", diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/master-settings.h --- a/src/master/master-settings.h Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/master-settings.h Thu Feb 10 01:54:26 2011 +0200 @@ -6,6 +6,7 @@ struct master_settings { const char *base_dir; const char *libexec_dir; + const char *import_environment; const char *protocols; const char *listen; const char *ssl; diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/service-process.c --- a/src/master/service-process.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/service-process.c Thu Feb 10 01:54:26 2011 +0200 @@ -180,12 +180,8 @@ service_process_setup_environment(struct service *service, unsigned int uid) { const struct master_service_settings *set = service->list->service_set; - const char *const *p; - /* remove all environment, and put back what we need */ - env_clean(); - for (p = service->list->child_process_env; *p != NULL; p++) - env_put(*p); + master_service_env_clean(); switch (service->type) { case SERVICE_TYPE_CONFIG: diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/service.c --- a/src/master/service.c Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/service.c Thu Feb 10 01:54:26 2011 +0200 @@ -427,7 +427,6 @@ } int services_create(const struct master_settings *set, - const char *const *child_process_env, struct service_list **services_r, const char **error_r) { struct service_list *service_list; @@ -445,7 +444,6 @@ service_list->service_set = master_service_settings_get(master_service); service_list->set_pool = master_service_settings_detach(master_service); service_list->set = set; - service_list->child_process_env = child_process_env; service_list->master_log_fd[0] = -1; service_list->master_log_fd[1] = -1; diff -r 98f13cc1e649 -r cec7fa92ff48 src/master/service.h --- a/src/master/service.h Thu Feb 10 00:45:51 2011 +0200 +++ b/src/master/service.h Thu Feb 10 01:54:26 2011 +0200 @@ -114,7 +114,6 @@ struct service *config; struct service *log; struct service *anvil; - const char *const *child_process_env; /* nonblocking log fds usd by master */ int master_log_fd[2]; @@ -131,7 +130,6 @@ /* Create all services from settings */ int services_create(const struct master_settings *set, - const char *const *child_process_env, struct service_list **services_r, const char **error_r); /* Destroy services */