summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/src/EDITME7
-rw-r--r--src/src/config.h.defaults2
-rw-r--r--src/src/functions.h54
-rw-r--r--src/src/globals.c10
-rw-r--r--src/src/globals.h4
-rw-r--r--src/src/macros.h3
-rw-r--r--src/src/readconf.c3
7 files changed, 71 insertions, 12 deletions
diff --git a/src/src/EDITME b/src/src/EDITME
index 8cd34e8be..f4329fabf 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -748,6 +748,13 @@ FIXED_NEVER_USERS=root
# WHITELIST_D_MACROS=TLS:SPOOL
+# The next setting enables a main config option
+# "allow_insecure_tainted_data" to turn taint failures into warnings.
+# Though this option is new, it is deprecated already now, and will be
+# ignored in future releases of Exim. It is meant as mitigation for
+# upgrading old (possibly insecure) configurations to more secure ones.
+ALLOW_INSECURE_TAINTED_DATA=yes
+
#------------------------------------------------------------------------------
# Exim has support for the AUTH (authentication) extension of the SMTP
# protocol, as defined by RFC 2554. If you don't know what SMTP authentication
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index e233fb3e5..877cc7bc4 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -17,6 +17,8 @@ Do not put spaces between # and the 'define'.
#define ALT_CONFIG_PREFIX
#define TRUSTED_CONFIG_LIST
+#define ALLOW_INSECURE_TAINTED_DATA
+
#define APPENDFILE_MODE 0600
#define APPENDFILE_DIRECTORY_MODE 0700
#define APPENDFILE_LOCKFILE_MODE 0600
diff --git a/src/src/functions.h b/src/src/functions.h
index 4212c3328..27c298cfa 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -1125,20 +1125,50 @@ if (f.running_in_test_harness && f.testsuite_delays) millisleep(millisec);
/******************************************************************************/
/* Taint-checked file opens */
+static inline uschar *
+is_tainted2(const void *p, int lflags, const uschar* fmt, ...)
+{
+va_list ap;
+uschar *msg;
+rmark mark;
+
+if (!is_tainted(p))
+ return NULL;
+
+mark = store_mark();
+va_start(ap, fmt);
+msg = string_from_gstring(string_vformat(NULL, SVFMT_TAINT_NOCHK|SVFMT_EXTEND, fmt, ap));
+va_end(ap);
+
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+if (allow_insecure_tainted_data)
+ {
+ if LOGGING(tainted) log_write(0, LOG_MAIN, "Warning: %s", msg);
+ store_reset(mark);
+ return NULL;
+ }
+#endif
+
+if (lflags) log_write(0, lflags, "%s", msg);
+return msg; /* no store_reset(), as the message might be used afterwards and Exim
+ is expected to exit anyway, so we do not care about the leaked
+ storage */
+}
static inline int
exim_open2(const char *pathname, int flags)
{
-if (!is_tainted(pathname)) return open(pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return open(pathname, flags);
errno = EACCES;
return -1;
}
+
static inline int
exim_open(const char *pathname, int flags, mode_t mode)
{
-if (!is_tainted(pathname)) return open(pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return open(pathname, flags, mode);
errno = EACCES;
return -1;
}
@@ -1146,16 +1176,16 @@ return -1;
static inline int
exim_openat(int dirfd, const char *pathname, int flags)
{
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return openat(dirfd, pathname, flags);
errno = EACCES;
return -1;
}
static inline int
exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode)
{
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return openat(dirfd, pathname, flags, mode);
errno = EACCES;
return -1;
}
@@ -1164,8 +1194,8 @@ return -1;
static inline FILE *
exim_fopen(const char *pathname, const char *mode)
{
-if (!is_tainted(pathname)) return fopen(pathname, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return fopen(pathname, mode);
errno = EACCES;
return NULL;
}
@@ -1173,8 +1203,8 @@ return NULL;
static inline DIR *
exim_opendir(const uschar * name)
{
-if (!is_tainted(name)) return opendir(CCS name);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name);
+if (!is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name))
+ return opendir(CCS name);
errno = EACCES;
return NULL;
}
diff --git a/src/src/globals.c b/src/src/globals.c
index e96586048..9e68aaca8 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -98,6 +98,10 @@ int sqlite_lock_timeout = 5;
BOOL move_frozen_messages = FALSE;
#endif
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+BOOL allow_insecure_tainted_data = FALSE;
+#endif
+
/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. Note that these are
@@ -1055,6 +1059,9 @@ int log_default[] = { /* for initializing log_selector */
Li_size_reject,
Li_skip_delivery,
Li_smtp_confirmation,
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ Li_tainted,
+#endif
Li_tls_certificate_verified,
Li_tls_cipher,
-1
@@ -1124,6 +1131,9 @@ bit_table log_options[] = { /* must be in alphabetical order,
BIT_TABLE(L, smtp_protocol_error),
BIT_TABLE(L, smtp_syntax_error),
BIT_TABLE(L, subject),
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ BIT_TABLE(L, tainted),
+#endif
BIT_TABLE(L, tls_certificate_verified),
BIT_TABLE(L, tls_cipher),
BIT_TABLE(L, tls_peerdn),
diff --git a/src/src/globals.h b/src/src/globals.h
index 937cce776..657e6c706 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -77,6 +77,10 @@ extern int sqlite_lock_timeout; /* Internal lock waiting timeout */
extern BOOL move_frozen_messages; /* Get them out of the normal directory */
#endif
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+extern BOOL allow_insecure_tainted_data;
+#endif
+
/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. */
diff --git a/src/src/macros.h b/src/src/macros.h
index f8987d604..ccdcc451f 100644
--- a/src/src/macros.h
+++ b/src/src/macros.h
@@ -491,6 +491,9 @@ enum logbit {
Li_smtp_mailauth,
Li_smtp_no_mail,
Li_subject,
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ Li_tainted,
+#endif
Li_tls_certificate_verified,
Li_tls_cipher,
Li_tls_peerdn,
diff --git a/src/src/readconf.c b/src/src/readconf.c
index ae36fa0c5..34ebf8769 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -68,6 +68,9 @@ static optionlist optionlist_config[] = {
{ "add_environment", opt_stringptr, {&add_environment} },
{ "admin_groups", opt_gidlist, {&admin_groups} },
{ "allow_domain_literals", opt_bool, {&allow_domain_literals} },
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ { "allow_insecure_tainted_data", opt_bool, {&allow_insecure_tainted_data} },
+#endif
{ "allow_mx_to_ip", opt_bool, {&allow_mx_to_ip} },
{ "allow_utf8_domains", opt_bool, {&allow_utf8_domains} },
{ "auth_advertise_hosts", opt_stringptr, {&auth_advertise_hosts} },