]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Added import_environment setting.
authorTimo Sirainen <tss@iki.fi>
Wed, 9 Feb 2011 23:54:26 +0000 (01:54 +0200)
committerTimo Sirainen <tss@iki.fi>
Wed, 9 Feb 2011 23:54:26 +0000 (01:54 +0200)
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.

14 files changed:
src/doveadm/doveadm.c
src/lib-lda/smtp-client.c
src/lib-master/master-interface.h
src/lib-master/master-service-settings.c
src/lib-master/master-service-settings.h
src/lib-master/master-service.c
src/lib-master/master-service.h
src/lib-storage/mail-storage-service.c
src/master/main.c
src/master/master-settings.c
src/master/master-settings.h
src/master/service-process.c
src/master/service.c
src/master/service.h

index 282d92124a6644b6034447c2336931474e7ec56f..a9b2422b56c07bff5f8fe47c6e03e32b6ebd9e54 100644 (file)
@@ -234,6 +234,7 @@ static void doveadm_read_settings(void)
        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)
index 539aa9dcfe1c0fbab77e4bd7c21f8a07207d673f..05ab0c925f350792e0e0499d995432f8d95e8c68 100644 (file)
@@ -51,7 +51,7 @@ smtp_client_run_sendmail(const struct lda_settings *set,
        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);
 }
index 2a6a79f62ecf9c792679e4220a103182fdd7707c..182d8694889634cc8b34bb3455432d5d664b2fea 100644 (file)
@@ -59,6 +59,10 @@ enum master_login_state {
    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 */
index 18ada0b2d4d6236375f6c9f98608d7cfce471798..ae9a04685e9549f0f60cb968db00a83ef3d2bfa3 100644 (file)
@@ -90,12 +90,22 @@ master_service_exec_config(struct master_service *service,
                           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");
 
index 6f349dd3adc686a45604dec3317a0234c5a8cb20..1f414eca2749054dd67f95bffc3b90cb59554653 100644 (file)
@@ -21,6 +21,8 @@ struct master_service_settings {
 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;
index 250f479171df0db24242b6700f5ba980ff765ec9..185c3fc02b86f723dfbde1e8e8beee5f897bbfd2 100644 (file)
@@ -391,22 +391,16 @@ void master_service_init_finish(struct master_service *service)
        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,
index 95346b6a81cfd5c6c001bb8f78b758560bbe52f0..1338a668608dd254268d8ffda23c0119de4474f3 100644 (file)
@@ -59,8 +59,9 @@ bool master_service_parse_option(struct master_service *service,
    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,
index cfccef26cf8efdad59c9d4c14cd6dd729792d955..adb05253c22f928eed2c2bcdbb9a1e988c64bcc7 100644 (file)
@@ -652,6 +652,7 @@ int mail_storage_service_read_settings(struct mail_storage_service_ctx *ctx,
 
        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 */
index 59bbec73a1e074663f3a33589e2044c570959902..add90d488dcfea5c6d2c9532187cc44fdf0f61d7 100644 (file)
@@ -48,7 +48,6 @@ struct service_list *services;
 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 @@ sig_settings_reload(const siginfo_t *si ATTR_UNUSED,
        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 @@ static struct master_settings *master_settings_read(void)
        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 @@ static void print_build_options(void)
 
 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 @@ int main(int argc, char *argv[])
 #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 @@ int main(int argc, char *argv[])
        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);
index 7fe247817ba8387626eca0f2bc9fae7560e9f4fb..d58f18d2f62ac9678fa93e469bb1f409ece0a0ad 100644 (file)
@@ -170,6 +170,7 @@ const struct setting_parser_info service_setting_parser_info = {
 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 @@ static const struct setting_define master_setting_defines[] = {
        SETTING_DEFINE_LIST_END
 };
 
+/* <settings checks> */
+#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
+/* </settings checks> */
+
 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",
index c62f3b33d1586205fdf59a33364df54f762c794b..3c7cfccc2ccce8a06fb3322a0b985451004e11fd 100644 (file)
@@ -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;
index 38d7f18e7029fec9c3f089ab628f2af1fff0058a..1fd8efa9028be58f6afee557ee1a28291df5fcd8 100644 (file)
@@ -180,12 +180,8 @@ static void
 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:
index b3bef00c045eb1bed5ed2297b04e7374f55309cb..323909a18876f08661c04ca54e925263a80470b5 100644 (file)
@@ -427,7 +427,6 @@ static bool service_want(struct service_settings *set)
 }
 
 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 @@ int services_create(const struct master_settings *set,
        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;
 
index 4d53fd7142c19f229653625d34c05b27b7448683..245e026fff487193b6a1c2d7caaacfc6bdb1001a 100644 (file)
@@ -114,7 +114,6 @@ struct service_list {
        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 @@ extern struct hash_table *service_pids;
 
 /* 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 */