summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/OS/Makefile-Base2
-rwxr-xr-xsrc/scripts/MakeLinks2
-rw-r--r--src/src/environment.c54
-rw-r--r--src/src/exim.c20
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/globals.c3
-rw-r--r--src/src/globals.h2
-rw-r--r--src/src/readconf.c36
-rw-r--r--src/src/setenv.c3
-rw-r--r--src/src/string.c11
-rw-r--r--src/src/tls-openssl.c2
11 files changed, 131 insertions, 6 deletions
diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
index 9bc819dd7..e0bdeecfd 100644
--- a/src/OS/Makefile-Base
+++ b/src/OS/Makefile-Base
@@ -335,6 +335,7 @@ OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \
+ environment.o \
$(OBJ_LOOKUPS) \
local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
$(OBJ_WITH_OLD_DEMIME) $(OBJ_EXPERIMENTAL)
@@ -592,6 +593,7 @@ dns.o: $(HDRS) dns.c
enq.o: $(HDRS) enq.c
exim.o: $(HDRS) exim.c
expand.o: $(HDRS) expand.c
+environment.o: $(HDRS) environment.c
filter.o: $(HDRS) filter.c
filtertest.o: $(HDRS) filtertest.c
globals.o: $(HDRS) globals.c
diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks
index 886214030..9420b11c6 100755
--- a/src/scripts/MakeLinks
+++ b/src/scripts/MakeLinks
@@ -101,7 +101,7 @@ for f in dbfunctions.h dbstuff.h exim.h functions.h globals.h local_scan.h \
exim_dbutil.c exim_lock.c expand.c filter.c filtertest.c globals.c \
header.c host.c ip.c log.c lss.c match.c moan.c parse.c perl.c queue.c \
rda.c readconf.c receive.c retry.c rewrite.c rfc2047.c route.c search.c \
- setenv.c \
+ setenv.c environment.c \
sieve.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c store.c \
string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-gnu.c tls-openssl.c \
tod.c transport.c tree.c verify.c version.c dkim.c dkim.h dmarc.c dmarc.h \
diff --git a/src/src/environment.c b/src/src/environment.c
new file mode 100644
index 000000000..aaa84f817
--- /dev/null
+++ b/src/src/environment.c
@@ -0,0 +1,54 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Heiko Schlittermann 2016
+ * hs@schlittermann.de
+ * See the file NOTICE for conditions of use and distribution.
+ */
+
+#include "exim.h"
+
+/* The cleanup_environment() function is used during the startup phase
+of the Exim process, right after reading the configurations main
+part, before any expansions take place. It retains the environment
+variables we trust (via the keep_environment option) and allows to
+set additional variables (via add_environment).
+
+Returns: TRUE if successful
+ FALSE otherwise
+*/
+
+BOOL
+cleanup_environment()
+{
+if (!keep_environment || *keep_environment == '\0')
+ clearenv();
+else if (Ustrcmp(keep_environment, "*") != 0)
+ {
+ uschar **p;
+ if (environ) for (p = USS environ; *p; /* see below */)
+ {
+ uschar *name = string_copyn(*p, US Ustrchr(*p, '=') - *p);
+
+ if (OK != match_isinlist(name, CUSS &keep_environment,
+ 0, NULL, NULL, MCL_NOEXPAND, FALSE, NULL))
+ if (unsetenv(CS name) < 0) return FALSE;
+ else /* nothing */;
+ else
+ p++;
+
+ store_reset(name);
+ }
+ }
+if (add_environment)
+ {
+ uschar *p;
+ int sep = 0;
+ const uschar* envlist = add_environment;
+ while ((p = string_nextinlist(&envlist, &sep, NULL, 0)))
+ putenv(CS p);
+ }
+
+ return TRUE;
+}
diff --git a/src/src/exim.c b/src/src/exim.c
index 02f2a9a4d..d6f2d4aac 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -3743,8 +3743,19 @@ if (running_in_test_harness) smtputf8_advertise_hosts = NULL;
is a failure. It leaves the configuration file open so that the subsequent
configuration data for delivery can be read if needed. */
+/* To be safe: change the working directory to /. */
+if (Uchdir("/") < 0)
+ {
+ perror("exim: chdir `/': ");
+ exit(EXIT_FAILURE);
+ }
+
readconf_main();
+if (cleanup_environment() == FALSE)
+ log_write(0, LOG_PANIC_DIE, "Can't cleanup environment");
+
+
/* If an action on specific messages is requested, or if a daemon or queue
runner is being started, we need to know if Exim was called by an admin user.
This is the case if the real user is root or exim, or if the real group is
@@ -3907,7 +3918,7 @@ EXIM_TMPDIR by the build scripts.
#ifdef EXIM_TMPDIR
{
uschar **p;
- for (p = USS environ; *p != NULL; p++)
+ if (environ) for (p = USS environ; *p != NULL; p++)
{
if (Ustrncmp(*p, "TMPDIR=", 7) == 0 &&
Ustrcmp(*p+7, EXIM_TMPDIR) != 0)
@@ -3947,10 +3958,10 @@ else
uschar **new;
uschar **newp;
int count = 0;
- while (*p++ != NULL) count++;
+ if (environ) while (*p++ != NULL) count++;
if (envtz == NULL) count++;
newp = new = malloc(sizeof(uschar *) * (count + 1));
- for (p = USS environ; *p != NULL; p++)
+ if (environ) for (p = USS environ; *p != NULL; p++)
{
if (Ustrncmp(*p, "TZ=", 3) == 0) continue;
*newp++ = *p;
@@ -4540,7 +4551,8 @@ if (list_options)
(Ustrcmp(argv[i], "router") == 0 ||
Ustrcmp(argv[i], "transport") == 0 ||
Ustrcmp(argv[i], "authenticator") == 0 ||
- Ustrcmp(argv[i], "macro") == 0))
+ Ustrcmp(argv[i], "macro") == 0 ||
+ Ustrcmp(argv[i], "environment") == 0))
{
readconf_print(argv[i+1], argv[i], flag_n);
i++;
diff --git a/src/src/functions.h b/src/src/functions.h
index 97d95dd3d..a4c791f10 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -108,6 +108,7 @@ extern int check_host(void *, const uschar *, const uschar **, uschar **);
extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
extern pid_t child_open_uid(const uschar **, const uschar **, int,
uid_t *, gid_t *, int *, int *, uschar *, BOOL);
+extern BOOL cleanup_environment(void);
extern uschar *cutthrough_finaldot(void);
extern BOOL cutthrough_flush_send(void);
extern BOOL cutthrough_headers_send(void);
@@ -418,6 +419,7 @@ extern uschar *string_append_listele(uschar *, uschar, const uschar *);
extern uschar *string_append_listele_n(uschar *, uschar, const uschar *, unsigned);
extern uschar *string_base62(unsigned long int);
extern uschar *string_cat(uschar *, int *, int *, const uschar *, int);
+extern int string_compare_by_pointer(const uschar **, const uschar **);
extern uschar *string_copy_dnsdomain(uschar *);
extern uschar *string_copy_malloc(const uschar *);
extern uschar *string_copylc(const uschar *);
diff --git a/src/src/globals.c b/src/src/globals.c
index 69f217642..e5bbb8340 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -321,6 +321,7 @@ uschar *acl_wherecodes[] = { US"550", /* RCPT */
BOOL active_local_from_check = FALSE;
BOOL active_local_sender_retain = FALSE;
BOOL accept_8bitmime = TRUE; /* deliberately not RFC compliant */
+uschar *add_environment = NULL;
address_item *addr_duplicate = NULL;
address_item address_defaults = {
@@ -803,6 +804,8 @@ uschar *iterate_item = NULL;
int journal_fd = -1;
+uschar *keep_environment = NULL;
+
int keep_malformed = 4*24*60*60; /* 4 days */
uschar *eldap_dn = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index 787de41f0..1919d8c1f 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -156,6 +156,7 @@ extern const uschar **address_expansions[ADDRESS_EXPANSIONS_COUNT];
/* General global variables */
extern BOOL accept_8bitmime; /* Allow *BITMIME incoming */
+extern uschar *add_environment; /* List of environment variables to add */
extern header_line *acl_added_headers; /* Headers added by an ACL */
extern tree_node *acl_anchor; /* Tree of named ACLs */
extern uschar *acl_arg[9]; /* Argument to ACL call */
@@ -516,6 +517,7 @@ extern uschar *iterate_item; /* Item from iterate list */
extern int journal_fd; /* Fd for journal file */
+extern uschar *keep_environment; /* Whitelist for environment variables */
extern int keep_malformed; /* Time to keep malformed messages */
extern uschar *eldap_dn; /* Where LDAP DNs are left */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 9de064d95..cf5f069e9 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -178,6 +178,7 @@ static optionlist optionlist_config[] = {
{ "acl_smtp_starttls", opt_stringptr, &acl_smtp_starttls },
#endif
{ "acl_smtp_vrfy", opt_stringptr, &acl_smtp_vrfy },
+ { "add_environment", opt_stringptr, &add_environment },
{ "admin_groups", opt_gidlist, &admin_groups },
{ "allow_domain_literals", opt_bool, &allow_domain_literals },
{ "allow_mx_to_ip", opt_bool, &allow_mx_to_ip },
@@ -296,6 +297,7 @@ static optionlist optionlist_config[] = {
{ "ignore_bounce_errors_after", opt_time, &ignore_bounce_errors_after },
{ "ignore_fromline_hosts", opt_stringptr, &ignore_fromline_hosts },
{ "ignore_fromline_local", opt_bool, &ignore_fromline_local },
+ { "keep_environment", opt_stringptr, &keep_environment },
{ "keep_malformed", opt_time, &keep_malformed },
#ifdef LOOKUP_LDAP
{ "ldap_ca_cert_dir", opt_stringptr, &eldap_ca_cert_dir },
@@ -2549,6 +2551,7 @@ second argument is NULL. There are some special values:
+name print a named list item
local_scan print the local_scan options
config print the configuration as it is parsed
+ environment print the used execution environment
If the second argument is not NULL, it must be one of "router", "transport",
"authenticator" or "macro" in which case the first argument identifies the
@@ -2697,6 +2700,25 @@ if (type == NULL)
names_only = TRUE;
}
+ else if (Ustrcmp(name, "environment") == 0)
+ {
+ if (environ)
+ {
+ uschar **p;
+ size_t n;
+ for (p = USS environ; *p; p++) ;
+ n = p - USS environ;
+ qsort(environ, p - USS environ, sizeof(*p), (__compar_fn_t) string_compare_by_pointer);
+
+ for (p = USS environ; *p; p++)
+ {
+ if (no_labels) *(Ustrchr(*p, '=')) = '\0';
+ puts(*p);
+ }
+ }
+ return;
+ }
+
else
{
print_ol(find_option(name, optionlist_config, optionlist_config_size),
@@ -3022,6 +3044,15 @@ const uschar *list = config_main_filelist;
while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
!= NULL)
{
+
+ /* To avoid confusion: Exim changes to / at the very beginning and
+ * and to $spool_directory later. */
+ if (filename[0] != '/')
+ {
+ fprintf(stderr, "-C %s: only absolute names are allowed\n", filename);
+ exit(EXIT_FAILURE);
+ }
+
/* Cut out all the fancy processing unless specifically wanted */
#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
@@ -3467,6 +3498,11 @@ if (gnutls_require_kx || gnutls_require_mac || gnutls_require_proto)
" gnutls_require_kx, gnutls_require_mac and gnutls_require_protocols"
" are obsolete\n");
#endif /*SUPPORT_TLS*/
+
+if ((!add_environment || *add_environment == '\0') && !keep_environment)
+ log_write(0, LOG_MAIN,
+ "WARNING: purging the environment.\n"
+ " Suggested action: use keep_environment and add_environment.\n");
}
diff --git a/src/src/setenv.c b/src/src/setenv.c
index 6da56d58d..eefbec09b 100644
--- a/src/src/setenv.c
+++ b/src/src/setenv.c
@@ -34,6 +34,9 @@ if (!name)
return -1;
}
+if (!environ)
+ return 0;
+
for (end = name; *end != '=' && *end; ) end++;
len = end - name;
diff --git a/src/src/string.c b/src/src/string.c
index c0dfd04b6..1c4ba121c 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -1707,6 +1707,17 @@ return yield;
#endif /* COMPILE_UTILITY */
+#ifndef COMPILE_UTILITY
+/* qsort(3), currently used to sort the environment variables
+for -bP environment output, needs a function to compare two pointers to string
+pointers. Here it is. */
+
+int
+string_compare_by_pointer(const uschar **a, const uschar **b)
+{
+return Ustrcmp(CUS *a, CUS *b);
+}
+#endif /* COMPILE_UTILITY */
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
index 4f02d078f..83594c973 100644
--- a/src/src/tls-openssl.c
+++ b/src/src/tls-openssl.c
@@ -897,7 +897,7 @@ bad:
{
extern char ** environ;
uschar ** p;
- for (p = USS environ; *p != NULL; p++)
+ if (environ) for (p = USS environ; *p != NULL; p++)
if (Ustrncmp(*p, "EXIM_TESTHARNESS_DISABLE_OCSPVALIDITYCHECK", 42) == 0)
{
DEBUG(D_tls) debug_printf("Supplying known bad OCSP response\n");