diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2010-12-12 02:41:37 +0000 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-12-12 02:52:02 +0000 |
commit | 261dc43e32f6039781ca92535e56f5caaa68b809 (patch) | |
tree | 0f03b0846dff44db79a6e7efcb7e940a53e2672a /src | |
parent | cd25e41d2d044556e024f0292a17c5ec3cc7987b (diff) |
Add TRUSTED_CONFIG_PREFIX_FILE option
(Bug 1044, CVE-2010-4345)
Diffstat (limited to 'src')
-rw-r--r-- | src/src/EDITME | 13 | ||||
-rw-r--r-- | src/src/config.h.defaults | 1 | ||||
-rw-r--r-- | src/src/exim.c | 101 |
3 files changed, 111 insertions, 4 deletions
diff --git a/src/src/EDITME b/src/src/EDITME index f8ba7cfe3..1ae139944 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -473,6 +473,19 @@ FIXED_NEVER_USERS=root #------------------------------------------------------------------------------ +# When a user other than root uses the -C option to override the configuration +# file (including the Exim user when re-executing Exim to regain root +# privileges for local message delivery), this will normally cause Exim to +# drop root privileges. The TRUSTED_CONFIG_PREFIX_LIST option, specifies +# a file which contains a list of trusted configuration prefixes (like the +# ALT_CONFIG_PREFIX above), one per line. If the -C option is used to specify +# a configuration file which matches a trusted prefix, root privileges are not +# dropped by Exim. + +# TRUSTED_CONFIG_PREFIX_LIST=/usr/exim/trusted_configs + + +#------------------------------------------------------------------------------ # Uncommenting this option disables the use of the -D command line option, # which changes the values of macros in the runtime configuration file. # This is another protection against somebody breaking into the Exim account. diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 9e4556e8c..d3d7d65bb 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -13,6 +13,7 @@ in config.h unless some value is defined in Local/Makefile. If there is data, it's a default value. */ #define ALT_CONFIG_PREFIX +#define TRUSTED_CONFIG_PREFIX_LIST #define APPENDFILE_MODE 0600 #define APPENDFILE_DIRECTORY_MODE 0700 diff --git a/src/src/exim.c b/src/src/exim.c index 0d9378d46..9db61e2a9 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1845,10 +1845,103 @@ for (i = 1; i < argc; i++) } } #endif + if (real_uid != root_uid) + { + #ifdef TRUSTED_CONFIG_PREFIX_LIST + + if (Ustrstr(argrest, "/../")) + trusted_config = FALSE; + else + { + FILE *trust_list = Ufopen(TRUSTED_CONFIG_PREFIX_LIST, "rb"); + if (trust_list) + { + struct stat statbuf; + + if (fstat(fileno(trust_list), &statbuf) != 0 || + (statbuf.st_uid != root_uid /* owner not root */ + #ifdef CONFIGURE_OWNER + && statbuf.st_uid != config_uid /* owner not the special one */ + #endif + ) || /* or */ + (statbuf.st_gid != root_gid /* group not root */ + #ifdef CONFIGURE_GROUP + && statbuf.st_gid != config_gid /* group not the special one */ + #endif + && (statbuf.st_mode & 020) != 0 /* group writeable */ + ) || /* or */ + (statbuf.st_mode & 2) != 0) /* world writeable */ + { + trusted_config = FALSE; + fclose(trust_list); + } + else + { + /* Well, the trust list at least is up to scratch... */ + void *reset_point = store_get(0); + uschar *trusted_prefixes[32]; + int nr_prefixes = 0; + int i = 0; + + while (Ufgets(big_buffer, big_buffer_size, trust_list)) + { + uschar *start = big_buffer, *nl; + while (*start && isspace(*start)) + start++; + if (*start == '#') + continue; + nl = Ustrchr(start, '\n'); + if (nl) + *nl = 0; + trusted_prefixes[nr_prefixes++] = string_copy(start); + if (nr_prefixes == 32) + break; + } + fclose(trust_list); + + if (nr_prefixes) + { + int sep = 0; + uschar *list = argrest; + uschar *filename; + while (trusted_config && (filename = string_nextinlist(&list, + &sep, big_buffer, big_buffer_size)) != NULL) + { + for (i=0; i < nr_prefixes; i++) + { + int len = Ustrlen(trusted_prefixes[i]); + if (Ustrlen(filename) >= len && + Ustrncmp(filename, trusted_prefixes[i], len) == 0) + break; + } + if (i == nr_prefixes) + { + trusted_config = FALSE; + break; + } + } + } + else + { + /* No valid prefixes found in trust_list file. */ + trusted_config = FALSE; + } + } + } + else + { + /* Could not open trust_list file. */ + trusted_config = FALSE; + } + } + #else + /* Not root; don't trust config */ + trusted_config = FALSE; + #endif + } config_main_filelist = argrest; config_changed = TRUE; - trusted_config = FALSE; } break; @@ -3241,7 +3334,7 @@ else There is a problem if we were running as the Exim user. The sysadmin may expect this case to retain privilege because "the binary was called by the Exim user", but it hasn't, because either the -D option set macros, or the --C option set a non-default configuration file. There are two possibilities: +-C option set a non-trusted configuration file. There are two possibilities: (1) If deliver_drop_privilege is set, Exim is not going to re-exec in order to do message deliveries. Thus, the fact that it is running as a @@ -3253,8 +3346,8 @@ Exim user", but it hasn't, because either the -D option set macros, or the (2) If deliver_drop_privilege is not set, the configuration won't work as apparently intended, and so we log a panic message. In order to retain - root for -C or -D, the caller must be root (when deliver_drop_privilege - is false). */ + root for -C or -D, the caller must either be root or be invoking a + trusted configuration file (when deliver_drop_privilege is false). */ if (removed_privilege && (!trusted_config || macros != NULL) && real_uid == exim_uid) |