/******************************************************************************/
/* 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;
}
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);
+uschar *msg;
+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;
}
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;
}
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;
}
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
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
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),
{ "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} },