mail/exim: update to 4.94.2 security release

* New upstream security release.
    + Release based on +fixes branch.
    + Fixes multiple security vulnerabilities reported by Qualys and adds
      related robustness improvements. (Special thanks to Heiko)
      CVE-2020-28023: Out-of-bounds read in smtp_setup_msg()
      CVE-2020-28007: Link attack in Exim's log directory
      CVE-2020-28016: Heap out-of-bounds write in parse_fix_phrase()
      CVE-2020-28012: Missing close-on-exec flag for privileged pipe
      CVE-2020-28024: Heap buffer underflow in smtp_ungetc()
      CVE-2020-28009: Integer overflow in get_stdinput()
      CVE-2020-28015, CVE-28021: New-line injection into spool header file
      CVE-2020-28026: Line truncation and injection in spool_read_header()
      CVE-2020-28022: Heap out-of-bounds read and write in extract_option()
      CVE-2020-28017: Integer overflow in receive_add_recipient()
      CVE-2020-28013: Heap buffer overflow in parse_fix_phrase()
      CVE-2020-28011: Heap buffer overflow in queue_run()
      CVE-2020-28010: Heap out-of-bounds write in main()
      CVE-2020-28018: Use-after-free in tls-openssl.c
      CVE-2020-28025: Heap out-of-bounds read in pdkim_finish_bodyhash()
      CVE-2020-28014, CVE-2021-27216: PID file handling
      CVE-2020-28008: Assorted attacks in Exim's spool directory
      CVE-2020-28019: Failure to reset function pointer after BDAT error
  * Incorporate debian patches to turn taint failures into warnings.
This commit is contained in:
Dima Panov 2021-05-05 01:57:17 +10:00
parent 0a60c9a8dc
commit 0a629bd710
65 changed files with 1674 additions and 3653 deletions

View file

@ -2,7 +2,7 @@
PORTNAME= exim
PORTVERSION?= ${EXIM_VERSION}
PORTREVISION?= 5
PORTREVISION?= 0
CATEGORIES= mail
MASTER_SITES= EXIM:exim
MASTER_SITE_SUBDIR= /exim4/:exim \
@ -65,6 +65,33 @@ SPF_LIB_DEPENDS= libspf2.so:mail/libspf2
SQLITE_LIB_DEPENDS= libicudata.so:devel/icu
SQLITE_USES= pkgconfig sqlite
TAINTWARN_PATCHES_PREFIX= ${FILESDIR}/debian/75
TAINTWARN_EXTRA_PATCHES= \
${TAINTWARN_PATCHES_PREFIX}_01-Introduce-main-config-option-allow_insecure_tainted_.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_02-search.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_03-dbstuff.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_04-acl.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_05-parse.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_06-rda.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_07-appendfile.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_08-autoreply.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_09-pipe.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_10-deliver.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_11-directory.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_12-expand.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_13-lf_sqlperform.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_14-rf_get_transport.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_15-deliver.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_16-smtp_out.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_17-smtp.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_18-update-doc.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_20-Set-mainlog_name-and-rejectlog_name-unconditionally.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_21-tidy-log.c.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_22-Silence-compiler.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_23-Do-not-close-the-main-_log-if-we-do-not-see-a-chance.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_24-Silence-the-compiler.patch:-p1 \
${TAINTWARN_PATCHES_PREFIX}_26-Disable-taintchecks-for-mkdir-this-isn-t-part-of-4.9.patch:-p1
.include <bsd.port.options.mk>
# OCSP is supported for openssl only
@ -104,7 +131,7 @@ EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.c
EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.conf
.endif
EXIM_VERSION= 4.94
EXIM_VERSION= 4.94.2
SA_EXIM_VERSION=4.2.1
EXIM_INSTALL_ARG+= "-no_chown" "-no_symlink"
EXTRA_PATCHES+= `${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`

View file

@ -1,5 +1,5 @@
TIMESTAMP = 1591032067
SHA256 (exim/exim-4.94.tar.bz2) = 73feeaa5ddb43363782db0c307b593aacb49542dd7e4b795a2880779595affe5
SIZE (exim/exim-4.94.tar.bz2) = 1997217
TIMESTAMP = 1620141511
SHA256 (exim/exim-4.94.2.tar.bz2) = 902e611486400608691dff31e1d8725eb9e23602399ad75670ec18878643bc4f
SIZE (exim/exim-4.94.2.tar.bz2) = 2007178
SHA256 (exim/sa-exim-4.2.1.tar.gz) = 24d4bf7b0fdddaea11f132981cebb6a86a4ab20ef54111a8ebd481b421c6e2c1
SIZE (exim/sa-exim-4.2.1.tar.gz) = 68933

View file

@ -0,0 +1,230 @@
From ec06d64532e4952fc36429f73e0222d26997ef7c Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 22:44:31 +0200
Subject: [PATCH 01/23] Introduce main config option
allow_insecure_tainted_data
This option is deprecated already now.
---
src/EDITME | 7 +++++
src/config.h.defaults | 2 ++
src/functions.h | 54 ++++++++++++++++++++++++++++++---------
src/globals.c | 10 ++++++++
src/globals.h | 4 +++
src/macros.h | 3 +++
src/readconf.c | 3 +++
7 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/src/EDITME b/src/EDITME
index 8da36a353..cebb8e2ec 100644
--- a/src/EDITME
+++ b/src/EDITME
@@ -749,6 +749,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/config.h.defaults b/src/config.h.defaults
index e17f015f9..4e8b18904 100644
--- a/src/config.h.defaults
+++ b/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/functions.h b/src/functions.h
index 51bb17a09..1e8083673 100644
--- a/src/functions.h
+++ b/src/functions.h
@@ -1083,36 +1083,66 @@ 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;
}
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;
}
@@ -1120,8 +1150,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;
}
@@ -1129,8 +1159,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/globals.c b/src/globals.c
index c34ac9ddd..ff660c352 100644
--- a/src/globals.c
+++ b/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
@@ -1033,6 +1037,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
@@ -1100,6 +1107,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/globals.h b/src/globals.h
index a4c1143b7..8d72577e0 100644
--- a/src/globals.h
+++ b/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/macros.h b/src/macros.h
index f78ae2e3d..322ddbf56 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -498,6 +498,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/readconf.c b/src/readconf.c
index 948fa2403..133135f8f 100644
--- a/src/readconf.c
+++ b/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} },
--
2.30.2

View file

@ -0,0 +1,39 @@
From b71d675f695c2cf17357b190476129535d5f446c Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 22:45:03 +0200
Subject: [PATCH 02/23] search
---
src/search.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/search.c b/src/search.c
index f8aaacb04..f6e4d1f5b 100644
--- a/src/search.c
+++ b/src/search.c
@@ -343,12 +343,8 @@ lookup_info *lk = lookup_list[search_type];
uschar keybuffer[256];
int old_pool = store_pool;
-if (filename && is_tainted(filename))
- {
- log_write(0, LOG_MAIN|LOG_PANIC,
- "Tainted filename for search: '%s'", filename);
+if (filename && is_tainted2(filename, LOG_MAIN|LOG_PANIC, "Tainted filename for search '%s'", filename))
return NULL;
- }
/* Change to the search store pool and remember our reset point */
@@ -639,7 +635,7 @@ DEBUG(D_lookup)
/* Arrange to put this database at the top of the LRU chain if it is a type
that opens real files. */
-if ( open_top != (tree_node *)handle
+if ( open_top != (tree_node *)handle
&& lookup_list[t->name[0]-'0']->type == lookup_absfile)
{
search_cache *c = (search_cache *)(t->data.ptr);
--
2.30.2

View file

@ -0,0 +1,30 @@
From 35b11dd0e52b5ac176849f807cca8898bcaf0c3d Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 10:49:49 +0200
Subject: [PATCH 03/23] dbstuff
---
src/dbstuff.h | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/dbstuff.h b/src/dbstuff.h
index c1fb54346..dcee78696 100644
--- a/src/dbstuff.h
+++ b/src/dbstuff.h
@@ -643,11 +643,9 @@ after reading data. */
: (flags) == O_RDWR ? "O_RDWR" \
: (flags) == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT" \
: "??"); \
- if (is_tainted(name) || is_tainted(dirname)) \
- { \
- log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); \
+ if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB file not permitted", name) \
+ || is_tainted2(dirname, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB directory not permitted", dirname)) \
*dbpp = NULL; \
- } \
else \
{ EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); } \
DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", *dbpp); \
--
2.30.2

View file

@ -0,0 +1,67 @@
From 44fd80ad8abcd885fc1c8dbb294fc2140e4ef481 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 10:50:14 +0200
Subject: [PATCH 04/23] acl
Last-Update: 2021-05-01
---
src/acl.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)
--- a/src/acl.c
+++ b/src/acl.c
@@ -3596,24 +3596,26 @@
rc = mime_regex(&arg);
break;
#endif
case ACLC_QUEUE:
- if (is_tainted(arg))
{
- *log_msgptr = string_sprintf("Tainted name '%s' for queue not permitted",
- arg);
- return ERROR;
+ uschar *m;
+ if (m = is_tainted2(arg, 0, "Tainted name '%s' for queue not permitted", arg))
+ {
+ *log_msgptr = m;
+ return ERROR;
+ }
+ if (Ustrchr(arg, '/'))
+ {
+ *log_msgptr = string_sprintf(
+ "Directory separator not permitted in queue name: '%s'", arg);
+ return ERROR;
+ }
+ queue_name = string_copy_perm(arg, FALSE);
+ break;
}
- if (Ustrchr(arg, '/'))
- {
- *log_msgptr = string_sprintf(
- "Directory separator not permitted in queue name: '%s'", arg);
- return ERROR;
- }
- queue_name = string_copy_perm(arg, FALSE);
- break;
case ACLC_RATELIMIT:
rc = acl_ratelimit(arg, where, log_msgptr);
break;
@@ -4005,14 +4007,12 @@
}
else if (*ss == '/')
{
struct stat statbuf;
- if (is_tainted(ss))
+ if (is_tainted2(ss, LOG_MAIN|LOG_PANIC, "Tainted ACL file name '%s'", ss))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to open tainted ACL file name \"%s\"", ss);
/* Avoid leaking info to an attacker */
*log_msgptr = US"internal configuration error";
return ERROR;
}
if ((fd = Uopen(ss, O_RDONLY, 0)) < 0)

View file

@ -0,0 +1,30 @@
From 7eeeb6f26af05322814ecc77c87f09c72ab2216a Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 10:58:46 +0200
Subject: [PATCH 05/23] parse
---
src/parse.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/src/parse.c b/src/parse.c
index 3ea758ac9..d1bc79039 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1402,12 +1402,8 @@ for (;;)
return FF_ERROR;
}
- if (is_tainted(filename))
- {
- *error = string_sprintf("Tainted name '%s' for included file not permitted\n",
- filename);
+ if (*error = is_tainted2(filename, 0, "Tainted name '%s' for included file not permitted\n", filename))
return FF_ERROR;
- }
/* Check file name if required */
--
2.30.2

View file

@ -0,0 +1,28 @@
From a6da9c67acaee699616516be141d600cc178a633 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 10:59:46 +0200
Subject: [PATCH 06/23] rda
---
src/rda.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/rda.c b/src/rda.c
index aed8abc24..6ad7dd8bd 100644
--- a/src/rda.c
+++ b/src/rda.c
@@ -179,10 +179,8 @@ struct stat statbuf;
/* Reading a file is a form of expansion; we wish to deny attackers the
capability to specify the file name. */
-if (is_tainted(filename))
+if (*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename))
{
- *error = string_sprintf("Tainted name '%s' for file read not permitted\n",
- filename);
*yield = FF_ERROR;
return NULL;
}
--
2.30.2

View file

@ -0,0 +1,34 @@
From c29b50d2fe17cc108d751175ed4f4113c25c1768 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 11:00:06 +0200
Subject: [PATCH 07/23] appendfile
---
src/transports/appendfile.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/transports/appendfile.c b/src/transports/appendfile.c
index 8ab8b6016..7dbbaa2f9 100644
--- a/src/transports/appendfile.c
+++ b/src/transports/appendfile.c
@@ -1286,12 +1286,14 @@ if (!(path = expand_string(fdname)))
expand_string_message);
goto ret_panic;
}
-if (is_tainted(path))
+{ uschar *m;
+if (m = is_tainted2(path, 0, "Tainted '%s' (file or directory "
+ "name for %s transport) not permitted", path, tblock->name))
{
- addr->message = string_sprintf("Tainted '%s' (file or directory "
- "name for %s transport) not permitted", path, tblock->name);
+ addr->message = m;
goto ret_panic;
}
+}
if (path[0] != '/')
{
--
2.30.2

View file

@ -0,0 +1,70 @@
From 26de37d8960da80473866fb59b9dfd10a5761538 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 28 Mar 2021 11:06:27 +0200
Subject: [PATCH 08/23] autoreply
---
src/transports/autoreply.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/transports/autoreply.c b/src/transports/autoreply.c
index 865abbf4f..ed99de4c6 100644
--- a/src/transports/autoreply.c
+++ b/src/transports/autoreply.c
@@ -404,14 +404,15 @@ recipient cache. */
if (oncelog && *oncelog && to)
{
+ uschar *m;
time_t then = 0;
- if (is_tainted(oncelog))
+ if (m = is_tainted2(oncelog, 0, "Tainted '%s' (once file for %s transport)"
+ " not permitted", oncelog, tblock->name))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (once file for %s transport)"
- " not permitted", oncelog, tblock->name);
+ addr->message = m;
goto END_OFF;
}
@@ -515,13 +516,14 @@ if (oncelog && *oncelog && to)
if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec))
{
+ uschar *m;
int log_fd;
- if (is_tainted(logfile))
+ if (m = is_tainted2(logfile, 0, "Tainted '%s' (logfile for %s transport)"
+ " not permitted", logfile, tblock->name))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (logfile for %s transport)"
- " not permitted", logfile, tblock->name);
+ addr->message = m;
goto END_OFF;
}
@@ -548,12 +550,13 @@ if (oncelog && *oncelog && to)
/* We are going to send a message. Ensure any requested file is available. */
if (file)
{
- if (is_tainted(file))
+ uschar *m;
+ if (m = is_tainted2(file, 0, "Tainted '%s' (file for %s transport)"
+ " not permitted", file, tblock->name))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (file for %s transport)"
- " not permitted", file, tblock->name);
+ addr->message = m;
return FALSE;
}
if (!(ff = Ufopen(file, "rb")) && !ob->file_optional)
--
2.30.2

View file

@ -0,0 +1,36 @@
From f9628406706112be459adb3f121db8e6cf282c2d Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Fri, 2 Apr 2021 17:30:27 +0200
Subject: [PATCH 09/23] pipe
---
src/transports/pipe.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/transports/pipe.c b/src/transports/pipe.c
index 27422bd42..4c9e68beb 100644
--- a/src/transports/pipe.c
+++ b/src/transports/pipe.c
@@ -599,13 +599,16 @@ if (!cmd || !*cmd)
tblock->name);
return FALSE;
}
-if (is_tainted(cmd))
+
+{ uschar *m;
+if (m = is_tainted2(cmd, 0, "Tainted '%s' (command "
+ "for %s transport) not permitted", cmd, tblock->name))
{
- addr->message = string_sprintf("Tainted '%s' (command "
- "for %s transport) not permitted", cmd, tblock->name);
addr->transport_return = PANIC;
+ addr->message = m;
return FALSE;
}
+}
/* When a pipe is set up by a filter file, there may be values for $thisaddress
and numerical the variables in existence. These are passed in
--
2.30.2

View file

@ -0,0 +1,49 @@
From 2fee91ae42e974c21202e0b5e17185f6a87bf8af Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Wed, 31 Mar 2021 23:12:44 +0200
Subject: [PATCH 10/23] deliver
---
src/deliver.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/deliver.c b/src/deliver.c
index d85edd70e..8b7998f37 100644
--- a/src/deliver.c
+++ b/src/deliver.c
@@ -5538,10 +5538,11 @@ FILE * fp = NULL;
if (!s || !*s)
log_write(0, LOG_MAIN|LOG_PANIC,
"Failed to expand %s: '%s'\n", varname, filename);
-else if (*s != '/' || is_tainted(s))
- log_write(0, LOG_MAIN|LOG_PANIC,
- "%s is not %s after expansion: '%s'\n",
- varname, *s == '/' ? "untainted" : "absolute", s);
+else if (*s != '/')
+ log_write(0, LOG_MAIN|LOG_PANIC, "%s is not absolute after expansion: '%s'\n",
+ varname, s);
+else if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted %s after expansion: '%s'\n", varname, s))
+ ;
else if (!(fp = Ufopen(s, "rb")))
log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s "
"message texts: %s", s, reason, strerror(errno));
@@ -6148,12 +6149,13 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
{
uschar *tmp = expand_string(tpname);
address_file = address_pipe = NULL;
+ uschar *m;
if (!tmp)
p->message = string_sprintf("failed to expand \"%s\" as a "
"system filter transport name", tpname);
- if (is_tainted(tmp))
- p->message = string_sprintf("attempt to used tainted value '%s' for"
- "transport '%s' as a system filter", tmp, tpname);
+ if (is_tainted2(tmp, 0, m = string_sprintf("Tainted values '%s' "
+ "for transport '%s' as a system filter", tmp, tpname)))
+ p->message = m;
tpname = tmp;
}
else
--
2.30.2

View file

@ -0,0 +1,26 @@
From 5f41e800ce9cc7ad154047298914df955e905bf4 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 21:28:59 +0200
Subject: [PATCH 11/23] directory
---
src/directory.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/directory.c b/src/directory.c
index 2d4d565f4..9f88f4141 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -44,6 +44,9 @@ uschar c = 1;
struct stat statbuf;
uschar * path;
+if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted path '%s' for new directory", name))
+ { p = US"create"; path = US name; errno = EACCES; goto bad; }
+
if (parent)
{
path = string_sprintf("%s%s%s", parent, US"/", name);
--
2.30.2

View file

@ -0,0 +1,34 @@
From c02ea85f525ff256d78e084d6f76fe3032fd52e1 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 21:33:50 +0200
Subject: [PATCH 12/23] expand
---
src/expand.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/expand.c b/src/expand.c
index 05de94c49..21b86ebf5 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -4383,13 +4383,13 @@ DEBUG(D_expand)
f.expand_string_forcedfail = FALSE;
expand_string_message = US"";
-if (is_tainted(string))
+{ uschar *m;
+if (m = is_tainted2(string, LOG_MAIN|LOG_PANIC, "Tainted string '%s' in expansion", s))
{
- expand_string_message =
- string_sprintf("attempt to expand tainted string '%s'", s);
- log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message);
+ expand_string_message = m;
goto EXPAND_FAILED;
}
+}
while (*s != 0)
{
--
2.30.2

View file

@ -0,0 +1,49 @@
From 9810dfc25d8b9687b46e57963a3ac30bf5c9b2c9 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 21:36:12 +0200
Subject: [PATCH 13/23] lf_sqlperform
---
src/lookups/lf_sqlperform.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/lookups/lf_sqlperform.c b/src/lookups/lf_sqlperform.c
index ad1df29d1..eda3089e2 100644
--- a/src/lookups/lf_sqlperform.c
+++ b/src/lookups/lf_sqlperform.c
@@ -102,11 +102,13 @@ if (Ustrncmp(query, "servers", 7) == 0)
}
}
- if (is_tainted(server))
- {
- *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+ { uschar *m;
+ if (m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server))
+ {
+ *errmsg = m;
return DEFER;
}
+ }
rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
@@ -158,11 +160,13 @@ else
server = ele;
}
- if (is_tainted(server))
+ { uschar *m;
+ if (is_tainted2(server, 0, "Tainted %s server '%s'", name, server))
{
- *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+ *errmsg = m;
return DEFER;
}
+ }
rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
--
2.30.2

View file

@ -0,0 +1,28 @@
From 015fff57c854184f8bce61476c46a2830a97daf8 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Fri, 2 Apr 2021 08:36:24 +0200
Subject: [PATCH 14/23] rf_get_transport
---
src/routers/rf_get_transport.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/routers/rf_get_transport.c b/src/routers/rf_get_transport.c
index 4a43818ff..32bde9ec3 100644
--- a/src/routers/rf_get_transport.c
+++ b/src/routers/rf_get_transport.c
@@ -66,10 +66,8 @@ if (expandable)
"\"%s\" in %s router: %s", tpname, router_name, expand_string_message);
return FALSE;
}
- if (is_tainted(ss))
+ if (is_tainted2(ss, LOG_MAIN|LOG_PANIC, "Tainted tainted value '%s' from '%s' for transport", ss, tpname))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted value '%s' from '%s' for transport", ss, tpname);
addr->basic_errno = ERRNO_BADTRANSPORT;
/* Avoid leaking info to an attacker */
addr->message = US"internal configuration error";
--
2.30.2

View file

@ -0,0 +1,31 @@
From 2bafe3fc82cf62f0c21f939f5891b8d067f3abc7 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sat, 3 Apr 2021 10:54:22 +0200
Subject: [PATCH 15/23] deliver
---
src/deliver.c | 5 +++--
test/paniclog/0622 | 2 +-
test/stderr/0622 | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/deliver.c b/src/deliver.c
index 8b7998f37..87e944b03 100644
--- a/src/deliver.c
+++ b/src/deliver.c
@@ -6153,9 +6153,10 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
if (!tmp)
p->message = string_sprintf("failed to expand \"%s\" as a "
"system filter transport name", tpname);
- if (is_tainted2(tmp, 0, m = string_sprintf("Tainted values '%s' "
- "for transport '%s' as a system filter", tmp, tpname)))
+ { uschar *m;
+ if (m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname))
p->message = m;
+ }
tpname = tmp;
}
else
--
2.30.2

View file

@ -0,0 +1,38 @@
From b9b967cca71a4da51506f8ba596b9ae40cfcef57 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 21:42:38 +0200
Subject: [PATCH 16/23] smtp_out
---
src/smtp_out.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/src/smtp_out.c b/src/smtp_out.c
index c4c409677..9c160e697 100644
--- a/src/smtp_out.c
+++ b/src/smtp_out.c
@@ -53,11 +53,8 @@ if (!(expint = expand_string(istring)))
return FALSE;
}
-if (is_tainted(expint))
+if (is_tainted2(expint, LOG_MAIN|LOG_PANIC, "Tainted value '%s' from '%s' for interface", expint, istring))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted value '%s' from '%s' for interface",
- expint, istring);
addr->transport_return = PANIC;
addr->message = string_sprintf("failed to expand \"interface\" "
"option for %s: configuration error", msg);
@@ -425,7 +422,7 @@ if (ob->socks_proxy)
{
int sock = socks_sock_connect(sc->host, sc->host_af, port, sc->interface,
sc->tblock, ob->connect_timeout);
-
+
if (sock >= 0)
{
if (early_data && early_data->data && early_data->len)
--
2.30.2

View file

@ -0,0 +1,29 @@
From 8b7d4ba8903ace7e3e3db70343798a5a0b7cea23 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 1 Apr 2021 22:02:27 +0200
Subject: [PATCH 17/23] smtp
---
src/transports/smtp.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/src/transports/smtp.c b/src/transports/smtp.c
index 6540e4d2b..8fecf7eef 100644
--- a/src/transports/smtp.c
+++ b/src/transports/smtp.c
@@ -4715,11 +4715,8 @@ if (!hostlist || (ob->hosts_override && ob->hosts))
else
if (ob->hosts_randomize) s = expanded_hosts = string_copy(s);
- if (is_tainted(s))
+ if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted host list '%s' from '%s' in transport %s", s, ob->hosts, tblock->name))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted host list '%s' from '%s' in transport %s",
- s, ob->hosts, tblock->name);
/* Avoid leaking info to an attacker */
addrlist->message = US"internal configuration error";
addrlist->transport_return = PANIC;
--
2.30.2

View file

@ -0,0 +1,154 @@
From 77cc1ad3058e4ef7ae82adb914ccff0be9fe2c8b Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sat, 3 Apr 2021 09:29:13 +0200
Subject: [PATCH 18/23] update doc
---
doc/doc-docbook/spec.xfpt | 45 ++++++++++++++++++++++++++++++++++++++-
doc/NewStuff | 45 +++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+), 1 deletion(-)
--- a/doc/NewStuff
+++ b/doc/NewStuff
@@ -4,10 +4,55 @@
This file contains descriptions of new features that have been added to Exim.
Before a formal release, there may be quite a lot of detail so that people can
test from the snapshots or the Git before the documentation is updated. Once
the documentation is updated, this file is reduced to a short list.
+Version 4.95
+------------
+
+ 1. The fast-ramp two phase queue run support, previously experimental, is
+ now supported by default.
+
+ 2. The native SRS support, previously experimental, is now supported. It is
+ not built unless specified in the Local/Makefile.
+
+ 3. TLS resumption support, previously experimental, is now supported and
+ included in default builds.
+
+ 4. Single-key LMDB lookups, previously experimental, are now supported.
+ The support is not built unless specified in the Local/Makefile.
+
+ 5. Option "message_linelength_limit" on the smtp transport to enforce (by
+ default) the RFC 998 character limit.
+
+ 6. An option to ignore the cache on a lookup.
+
+ 7. Quota checking during reception (i.e. at SMTP time) for appendfile-
+ transport-managed quotas.
+
+ 8. Sqlite lookups accept a "file=<path>" option to specify a per-operation
+ db file, replacing the previous prefix to the SQL string (which had
+ issues when the SQL used tainted values).
+
+ 9. Lsearch lookups accept a "ret=full" option, to return both the portion
+ of the line matching the key, and the remainder.
+
+10. A command-line option to have a daemon not create a notifier socket.
+
+11. Faster TLS startup. When various configuration options contain no
+ expandable elements, the information can be preloaded and cached rather
+ than the provious behaviour of always loading at startup time for every
+ connection. This helps particularly for the CA bundle.
+
+12. Proxy Protocol Timeout is configurable via "proxy_protocol_timeout"
+ main config option.
+
+13. Option "smtp_accept_msx_per_connection" is now expanded.
+
+13. A main config option "allow_insecure_tainted_data" allows to turn
+ taint errors into warnings.
+
Version 4.94
------------
1. EXPERIMENTAL_SRS_NATIVE optional build feature. See the experimental.spec
file.
--- a/doc/spec.txt
+++ b/doc/spec.txt
@@ -8650,12 +8650,20 @@
Whether a string is expanded depends upon the context. Usually this is solely
dependent upon the option for which a value is sought; in this documentation,
options for which string expansion is performed are marked with * after the
data type. ACL rules always expand strings. A couple of expansion conditions do
not expand some of the brace-delimited branches, for security reasons, and
-expansion of data deriving from the sender ("tainted data") is not permitted.
-
+expansion of data deriving from the sender ("tainted data") is not permitted
+(including acessing a file using a tainted name). The main config
+option allow_insecure_tainted_data can be used as mitigation during
+uprades to more secure configurations.
+
+Common ways of obtaining untainted equivalents of variables with tainted
+values come down to using the tainted value as a lookup key in a trusted
+database. This database could be the filesystem structure, or the
+password file, or accessed via a DBMS. Specific methods are indexed
+under "de-tainting".
11.1 Literal text in expanded strings
-------------------------------------
An uninterpreted dollar can be included in an expanded string by putting a
@@ -12946,10 +12954,12 @@
14.1 Miscellaneous
------------------
+add_environment environment variables
+allow_insecure_tainted_data turn taint errors into warnings
bi_command to run for -bi command line option
debug_store do extra internal checks
disable_ipv6 do no IPv6 processing
keep_malformed for broken files - should not happen
localhost_number for unique message ids in clusters
@@ -13553,10 +13563,20 @@
true, and also to add "@[]" to the list of local domains (defined in the named
domain list local_domains in the default configuration). This "magic string"
matches the domain literal form of all the local host's IP addresses.
+-----------------------------------------------------+
+|allow_insecure_tainted_data main boolean false |
++-----------------------------------------------------+
+
+The handling of tainted data may break older (pre 4.94) configurations.
+Setting this option to "true" turns taint errors (which result in a temporary
+message rejection) into warnings. This option is meant as mitigation only
+and deprecated already today. Future releases of Exim may ignore it.
+The taint log selector can be used to suppress even the warnings.
+
++-----------------------------------------------------+
|allow_mx_to_ip|Use: main|Type: boolean|Default: false|
+-----------------------------------------------------+
It appears that more and more DNS zone administrators are breaking the rules
and putting domain names that look like IP addresses on the right hand side of
@@ -35316,10 +35336,11 @@
smtp_mailauth AUTH argument to MAIL commands
smtp_no_mail session with no MAIL commands
smtp_protocol_error SMTP protocol errors
smtp_syntax_error SMTP syntax errors
subject contents of Subject: on <= lines
+*taint taint errors or warnings
*tls_certificate_verified certificate verification status
*tls_cipher TLS cipher suite on <= and => lines
tls_peerdn TLS peer DN on <= and => lines
tls_sni TLS SNI on <= lines
unknown_in_list DNS lookup failed in list match
@@ -35604,11 +35625,13 @@
* tls_certificate_verified: An extra item is added to <= and => log lines
when TLS is in use. The item is "CV=yes" if the peer's certificate was
verified using a CA trust anchor, "CA=dane" if using a DNS trust anchor,
and "CV=no" if not.
-
+ * taint: Log warnings about tainted data. This selector can't be
+ turned of if allow_insecure_tainted_data is false (which is the
+ default).
* tls_cipher: When a message is sent or received over an encrypted
connection, the cipher suite used is added to the log line, preceded by X=.
* tls_peerdn: When a message is sent or received over an encrypted
connection, and a certificate is supplied by the remote host, the peer DN

View file

@ -0,0 +1,42 @@
From 41c494e2465efadc2e82002a07430e8aec85bc9b Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Mon, 12 Apr 2021 08:41:44 +0200
Subject: [PATCH 20/23] Set mainlog_name and rejectlog_name unconditionally.
(cherry picked from commit 3f06b9b4c7244b169d50bce216c1f54b4dfe7efb)
---
src/log.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/log.c b/src/log.c
index 99eba5f90..011c4debc 100644
--- a/src/log.c
+++ b/src/log.c
@@ -402,18 +402,20 @@ it gets statted to see if it has been cycled. With a datestamp, the datestamp
will be compared. The static slot for saving it is the same size as buffer,
and the text has been checked above to fit, so this use of strcpy() is OK. */
-if (type == lt_main && string_datestamp_offset >= 0)
+if (type == lt_main)
{
Ustrcpy(mainlog_name, buffer);
- mainlog_datestamp = mainlog_name + string_datestamp_offset;
+ if (string_datestamp_offset > 0)
+ mainlog_datestamp = mainlog_name + string_datestamp_offset;
}
/* Ditto for the reject log */
-else if (type == lt_reject && string_datestamp_offset >= 0)
+else if (type == lt_reject)
{
Ustrcpy(rejectlog_name, buffer);
- rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ if (string_datestamp_offset > 0)
+ rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
}
/* and deal with the debug log (which keeps the datestamp, but does not
--
2.30.2

View file

@ -0,0 +1,124 @@
From 8021b95c2e266861aba29c97b4bb90dc6f7637a2 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Mon, 12 Apr 2021 09:19:21 +0200
Subject: [PATCH 21/23] tidy log.c
(cherry picked from commit 0327b6460eec64da6b0c1543c7e9b3d0f8cb9294)
---
src/log.c | 97 +++++++++++++++++++++++----------------------------
1 file changed, 44 insertions(+), 53 deletions(-)
diff --git a/src/log.c b/src/log.c
index 011c4debc..7ef7074ec 100644
--- a/src/log.c
+++ b/src/log.c
@@ -397,62 +397,53 @@ people want, I hope. */
ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
-/* Save the name of the mainlog for rollover processing. Without a datestamp,
-it gets statted to see if it has been cycled. With a datestamp, the datestamp
-will be compared. The static slot for saving it is the same size as buffer,
-and the text has been checked above to fit, so this use of strcpy() is OK. */
-
-if (type == lt_main)
+switch (type)
{
- Ustrcpy(mainlog_name, buffer);
- if (string_datestamp_offset > 0)
- mainlog_datestamp = mainlog_name + string_datestamp_offset;
- }
-
-/* Ditto for the reject log */
-
-else if (type == lt_reject)
- {
- Ustrcpy(rejectlog_name, buffer);
- if (string_datestamp_offset > 0)
- rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
- }
-
-/* and deal with the debug log (which keeps the datestamp, but does not
-update it) */
-
-else if (type == lt_debug)
- {
- Ustrcpy(debuglog_name, buffer);
- if (tag)
- {
- /* this won't change the offset of the datestamp */
- ok2 = string_format(buffer, sizeof(buffer), "%s%s",
- debuglog_name, tag);
- if (ok2)
- Ustrcpy(debuglog_name, buffer);
- }
- }
-
-/* Remove any datestamp if this is the panic log. This is rare, so there's no
-need to optimize getting the datestamp length. We remove one non-alphanumeric
-char afterwards if at the start, otherwise one before. */
-
-else if (string_datestamp_offset >= 0)
- {
- uschar * from = buffer + string_datestamp_offset;
- uschar * to = from + string_datestamp_length;
+ case lt_main:
+ /* Save the name of the mainlog for rollover processing. Without a datestamp,
+ it gets statted to see if it has been cycled. With a datestamp, the datestamp
+ will be compared. The static slot for saving it is the same size as buffer,
+ and the text has been checked above to fit, so this use of strcpy() is OK. */
+ Ustrcpy(mainlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ mainlog_datestamp = mainlog_name + string_datestamp_offset;
+ case lt_reject:
+ /* Ditto for the reject log */
+ Ustrcpy(rejectlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ case lt_debug:
+ /* and deal with the debug log (which keeps the datestamp, but does not
+ update it) */
+ Ustrcpy(debuglog_name, buffer);
+ if (tag)
+ {
+ /* this won't change the offset of the datestamp */
+ ok2 = string_format(buffer, sizeof(buffer), "%s%s",
+ debuglog_name, tag);
+ if (ok2)
+ Ustrcpy(debuglog_name, buffer);
+ }
+ default:
+ /* Remove any datestamp if this is the panic log. This is rare, so there's no
+ need to optimize getting the datestamp length. We remove one non-alphanumeric
+ char afterwards if at the start, otherwise one before. */
+ if (string_datestamp_offset >= 0)
+ {
+ uschar * from = buffer + string_datestamp_offset;
+ uschar * to = from + string_datestamp_length;
- if (from == buffer || from[-1] == '/')
- {
- if (!isalnum(*to)) to++;
- }
- else
- if (!isalnum(from[-1])) from--;
+ if (from == buffer || from[-1] == '/')
+ {
+ if (!isalnum(*to)) to++;
+ }
+ else
+ if (!isalnum(from[-1])) from--;
- /* This copy is ok, because we know that to is a substring of from. But
- due to overlap we must use memmove() not Ustrcpy(). */
- memmove(from, to, Ustrlen(to)+1);
+ /* This copy is ok, because we know that to is a substring of from. But
+ due to overlap we must use memmove() not Ustrcpy(). */
+ memmove(from, to, Ustrlen(to)+1);
+ }
}
/* If the file name is too long, it is an unrecoverable disaster */
--
2.30.2

View file

@ -0,0 +1,222 @@
From 2c9869d0622cc690b424cc74166d4a8393017ece Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Fri, 23 Apr 2021 17:40:40 +0200
Subject: [PATCH 22/23] Silence compiler
---
src/acl.c | 2 +-
src/deliver.c | 3 +--
src/expand.c | 6 +++++-
src/functions.h | 2 +-
src/lookups/lf_sqlperform.c | 4 ++--
src/parse.c | 2 +-
src/rda.c | 2 +-
src/transports/appendfile.c | 4 ++--
src/transports/autoreply.c | 12 ++++++------
src/transports/pipe.c | 4 ++--
10 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/src/acl.c b/src/acl.c
index 81beab5f3..b62af5c65 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -3600,7 +3600,7 @@ for (; cb; cb = cb->next)
case ACLC_QUEUE:
{
uschar *m;
- if (m = is_tainted2(arg, 0, "Tainted name '%s' for queue not permitted", arg))
+ if ((m = is_tainted2(arg, 0, "Tainted name '%s' for queue not permitted", arg)))
{
*log_msgptr = m;
return ERROR;
diff --git a/src/deliver.c b/src/deliver.c
index 87e944b03..b40eed4f9 100644
--- a/src/deliver.c
+++ b/src/deliver.c
@@ -6149,12 +6149,11 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
{
uschar *tmp = expand_string(tpname);
address_file = address_pipe = NULL;
- uschar *m;
if (!tmp)
p->message = string_sprintf("failed to expand \"%s\" as a "
"system filter transport name", tpname);
{ uschar *m;
- if (m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname))
+ if ((m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname)))
p->message = m;
}
tpname = tmp;
diff --git a/src/expand.c b/src/expand.c
index 21b86ebf5..dc4b4e102 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -4384,7 +4384,7 @@ f.expand_string_forcedfail = FALSE;
expand_string_message = US"";
{ uschar *m;
-if (m = is_tainted2(string, LOG_MAIN|LOG_PANIC, "Tainted string '%s' in expansion", s))
+if ((m = is_tainted2(string, LOG_MAIN|LOG_PANIC, "Tainted string '%s' in expansion", s)))
{
expand_string_message = m;
goto EXPAND_FAILED;
@@ -7629,10 +7629,12 @@ while (*s != 0)
/* Manually track tainting, as we deal in individual chars below */
if (is_tainted(sub))
+ {
if (yield->s && yield->ptr)
gstring_rebuffer(yield);
else
yield->s = store_get(yield->size = Ustrlen(sub), TRUE);
+ }
/* Check the UTF-8, byte-by-byte */
@@ -8193,6 +8195,7 @@ that is a bad idea, because expand_string_message is in dynamic store. */
EXPAND_FAILED:
if (left) *left = s;
DEBUG(D_expand)
+ {
DEBUG(D_noutf8)
{
debug_printf_indent("|failed to expand: %s\n", string);
@@ -8212,6 +8215,7 @@ DEBUG(D_expand)
if (f.expand_string_forcedfail)
debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n");
}
+ }
if (resetok_p && !resetok) *resetok_p = FALSE;
expand_level--;
return NULL;
diff --git a/src/functions.h b/src/functions.h
index 1e8083673..b4d23c4bc 100644
--- a/src/functions.h
+++ b/src/functions.h
@@ -1084,7 +1084,7 @@ 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, ...)
+is_tainted2(const void *p, int lflags, const char* fmt, ...)
{
va_list ap;
uschar *msg;
diff --git a/src/lookups/lf_sqlperform.c b/src/lookups/lf_sqlperform.c
index eda3089e2..38b7c2ad3 100644
--- a/src/lookups/lf_sqlperform.c
+++ b/src/lookups/lf_sqlperform.c
@@ -103,7 +103,7 @@ if (Ustrncmp(query, "servers", 7) == 0)
}
{ uschar *m;
- if (m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server))
+ if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
{
*errmsg = m;
return DEFER;
@@ -161,7 +161,7 @@ else
}
{ uschar *m;
- if (is_tainted2(server, 0, "Tainted %s server '%s'", name, server))
+ if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
{
*errmsg = m;
return DEFER;
diff --git a/src/parse.c b/src/parse.c
index d1bc79039..0622b3127 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1402,7 +1402,7 @@ for (;;)
return FF_ERROR;
}
- if (*error = is_tainted2(filename, 0, "Tainted name '%s' for included file not permitted\n", filename))
+ if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for included file not permitted\n", filename)))
return FF_ERROR;
/* Check file name if required */
diff --git a/src/rda.c b/src/rda.c
index 6ad7dd8bd..bba0b719b 100644
--- a/src/rda.c
+++ b/src/rda.c
@@ -179,7 +179,7 @@ struct stat statbuf;
/* Reading a file is a form of expansion; we wish to deny attackers the
capability to specify the file name. */
-if (*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename))
+if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename)))
{
*yield = FF_ERROR;
return NULL;
diff --git a/src/transports/appendfile.c b/src/transports/appendfile.c
index 7dbbaa2f9..6772b338b 100644
--- a/src/transports/appendfile.c
+++ b/src/transports/appendfile.c
@@ -1287,8 +1287,8 @@ if (!(path = expand_string(fdname)))
goto ret_panic;
}
{ uschar *m;
-if (m = is_tainted2(path, 0, "Tainted '%s' (file or directory "
- "name for %s transport) not permitted", path, tblock->name))
+if ((m = is_tainted2(path, 0, "Tainted '%s' (file or directory "
+ "name for %s transport) not permitted", path, tblock->name)))
{
addr->message = m;
goto ret_panic;
diff --git a/src/transports/autoreply.c b/src/transports/autoreply.c
index ed99de4c6..80c7c0db0 100644
--- a/src/transports/autoreply.c
+++ b/src/transports/autoreply.c
@@ -407,8 +407,8 @@ if (oncelog && *oncelog && to)
uschar *m;
time_t then = 0;
- if (m = is_tainted2(oncelog, 0, "Tainted '%s' (once file for %s transport)"
- " not permitted", oncelog, tblock->name))
+ if ((m = is_tainted2(oncelog, 0, "Tainted '%s' (once file for %s transport)"
+ " not permitted", oncelog, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
@@ -518,8 +518,8 @@ if (oncelog && *oncelog && to)
{
uschar *m;
int log_fd;
- if (m = is_tainted2(logfile, 0, "Tainted '%s' (logfile for %s transport)"
- " not permitted", logfile, tblock->name))
+ if ((m = is_tainted2(logfile, 0, "Tainted '%s' (logfile for %s transport)"
+ " not permitted", logfile, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
@@ -551,8 +551,8 @@ if (oncelog && *oncelog && to)
if (file)
{
uschar *m;
- if (m = is_tainted2(file, 0, "Tainted '%s' (file for %s transport)"
- " not permitted", file, tblock->name))
+ if ((m = is_tainted2(file, 0, "Tainted '%s' (file for %s transport)"
+ " not permitted", file, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
diff --git a/src/transports/pipe.c b/src/transports/pipe.c
index 4c9e68beb..fc44fa585 100644
--- a/src/transports/pipe.c
+++ b/src/transports/pipe.c
@@ -601,8 +601,8 @@ if (!cmd || !*cmd)
}
{ uschar *m;
-if (m = is_tainted2(cmd, 0, "Tainted '%s' (command "
- "for %s transport) not permitted", cmd, tblock->name))
+if ((m = is_tainted2(cmd, 0, "Tainted '%s' (command "
+ "for %s transport) not permitted", cmd, tblock->name)))
{
addr->transport_return = PANIC;
addr->message = m;
--
2.30.2

View file

@ -0,0 +1,166 @@
From 235c7030ee9ee1c1aad507786506a470b580bfe2 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Fri, 23 Apr 2021 22:41:57 +0200
Subject: [PATCH 23/23] Do not close the (main)_log, if we do not see a chance
to open it again.
The process doing local deliveries runs as an unprivileged user. If this
process needs to log failures or warnings (as caused by the
is_tainting2() function), it can't re-open the main_log and just exits.
---
src/log.c | 84 ++++++++++++++++-----------------
src/transports/appendfile.c | 6 +++
2 files changed, 47 insertions(+), 43 deletions(-)
diff --git a/src/log.c b/src/log.c
index 7ef7074ec..c2ef698e7 100644
--- a/src/log.c
+++ b/src/log.c
@@ -646,18 +646,36 @@ return total_written;
}
-
-static void
-set_file_path(void)
+void
+set_file_path(BOOL *multiple)
{
+uschar *s;
int sep = ':'; /* Fixed separator - outside use */
-uschar *t;
-const uschar *tt = US LOG_FILE_PATH;
-while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
+uschar *ss = *log_file_path ? log_file_path : LOG_FILE_PATH;
+
+logging_mode = 0;
+while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
{
- if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
- file_path = string_copy(t);
- break;
+ if (Ustrcmp(s, "syslog") == 0)
+ logging_mode |= LOG_MODE_SYSLOG;
+ else if (logging_mode & LOG_MODE_FILE) /* we know a file already */
+ {
+ if (multiple) *multiple = TRUE;
+ }
+ else
+ {
+ logging_mode |= LOG_MODE_FILE;
+
+ /* If a non-empty path is given, use it */
+
+ if (*s)
+ file_path = string_copy(s);
+
+ /* If the path is empty, we want to use the first non-empty, non-
+ syslog item in LOG_FILE_PATH, if there is one, since the value of
+ log_file_path may have been set at runtime. If there is no such item,
+ use the ultimate default in the spool directory. */
+ }
}
}
@@ -665,7 +683,11 @@ while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
void
mainlog_close(void)
{
-if (mainlogfd < 0) return;
+/* avoid closing it if it is closed already or if we do not see a chance
+to open the file mainlog later again */
+if (mainlogfd < 0 /* already closed */
+ || !(geteuid() == 0 || geteuid() == exim_uid))
+ return;
(void)close(mainlogfd);
mainlogfd = -1;
mainlog_inode = 0;
@@ -780,38 +802,7 @@ if (!path_inspected)
/* If nothing has been set, don't waste effort... the default values for the
statics are file_path="" and logging_mode = LOG_MODE_FILE. */
- if (*log_file_path)
- {
- int sep = ':'; /* Fixed separator - outside use */
- uschar *s;
- const uschar *ss = log_file_path;
-
- logging_mode = 0;
- while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
- {
- if (Ustrcmp(s, "syslog") == 0)
- logging_mode |= LOG_MODE_SYSLOG;
- else if (logging_mode & LOG_MODE_FILE)
- multiple = TRUE;
- else
- {
- logging_mode |= LOG_MODE_FILE;
-
- /* If a non-empty path is given, use it */
-
- if (*s)
- file_path = string_copy(s);
-
- /* If the path is empty, we want to use the first non-empty, non-
- syslog item in LOG_FILE_PATH, if there is one, since the value of
- log_file_path may have been set at runtime. If there is no such item,
- use the ultimate default in the spool directory. */
-
- else
- set_file_path(); /* Empty item in log_file_path */
- } /* First non-syslog item in log_file_path */
- } /* Scan of log_file_path */
- }
+ if (*log_file_path) set_file_path(&multiple);
/* If no modes have been selected, it is a major disaster */
@@ -1431,7 +1422,7 @@ if (opts)
resulting in certain setup not having been done. Hack this for now so we
do not segfault; note that nondefault log locations will not work */
-if (!*file_path) set_file_path();
+if (!*file_path) set_file_path(NULL);
open_log(&fd, lt_debug, tag_name);
@@ -1453,5 +1444,12 @@ debug_file = NULL;
unlink_log(lt_debug);
}
+void
+open_logs(const char *m)
+{
+set_file_path(NULL);
+open_log(&mainlogfd, lt_main, 0);
+open_log(&rejectlogfd, lt_reject, 0);
+}
/* End of log.c */
diff --git a/src/transports/appendfile.c b/src/transports/appendfile.c
index 6772b338b..706af6dde 100644
--- a/src/transports/appendfile.c
+++ b/src/transports/appendfile.c
@@ -217,6 +217,9 @@ Arguments:
Returns: OK, FAIL, or DEFER
*/
+void
+openlogs();
+
static int
appendfile_transport_setup(transport_instance *tblock, address_item *addrlist,
transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg)
@@ -231,6 +234,9 @@ dummy = dummy;
uid = uid;
gid = gid;
+/* we can't wait until we're not privileged anymore */
+open_logs("appendfile");
+
if (ob->expand_maildir_use_size_file)
ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
US"`maildir_use_size_file` in transport", tblock->name);
--
2.30.2

View file

@ -0,0 +1,57 @@
From 33d5b8e8e4c2f23b4e834e3a095e3c9dd9f0686b Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 25 Apr 2021 18:58:35 +0200
Subject: [PATCH 1/4] Silence the compiler
---
src/log.c | 4 ++--
src/transports/appendfile.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/log.c b/src/log.c
index c2ef698e7..11d259197 100644
--- a/src/log.c
+++ b/src/log.c
@@ -651,7 +651,7 @@ set_file_path(BOOL *multiple)
{
uschar *s;
int sep = ':'; /* Fixed separator - outside use */
-uschar *ss = *log_file_path ? log_file_path : LOG_FILE_PATH;
+const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
logging_mode = 0;
while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
@@ -1445,7 +1445,7 @@ unlink_log(lt_debug);
}
void
-open_logs(const char *m)
+open_logs(void)
{
set_file_path(NULL);
open_log(&mainlogfd, lt_main, 0);
diff --git a/src/transports/appendfile.c b/src/transports/appendfile.c
index 706af6dde..c0f4de4c8 100644
--- a/src/transports/appendfile.c
+++ b/src/transports/appendfile.c
@@ -218,7 +218,7 @@ Returns: OK, FAIL, or DEFER
*/
void
-openlogs();
+open_logs(void);
static int
appendfile_transport_setup(transport_instance *tblock, address_item *addrlist,
@@ -235,7 +235,7 @@ uid = uid;
gid = gid;
/* we can't wait until we're not privileged anymore */
-open_logs("appendfile");
+open_logs();
if (ob->expand_maildir_use_size_file)
ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
--
2.30.2

View file

@ -0,0 +1,27 @@
From 1416743e923cacf42955392e92995f5fe7e1c680 Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Sun, 25 Apr 2021 10:19:32 +0200
Subject: [PATCH 3/4] Disable taintchecks for mkdir, this isn't part of 4.94
---
src/directory.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/directory.c b/src/directory.c
index 9f88f4141..ece1ee8f3 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -44,8 +44,10 @@ uschar c = 1;
struct stat statbuf;
uschar * path;
+/* does not work with 4.94
if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted path '%s' for new directory", name))
{ p = US"create"; path = US name; errno = EACCES; goto bad; }
+*/
if (parent)
{
--
2.30.2

View file

@ -1,56 +0,0 @@
From 173bd1c8f9cf83ad8c0e61a9e32678e7e371d41d Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Tue, 2 Jun 2020 14:50:31 +0100
Subject: [PATCH 02/26] Taint: fix pam expansion condition. Bug 2587
(cherry picked from commit f7f933a199be8bb7362c715e0040545b514cddca)
---
doc/ChangeLog | 9 +++++++++
src/auths/call_pam.c | 5 ++---
diff --git doc/ChangeLog doc/ChangeLog
index 585deb042..dbdc22117 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -3,6 +3,15 @@ affect Exim's operation, with an unchanged configuration file. For new
options, and new features, see the NewStuff file next to this ChangeLog.
+Since Exim version 4.94
+-----------------------
+
+JH/02 Bug 2587: Fix pam expansion condition. Tainted values are commonly used
+ as arguments, so an implementation trying to copy these into a local
+ buffer was taking a taint-enformance trap. Fix by using dynamically
+ created buffers.
+
+
Exim version 4.94
-----------------
diff --git src/auths/call_pam.c src/auths/call_pam.c
index 2959cbbf3..80bb23ec3 100644
--- src/auths/call_pam.c
+++ src/auths/call_pam.c
@@ -83,8 +83,7 @@ for (int i = 0; i < num_msg; i++)
{
case PAM_PROMPT_ECHO_ON:
case PAM_PROMPT_ECHO_OFF:
- arg = string_nextinlist(&pam_args, &sep, big_buffer, big_buffer_size);
- if (!arg)
+ if (!(arg = string_nextinlist(&pam_args, &sep, NULL, 0)))
{
arg = US"";
pam_arg_ended = TRUE;
@@ -155,7 +154,7 @@ pam_arg_ended = FALSE;
fail. PAM doesn't support authentication with an empty user (it prompts for it,
causing a potential mis-interpretation). */
-user = string_nextinlist(&pam_args, &sep, big_buffer, big_buffer_size);
+user = string_nextinlist(&pam_args, &sep, NULL, 0);
if (user == NULL || user[0] == 0) return FAIL;
/* Start off PAM interaction */
--
2.24.3 (Apple Git-128)

View file

@ -1,43 +0,0 @@
From 63652bbaf66c4bdb388b08fdf3eb8ab1e4d91475 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Tue, 2 Jun 2020 15:03:36 +0100
Subject: [PATCH 03/26] Taint: fix listcount expansion operator. Bug 2586
(cherry picked from commit 44644c2e404a3ea0191db0b0458e86924fb240bb)
---
doc/ChangeLog | 4 ++++
src/expand.c | 3 +--
diff --git doc/ChangeLog doc/ChangeLog
index dbdc22117..94bcea29b 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -11,6 +11,10 @@ JH/02 Bug 2587: Fix pam expansion condition. Tainted values are commonly used
buffer was taking a taint-enformance trap. Fix by using dynamically
created buffers.
+JH/03 Bug 2586: Fix listcount expansion operator. Using tainted arguments is
+ reasonable, eg. to count headers. Fix by using dynamically created
+ buffers rather than a local,
+
Exim version 4.94
-----------------
diff --git src/expand.c src/expand.c
index 26f7f10ac..6ed22c14d 100644
--- src/expand.c
+++ src/expand.c
@@ -7208,9 +7208,8 @@ while (*s != 0)
{
int cnt = 0;
int sep = 0;
- uschar buffer[256];
- while (string_nextinlist(CUSS &sub, &sep, buffer, sizeof(buffer))) cnt++;
+ while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++;
yield = string_fmt_append(yield, "%d", cnt);
continue;
}
--
2.24.3 (Apple Git-128)

View file

@ -1,28 +0,0 @@
From aabe0ebe82297d7dec3abdfff9c3b1edc34fd8ab Mon Sep 17 00:00:00 2001
From: Patrick Boutilier <boutilpj@ednet.ns.ca>
Date: Tue, 2 Jun 2020 15:16:10 +0100
Subject: [PATCH 04/26] Docs: fix mistaken variable name
(cherry picked from commit eb55cb1d2c5552209e24345e9d21f83ec1eaccf6)
---
README.UPDATING | 4 ++--
diff --git README.UPDATING README.UPDATING
index a0afa8df0..708027f2c 100644
--- README.UPDATING
+++ README.UPDATING
@@ -31,9 +31,9 @@ Exim version 4.94
Some Transports now refuse to use tainted data in constructing their delivery
location; this WILL BREAK configurations which are not updated accordingly.
-In particular: any Transport use of $local_user which has been relying upon
+In particular: any Transport use of $local_part which has been relying upon
check_local_user far away in the Router to make it safe, should be updated to
-replace $local_user with $local_part_data.
+replace $local_part with $local_part_data.
Attempting to remove, in router or transport, a header name that ends with
an asterisk (which is a standards-legal name) will now result in all headers
--
2.24.3 (Apple Git-128)

View file

@ -1,25 +0,0 @@
From de498d230862bcc49acbc6d5e76c71b1e15596c3 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Tue, 2 Jun 2020 16:34:42 +0100
Subject: [PATCH 06/26] Docs: typoes
Cherry-picked from: 1195f8f2a4
---
doc/ChangeLog | 2 +-
diff --git doc/ChangeLog doc/ChangeLog
index 94bcea29b..f858c9121 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -8,7 +8,7 @@ Since Exim version 4.94
JH/02 Bug 2587: Fix pam expansion condition. Tainted values are commonly used
as arguments, so an implementation trying to copy these into a local
- buffer was taking a taint-enformance trap. Fix by using dynamically
+ buffer was taking a taint-enforcement trap. Fix by using dynamically
created buffers.
JH/03 Bug 2586: Fix listcount expansion operator. Using tainted arguments is
--
2.24.3 (Apple Git-128)

View file

@ -1,79 +0,0 @@
From 623f07cfdcaca96274ca765d0fcf0761bdf7151b Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Wed, 3 Jun 2020 11:40:17 +0100
Subject: [PATCH 07/26] Taint: fix multiple ACL actions to properly manage
tainted argument data
(cherry picked from commit 12b7f811de4a540d0724585aecfa33b5881e2a30)
---
doc/ChangeLog | 4 +++-
src/acl.c | 12 ++++++------
diff --git doc/ChangeLog doc/ChangeLog
index f858c9121..015959cb6 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -13,7 +13,9 @@ JH/02 Bug 2587: Fix pam expansion condition. Tainted values are commonly used
JH/03 Bug 2586: Fix listcount expansion operator. Using tainted arguments is
reasonable, eg. to count headers. Fix by using dynamically created
- buffers rather than a local,
+ buffers rather than a local. Do similar fixes for ACL actions "dcc",
+ "log_reject_target", "malware" and "spam"; the arguments are expanded
+ so could be handling tainted values.
Exim version 4.94
diff --git src/acl.c src/acl.c
index c1d60bbd9..8619cd5ef 100644
--- src/acl.c
+++ src/acl.c
@@ -3349,11 +3349,11 @@ for (; cb; cb = cb->next)
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
+ uschar *ss = string_nextinlist(&list, &sep, NULL, 0);
/* Run the dcc backend. */
rc = dcc_process(&ss);
/* Modify return code based upon the existence of options. */
- while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+ while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
rc = FAIL; /* FAIL so that the message is passed to the next ACL */
}
@@ -3514,7 +3514,7 @@ for (; cb; cb = cb->next)
int sep = 0;
const uschar *s = arg;
uschar * ss;
- while ((ss = string_nextinlist(&s, &sep, big_buffer, big_buffer_size)))
+ while ((ss = string_nextinlist(&s, &sep, NULL, 0)))
{
if (Ustrcmp(ss, "main") == 0) logbits |= LOG_MAIN;
else if (Ustrcmp(ss, "panic") == 0) logbits |= LOG_PANIC;
@@ -3567,7 +3567,7 @@ for (; cb; cb = cb->next)
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar * ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
+ uschar * ss = string_nextinlist(&list, &sep, NULL, 0);
uschar * opt;
BOOL defer_ok = FALSE;
int timeout = 0;
@@ -3672,11 +3672,11 @@ for (; cb; cb = cb->next)
{
/* Separate the regular expression and any optional parameters. */
const uschar * list = arg;
- uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
+ uschar *ss = string_nextinlist(&list, &sep, NULL, 0);
rc = spam(CUSS &ss);
/* Modify return code based upon the existence of options. */
- while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+ while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
if (strcmpic(ss, US"defer_ok") == 0 && rc == DEFER)
rc = FAIL; /* FAIL so that the message is passed to the next ACL */
}
--
2.24.3 (Apple Git-128)

View file

@ -1,44 +0,0 @@
From 0e8319c3edebfec2158fbaa4898af27cb3225c99 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 4 Jun 2020 15:28:15 +0100
Subject: [PATCH 08/26] Fix -bi. Bug 2590
Actual fix from pierre.labastie@neuf.fr ; additional coding and testcase bu jgh
Broken-by: bdcc6f2bd5
(Cherry-picked from: 0e0e171628)
---
doc/ChangeLog | 4 ++++
src/exim.c | 2 +-
diff --git doc/ChangeLog doc/ChangeLog
index 015959cb6..621d5b1b5 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -17,6 +17,10 @@ JH/03 Bug 2586: Fix listcount expansion operator. Using tainted arguments is
"log_reject_target", "malware" and "spam"; the arguments are expanded
so could be handling tainted values.
+JH/04 Bug 2590: Fix -bi (newaliases). A previous code rearrangement had
+ broken the (no-op) support for this sendmail command. Restore it
+ to doing nothing, silently, and returning good status.
+
Exim version 4.94
-----------------
diff --git src/exim.c src/exim.c
index a60488e95..6143fe989 100644
--- src/exim.c
+++ src/exim.c
@@ -2148,7 +2148,7 @@ on the second character (the one after '-'), to save some effort. */
concept of *the* alias file, but since Sun's YP make script calls
sendmail this way, some support must be provided. */
case 'i':
- if (!*++argrest) bi_option = TRUE;
+ if (!*argrest) bi_option = TRUE;
else badarg = TRUE;
break;
--
2.24.3 (Apple Git-128)

View file

@ -1,48 +0,0 @@
From 701af1005a6effaac5ce249f1c2086dc6c0c2a7f Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Mon, 8 Jun 2020 13:00:55 +0100
Subject: [PATCH 09/26] Filters: fix "vacation" in Exim filter. Bug 2593
Broken-by: cfb9cf20cb (4.90)
(cherry picked from commit 59eee1bc902f106d20f507ba16f37cb8ab5a5e8d)
---
doc/ChangeLog | 5 ++
src/transports/autoreply.c | 6 +--
diff --git doc/ChangeLog doc/ChangeLog
index 621d5b1b5..b9c1ec29e 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -21,6 +21,11 @@ JH/04 Bug 2590: Fix -bi (newaliases). A previous code rearrangement had
broken the (no-op) support for this sendmail command. Restore it
to doing nothing, silently, and returning good status.
+JH/05 Bug 2593: Fix "vacation" in Exim filter. Previously, when a "once"
+ record path was given (or the default used) without a leading directory
+ path, an error occurred on trying to open it. Use the transport's working
+ directory.
+
Exim version 4.94
-----------------
diff --git src/transports/autoreply.c src/transports/autoreply.c
index 4c2c08b70..865abbf4f 100644
--- src/transports/autoreply.c
+++ src/transports/autoreply.c
@@ -474,10 +474,10 @@ if (oncelog && *oncelog && to)
else
{
EXIM_DATUM key_datum, result_datum;
- uschar * dirname = string_copy(oncelog);
- uschar * s;
+ uschar * dirname, * s;
- if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+ dirname = (s = Ustrrchr(oncelog, '/'))
+ ? string_copyn(oncelog, s - oncelog) : NULL;
EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
if (!dbm_file)
{
--
2.24.3 (Apple Git-128)

View file

@ -1,180 +0,0 @@
From 3fe5ec41e81831028c992f77a15292872fbbac75 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 11 Jun 2020 20:45:05 +0100
Subject: [PATCH 10/26] TLS: use RFC 6125 rules for certifucate name
checks when CNAMES are present. Bug 2594
(cherry picked from commit 0851a3bbf4667081d47f5d85b6b3a5cb33cbdba6)
---
doc/ChangeLog | 7 ++-
src/host.c | 17 +++++++
src/structs.h | 19 ++++----
src/tls-gnu.c | 4 +-
src/tls-openssl.c | 20 ++++-----
diff --git doc/ChangeLog doc/ChangeLog
index b9c1ec29e..612005803 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -26,6 +26,11 @@ JH/05 Bug 2593: Fix "vacation" in Exim filter. Previously, when a "once"
path, an error occurred on trying to open it. Use the transport's working
directory.
+JH/06 Bug 2594: Change the name used for certificate name checks in the smtp
+ transport. Previously it was the name on the DNS A-record; use instead
+ the head of the CNAME chain leading there (if there is one). This seems
+ to align better with RFC 6125.
+
Exim version 4.94
-----------------
@@ -331,7 +336,7 @@ JH/20 Bug 2389: fix server advertising of usable certificates, under GnuTLS in
JH/21 The smtp transport option "hosts_noproxy_tls" is now unset by default.
A single TCP connection by a client will now hold a TLS connection open
- for multiple message deliveries, by default. Previoud the default was to
+ for multiple message deliveries, by default. Previously the default was to
not do so.
JH/22 The smtp transport option "hosts_try_dane" now enables all hosts by
diff --git src/host.c src/host.c
index 0e0e0130b..817d4446c 100644
--- src/host.c
+++ src/host.c
@@ -1950,6 +1950,13 @@ BOOL temp_error = FALSE;
int af;
#endif
+#ifndef DISABLE_TLS
+/* Copy the host name at this point to the value which is used for
+TLS certificate name checking, before anything modifies it. */
+
+host->certname = host->name;
+#endif
+
/* Make sure DNS options are set as required. This appears to be necessary in
some circumstances when the get..byname() function actually calls the DNS. */
@@ -2117,6 +2124,9 @@ for (int i = 1; i <= times;
{
host_item *next = store_get(sizeof(host_item), FALSE);
next->name = host->name;
+#ifndef DISABLE_TLS
+ next->certname = host->certname;
+#endif
next->mx = host->mx;
next->address = text_address;
next->port = PORT_NONE;
@@ -2260,6 +2270,13 @@ BOOL v6_find_again = FALSE;
BOOL dnssec_fail = FALSE;
int i;
+#ifndef DISABLE_TLS
+/* Copy the host name at this point to the value which is used for
+TLS certificate name checking, before any CNAME-following modifies it. */
+
+host->certname = host->name;
+#endif
+
/* If allow_ip is set, a name which is an IP address returns that value
as its address. This is used for MX records when allow_mx_to_ip is set, for
those sites that feel they have to flaunt the RFC rules. */
diff --git src/structs.h src/structs.h
index c6700d513..206237f04 100644
--- src/structs.h
+++ src/structs.h
@@ -80,14 +80,17 @@ typedef enum {DS_UNK=-1, DS_NO, DS_YES} dnssec_status_t;
typedef struct host_item {
struct host_item *next;
- const uschar *name; /* Host name */
- const uschar *address; /* IP address in text form */
- int port; /* port value in host order (if SRV lookup) */
- int mx; /* MX value if found via MX records */
- int sort_key; /* MX*1000 plus random "fraction" */
- int status; /* Usable, unusable, or unknown */
- int why; /* Why host is unusable */
- int last_try; /* Time of last try if known */
+ const uschar *name; /* Host name */
+#ifndef DISABLE_TLS
+ const uschar *certname; /* Name used for certificate checks */
+#endif
+ const uschar *address; /* IP address in text form */
+ int port; /* port value in host order (if SRV lookup) */
+ int mx; /* MX value if found via MX records */
+ int sort_key; /* MX*1000 plus random "fraction" */
+ int status; /* Usable, unusable, or unknown */
+ int why; /* Why host is unusable */
+ int last_try; /* Time of last try if known */
dnssec_status_t dnssec;
} host_item;
diff --git src/tls-gnu.c src/tls-gnu.c
index 24114f05e..875c82efa 100644
--- src/tls-gnu.c
+++ src/tls-gnu.c
@@ -2601,9 +2601,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
{
state->exp_tls_verify_cert_hostnames =
#ifdef SUPPORT_I18N
- string_domain_utf8_to_alabel(host->name, NULL);
+ string_domain_utf8_to_alabel(host->certname, NULL);
#else
- host->name;
+ host->certname;
#endif
DEBUG(D_tls)
debug_printf("TLS: server cert verification includes hostname: \"%s\".\n",
diff --git src/tls-openssl.c src/tls-openssl.c
index 8c9d8aa69..a62322928 100644
--- src/tls-openssl.c
+++ src/tls-openssl.c
@@ -372,10 +372,10 @@ typedef struct ocsp_resp {
} ocsp_resplist;
typedef struct tls_ext_ctx_cb {
- tls_support * tlsp;
- uschar *certificate;
- uschar *privatekey;
- BOOL is_server;
+ tls_support * tlsp;
+ uschar * certificate;
+ uschar * privatekey;
+ BOOL is_server;
#ifndef DISABLE_OCSP
STACK_OF(X509) *verify_stack; /* chain for verifying the proof */
union {
@@ -390,14 +390,14 @@ typedef struct tls_ext_ctx_cb {
} client;
} u_ocsp;
#endif
- uschar *dhparam;
+ uschar * dhparam;
/* these are cached from first expand */
- uschar *server_cipher_list;
+ uschar * server_cipher_list;
/* only passed down to tls_error: */
- host_item *host;
+ host_item * host;
const uschar * verify_cert_hostnames;
#ifndef DISABLE_EVENT
- uschar * event_action;
+ uschar * event_action;
#endif
} tls_ext_ctx_cb;
@@ -2915,9 +2915,9 @@ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
{
cbinfo->verify_cert_hostnames =
#ifdef SUPPORT_I18N
- string_domain_utf8_to_alabel(host->name, NULL);
+ string_domain_utf8_to_alabel(host->certname, NULL);
#else
- host->name;
+ host->certname;
#endif
DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
cbinfo->verify_cert_hostnames);
--
2.24.3 (Apple Git-128)

View file

@ -1,40 +0,0 @@
From 94d719d803caf2c0c902dceeb787795eac11a63b Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 12 Jun 2020 00:46:34 +0100
Subject: [PATCH 11/26] Taint: fix radius expansion condition
(cherry picked from commit f91219c114a3d95792d052555664a5a7a3984a8d)
---
doc/ChangeLog | 2 +-
src/auths/call_radius.c | 3 +--
diff --git doc/ChangeLog doc/ChangeLog
index 612005803..41d8c6276 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -9,7 +9,7 @@ Since Exim version 4.94
JH/02 Bug 2587: Fix pam expansion condition. Tainted values are commonly used
as arguments, so an implementation trying to copy these into a local
buffer was taking a taint-enforcement trap. Fix by using dynamically
- created buffers.
+ created buffers. Similar fix for radius expansion condition.
JH/03 Bug 2586: Fix listcount expansion operator. Using tainted arguments is
reasonable, eg. to count headers. Fix by using dynamically created
diff --git src/auths/call_radius.c src/auths/call_radius.c
index cc269dcd5..9d10b34c6 100644
--- src/auths/call_radius.c
+++ src/auths/call_radius.c
@@ -96,8 +96,7 @@ int sep = 0;
#endif
-user = string_nextinlist(&radius_args, &sep, big_buffer, big_buffer_size);
-if (!user) user = US"";
+if (!(user = string_nextinlist(&radius_args, &sep, NULL, 0))) user = US"";
DEBUG(D_auth) debug_printf("Running RADIUS authentication for user \"%s\" "
"and \"%s\"\n", user, radius_args);
--
2.24.3 (Apple Git-128)

View file

@ -1,42 +0,0 @@
From c165e95889471bc1a644104dd9a6129c47c56c09 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 12 Jun 2020 20:43:43 +0100
Subject: [PATCH 12/26] smtp_accept_map_per_host: call search_tidyup in fail
path. Bug 2597
(cherry-picked from: d3a538c8fe)
---
doc/ChangeLog | 5 +++++
src/daemon.c | 1 +
diff --git doc/ChangeLog doc/ChangeLog
index 41d8c6276..92298e7fc 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -31,6 +31,11 @@ JH/06 Bug 2594: Change the name used for certificate name checks in the smtp
the head of the CNAME chain leading there (if there is one). This seems
to align better with RFC 6125.
+JH/07 Bug 2597: Fix a resource leak. Using a lookup in obtaining a value for
+ smtp_accept_max_per_host allocated resources which were not released
+ when the limit was exceeded. This eventually crashed the daemon. Fix
+ by adding a relase action in that path.
+
Exim version 4.94
-----------------
diff --git src/daemon.c src/daemon.c
index 2bed143a1..9d491593f 100644
--- src/daemon.c
+++ src/daemon.c
@@ -336,6 +336,7 @@ if ((max_for_this_host > 0) &&
log_write(L_connection_reject,
LOG_MAIN, "Connection from %s refused: too many connections "
"from that IP address", whofrom->s);
+ search_tidyup();
goto ERROR_RETURN;
}
}
--
2.24.3 (Apple Git-128)

View file

@ -1,50 +0,0 @@
From ecf1e77accda6355ebb745a0a03e97ba7eb298b2 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 14 Jun 2020 22:14:11 +0100
Subject: [PATCH 13/26] Taint: fix verify. Bug 2598
(cherry-picked from 2b60ac1021 and 9eed571fd7)
---
doc/ChangeLog | 4 +++
src/acl.c | 4 +--
diff --git doc/ChangeLog doc/ChangeLog
index 92298e7fc..859e87b00 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -36,6 +36,10 @@ JH/07 Bug 2597: Fix a resource leak. Using a lookup in obtaining a value for
when the limit was exceeded. This eventually crashed the daemon. Fix
by adding a relase action in that path.
+JH/08 Bug 2598: Fix verify ACL condition. The options for the condition are
+ expanded; previously using tainted values was rejected. Fix by using
+ dynamically-created buffers.
+
Exim version 4.94
-----------------
diff --git src/acl.c src/acl.c
index 8619cd5ef..11d1fd028 100644
--- src/acl.c
+++ src/acl.c
@@ -1767,7 +1767,7 @@ switch(vp->value)
/* Remaining items are optional; they apply to sender and recipient
verification, including "header sender" verification. */
-while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+while ((ss = string_nextinlist(&list, &sep, NULL, 0)))
{
if (strcmpic(ss, US"defer_ok") == 0) defer_ok = TRUE;
else if (strcmpic(ss, US"no_details") == 0) no_details = TRUE;
@@ -1804,7 +1804,7 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
uschar * opt;
while (isspace(*sublist)) sublist++;
- while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer))))
+ while ((opt = string_nextinlist(&sublist, &optsep, NULL, 0)))
{
callout_opt_t * op;
double period = 1.0F;
--
2.24.3 (Apple Git-128)

View file

@ -1,48 +0,0 @@
From 5c608b75d5bd734ddca41e4468fb22544ef96265 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sat, 20 Jun 2020 00:54:05 +0100
Subject: [PATCH 14/26] Fix string_copy() macro to not multiple-eval args. Bug
2603
Broken-by: a76d120aed
(cherry picked from commit 80c2ec2e47c556daff00c79ee068ce68f25fd264)
---
doc/ChangeLog | 6 ++++++
src/functions.h | 4 ++--
diff --git doc/ChangeLog doc/ChangeLog
index 859e87b00..1173b3651 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -40,6 +40,12 @@ JH/08 Bug 2598: Fix verify ACL condition. The options for the condition are
expanded; previously using tainted values was rejected. Fix by using
dynamically-created buffers.
+JH/10 Bug 2603: Fix coding of string copying to only evaluate arguments once.
+ Previously a macro used one argument twice; when called with the
+ argument as an expression having side-effects, incorrect operation
+ resulted. Use an inlineable function.
+
+
Exim version 4.94
-----------------
diff --git src/functions.h src/functions.h
index 0028deb0d..0050cdeeb 100644
--- src/functions.h
+++ src/functions.h
@@ -767,9 +767,9 @@ string_copy_trc(const uschar * s, const char * func, int line)
/* Simple string-copy functions maintaining the taint */
#define string_copyn(s, len) \
- string_copyn_taint_trc((s), (len), is_tainted(s), __FUNCTION__, __LINE__)
+ string_copyn_trc((s), (len), __FUNCTION__, __LINE__)
#define string_copy(s) \
- string_copy_taint_trc((s), is_tainted(s), __FUNCTION__, __LINE__)
+ string_copy_trc((s), __FUNCTION__, __LINE__)
/*************************************************
--
2.24.3 (Apple Git-128)

View file

@ -1,118 +0,0 @@
From cdee8a5f76cc013de5622112cd04e42d0dcf333b Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Mon, 22 Jun 2020 17:27:18 +0100
Subject: [PATCH 15/26] Cutthrough: handle request when a callout-hold is
active. Bug 2604
(cherry picked from commit 99bfcf2b678e7bd8125a7eb44409e46549bfc111)
---
doc/ChangeLog | 4 +++
src/acl.c | 50 +++++++++++++++++--------------
src/verify.c | 4 +--
diff --git doc/ChangeLog doc/ChangeLog
index 1173b3651..de11b4f09 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -45,6 +45,10 @@ JH/10 Bug 2603: Fix coding of string copying to only evaluate arguments once.
argument as an expression having side-effects, incorrect operation
resulted. Use an inlineable function.
+JH/11 Bug 2604: Fix request to cutthrough-deliver when a connection is already
+ held open for a verify callout. Previously this wan not accounted for
+ and a corrupt onward SMTP conversation resulted.
+
Exim version 4.94
diff --git src/acl.c src/acl.c
index 11d1fd028..62cb68561 100644
--- src/acl.c
+++ src/acl.c
@@ -3264,37 +3264,41 @@ for (; cb; cb = cb->next)
the case where both sides handle prdr and this-node prdr acl
is "accept" */
ignored = US"PRDR active";
+ else if (f.deliver_freeze)
+ ignored = US"frozen";
+ else if (f.queue_only_policy)
+ ignored = US"queue-only";
+ else if (fake_response == FAIL)
+ ignored = US"fakereject";
+ else if (rcpt_count != 1)
+ ignored = US"nonfirst rcpt";
+ else if (cutthrough.delivery)
+ ignored = US"repeated";
+ else if (cutthrough.callout_hold_only)
+ {
+ DEBUG(D_acl)
+ debug_printf_indent(" cutthrough request upgrades callout hold\n");
+ cutthrough.callout_hold_only = FALSE;
+ cutthrough.delivery = TRUE; /* control accepted */
+ }
else
{
- if (f.deliver_freeze)
- ignored = US"frozen";
- else if (f.queue_only_policy)
- ignored = US"queue-only";
- else if (fake_response == FAIL)
- ignored = US"fakereject";
- else
+ cutthrough.delivery = TRUE; /* control accepted */
+ while (*p == '/')
{
- if (rcpt_count == 1)
+ const uschar * pp = p+1;
+ if (Ustrncmp(pp, "defer=", 6) == 0)
{
- cutthrough.delivery = TRUE; /* control accepted */
- while (*p == '/')
- {
- const uschar * pp = p+1;
- if (Ustrncmp(pp, "defer=", 6) == 0)
- {
- pp += 6;
- if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE;
- /* else if (Ustrncmp(pp, "spool") == 0) ; default */
- }
- else
- while (*pp && *pp != '/') pp++;
- p = pp;
- }
+ pp += 6;
+ if (Ustrncmp(pp, "pass", 4) == 0) cutthrough.defer_pass = TRUE;
+ /* else if (Ustrncmp(pp, "spool") == 0) ; default */
}
else
- ignored = US"nonfirst rcpt";
+ while (*pp && *pp != '/') pp++;
+ p = pp;
}
}
+
DEBUG(D_acl) if (ignored)
debug_printf(" cutthrough request ignored on %s item\n", ignored);
}
diff --git src/verify.c src/verify.c
index fba1f6e9e..5f4181de9 100644
--- src/verify.c
+++ src/verify.c
@@ -875,12 +875,12 @@ tls_retry_connection:
case PENDING_OK: done = TRUE;
new_address_record.result = ccache_accept;
break;
- case FAIL: done = TRUE;
+ case FAIL: done = TRUE;
yield = FAIL;
*failure_ptr = US"recipient";
new_address_record.result = ccache_reject;
break;
- default: break;
+ default: break;
}
break;
--
2.24.3 (Apple Git-128)

View file

@ -1,53 +0,0 @@
From 777ee8ae75277c05fb72cc94f568ba4d2bfe15a6 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 25 Jun 2020 11:16:54 +0100
Subject: [PATCH 16/26] Lookups: Fix "subdir" filter on a dsearch.
(cherry picked from commit e0e21929b7426b9b5bbf5e3747797043801b1151)
---
doc/ChangeLog | 2 ++
src/lookups/dsearch.c | 7 +++----
diff --git doc/ChangeLog doc/ChangeLog
index de11b4f09..bae9abb85 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -49,6 +49,8 @@ JH/11 Bug 2604: Fix request to cutthrough-deliver when a connection is already
held open for a verify callout. Previously this wan not accounted for
and a corrupt onward SMTP conversation resulted.
+JH/13 Fix dsearch "subdir" filter to ignore ".". Previously only ".." was
+ excluded, not matching the documentation.
Exim version 4.94
diff --git src/lookups/dsearch.c src/lookups/dsearch.c
index 455273fb1..501293ac0 100644
--- src/lookups/dsearch.c
+++ src/lookups/dsearch.c
@@ -125,8 +125,7 @@ if ( Ulstat(filename, &statbuf) >= 0
&& S_ISDIR(statbuf.st_mode)
&& ( flags & FILTER_DIR
|| keystring[0] != '.'
- || keystring[1] != '.'
- || keystring[1] && keystring[2]
+ || keystring[1] && keystring[1] != '.'
) ) ) )
{
/* Since the filename exists in the filesystem, we can return a
@@ -135,10 +134,10 @@ if ( Ulstat(filename, &statbuf) >= 0
return OK;
}
-if (errno == ENOENT) return FAIL;
+if (errno == ENOENT || errno == 0) return FAIL;
save_errno = errno;
-*errmsg = string_sprintf("%s: lstat failed", filename);
+*errmsg = string_sprintf("%s: lstat: %s", filename, strerror(errno));
errno = save_errno;
return DEFER;
}
--
2.24.3 (Apple Git-128)

View file

@ -1,59 +0,0 @@
From 2be77199fc9009ab796ad2d67eed20d8da4773c7 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 28 Jun 2020 15:24:21 +0100
Subject: [PATCH 18/26] Sqlite: fix segfault on bad/missing sqlite_dbfile.
Bug 2606
(cherry picked from commit 3d0472791a0928963a3f8184fe28479e80d1a47d)
---
doc/ChangeLog | 3 +++
src/lookups/sqlite.c | 13 ++++++++++---
diff --git doc/ChangeLog doc/ChangeLog
index bae9abb85..8a13bda87 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -52,6 +52,9 @@ JH/11 Bug 2604: Fix request to cutthrough-deliver when a connection is already
JH/13 Fix dsearch "subdir" filter to ignore ".". Previously only ".." was
excluded, not matching the documentation.
+JH/14 Bug 2606: Fix a segfault in sqlite lookups. When no, or a bad, filename
+ was given for the sqlite_dbfile a trap resulted.
+
Exim version 4.94
-----------------
diff --git src/lookups/sqlite.c src/lookups/sqlite.c
index dc4439153..1638ea401 100644
--- src/lookups/sqlite.c
+++ src/lookups/sqlite.c
@@ -24,16 +24,23 @@ sqlite_open(const uschar * filename, uschar ** errmsg)
sqlite3 *db = NULL;
int ret;
-if (!filename || !*filename) filename = sqlite_dbfile;
-if (*filename != '/')
+if (!filename || !*filename)
+ {
+ DEBUG(D_lookup) debug_printf_indent("Using sqlite_dbfile: %s\n", sqlite_dbfile);
+ filename = sqlite_dbfile;
+ }
+if (!filename || *filename != '/')
*errmsg = US"absolute file name expected for \"sqlite\" lookup";
else if ((ret = sqlite3_open(CCS filename, &db)) != 0)
{
*errmsg = (void *)sqlite3_errmsg(db);
+ sqlite3_close(db);
+ db = NULL;
DEBUG(D_lookup) debug_printf_indent("Error opening database: %s\n", *errmsg);
}
-sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout);
+if (db)
+ sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout);
return db;
}
--
2.24.3 (Apple Git-128)

View file

@ -1,52 +0,0 @@
From 5f3e2ac9f39db5c8ef5a408929c8a5aba957b20f Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Mon, 29 Jun 2020 17:26:36 +0100
Subject: [PATCH 19/26] Taint: fix ACL "spam" condition, to permit tainted
name arguments.
Cherry-picked from: 62b2ccce05
---
doc/ChangeLog | 4 ++++
src/spam.c | 5 +----
diff --git doc/ChangeLog doc/ChangeLog
index 8a13bda87..6a867c716 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -55,6 +55,10 @@ JH/13 Fix dsearch "subdir" filter to ignore ".". Previously only ".." was
JH/14 Bug 2606: Fix a segfault in sqlite lookups. When no, or a bad, filename
was given for the sqlite_dbfile a trap resulted.
+JH/15 Fix "spam" ACL condition. Previously, tainted values for the "name"
+ argument resulted in a trap. There is no reason to disallow such; this
+ was a coding error.
+
Exim version 4.94
-----------------
diff --git src/spam.c src/spam.c
index 5eff1ad5c..63ced4f65 100644
--- src/spam.c
+++ src/spam.c
@@ -190,7 +190,6 @@ spam(const uschar **listptr)
int sep = 0;
const uschar *list = *listptr;
uschar *user_name;
-uschar user_name_buffer[128];
unsigned long mbox_size;
FILE *mbox_file;
client_conn_ctx spamd_cctx = {.sock = -1};
@@ -218,9 +217,7 @@ spamd_address_container * sd;
result = 0;
/* find the username from the option list */
-if ((user_name = string_nextinlist(&list, &sep,
- user_name_buffer,
- sizeof(user_name_buffer))) == NULL)
+if (!(user_name = string_nextinlist(&list, &sep, NULL, 0)))
{
/* no username given, this means no scanning should be done */
return FAIL;
--
2.24.3 (Apple Git-128)

View file

@ -1,158 +0,0 @@
From cafcab0848e35047a93a8920b5105baf55f8e702 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Tue, 30 Jun 2020 21:16:42 +0100
Subject: [PATCH 20/26] Fix message-reception clock usage. Bug 2615
Broken-by: 6906c131d1 (4.94)
(cherry picked from commit c9bce82e3064126be34d85280d0a7fbf65b3abec)
---
doc/ChangeLog | 8 ++++++
src/exim.c | 60 +++++++++++++++++++++++++------------------
src/functions.h | 1 +
src/receive.c | 2 +-
diff --git doc/ChangeLog doc/ChangeLog
index 6a867c716..80277f979 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -59,6 +59,14 @@ JH/15 Fix "spam" ACL condition. Previously, tainted values for the "name"
argument resulted in a trap. There is no reason to disallow such; this
was a coding error.
+JH/16 Bug 2615: Fix pause during message reception, on systems that have been
+ suspended/resumed. The Linux CLOCK_MONOTONIC does not account for time
+ spent suspended, ignoring the Posix definition. Previously we assumed
+ it did and a constant offset from real time could be used as a correction.
+ Change to using the same clock source for the start-of-message and the
+ post-message next-tick-wait. Also change to using CLOCK_BOOTTIME if it
+ exists, just to get a clock slightly more aligned to reality.
+
Exim version 4.94
-----------------
diff --git src/exim.c src/exim.c
index 6143fe989..dde991065 100644
--- src/exim.c
+++ src/exim.c
@@ -384,14 +384,20 @@ return 0;
*************************************************/
#ifdef _POSIX_MONOTONIC_CLOCK
-/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */
+# ifdef CLOCK_BOOTTIME
+# define EXIM_CLOCKTYPE CLOCK_BOOTTIME
+# else
+# define EXIM_CLOCKTYPE CLOCK_MONOTONIC
+# endif
+
+/* Amount EXIM_CLOCK is behind realtime, at startup. */
static struct timespec offset_ts;
static void
exim_clock_init(void)
{
struct timeval tv;
-if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return;
+if (clock_gettime(EXIM_CLOCKTYPE, &offset_ts) != 0) return;
(void)gettimeofday(&tv, NULL);
offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec;
offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec;
@@ -402,6 +408,29 @@ offset_ts.tv_nsec += 1000*1000*1000;
#endif
+void
+exim_gettime(struct timeval * tv)
+{
+#ifdef _POSIX_MONOTONIC_CLOCK
+struct timespec now_ts;
+
+if (clock_gettime(EXIM_CLOCKTYPE, &now_ts) == 0)
+ {
+ now_ts.tv_sec += offset_ts.tv_sec;
+ if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
+ {
+ now_ts.tv_sec++;
+ now_ts.tv_nsec -= 1000*1000*1000;
+ }
+ tv->tv_sec = now_ts.tv_sec;
+ tv->tv_usec = now_ts.tv_nsec / 1000;
+ }
+else
+#endif
+ (void)gettimeofday(tv, NULL);
+}
+
+
/* Exim uses a time + a pid to generate a unique identifier in two places: its
message IDs, and in file names for maildir deliveries. Because some OS now
re-use pids within the same second, sub-second times are now being used.
@@ -428,28 +457,9 @@ exim_wait_tick(struct timeval * tgt_tv, int resolution)
struct timeval now_tv;
long int now_true_usec;
-#ifdef _POSIX_MONOTONIC_CLOCK
-struct timespec now_ts;
-
-if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0)
- {
- now_ts.tv_sec += offset_ts.tv_sec;
- if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
- {
- now_ts.tv_sec++;
- now_ts.tv_nsec -= 1000*1000*1000;
- }
- now_tv.tv_sec = now_ts.tv_sec;
- now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution;
- now_tv.tv_usec = now_true_usec;
- }
-else
-#endif
- {
- (void)gettimeofday(&now_tv, NULL);
- now_true_usec = now_tv.tv_usec;
- now_tv.tv_usec = (now_true_usec/resolution) * resolution;
- }
+exim_gettime(&now_tv);
+now_true_usec = now_tv.tv_usec;
+now_tv.tv_usec = (now_true_usec/resolution) * resolution;
while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
{
@@ -1728,7 +1738,7 @@ make quite sure. */
setlocale(LC_ALL, "C");
-/* Get the offset between CLOCK_MONOTONIC and wallclock */
+/* Get the offset between CLOCK_MONOTONIC/CLOCK_BOOTTIME and wallclock */
#ifdef _POSIX_MONOTONIC_CLOCK
exim_clock_init();
diff --git src/functions.h src/functions.h
index 0050cdeeb..8b17531ed 100644
--- src/functions.h
+++ src/functions.h
@@ -234,6 +234,7 @@ extern void msg_event_raise(const uschar *, const address_item *);
extern int exim_chown_failure(int, const uschar*, uid_t, gid_t);
extern const uschar * exim_errstr(int);
extern void exim_exit(int) NORETURN;
+extern void exim_gettimg(struct timeval *);
extern void exim_nullstd(void);
extern void exim_setugid(uid_t, gid_t, BOOL, uschar *);
extern void exim_underbar_exit(int) NORETURN;
diff --git src/receive.c src/receive.c
index 0fbd35f82..0db897e9e 100644
--- src/receive.c
+++ src/receive.c
@@ -1784,7 +1784,7 @@ if (sender_host_address) dmarc_init(); /* initialize libopendmarc */
ids, and fractions of a second are required. See the comments that precede the
message id creation below. */
-(void)gettimeofday(&message_id_tv, NULL);
+exim_gettime(&message_id_tv);
/* For other uses of the received time we can operate with granularity of one
second, and for that we use the global variable received_time. This is for
--
2.24.3 (Apple Git-128)

View file

@ -1,24 +0,0 @@
From 436c0d208b49421d3d126f7c284bc3130b50ff14 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 3 Jul 2020 20:35:58 +0100
Subject: [PATCH 21/26] typoes
---
src/functions.h | 2 +-
diff --git src/functions.h src/functions.h
index 8b17531ed..afe9f1bf4 100644
--- src/functions.h
+++ src/functions.h
@@ -234,7 +234,7 @@ extern void msg_event_raise(const uschar *, const address_item *);
extern int exim_chown_failure(int, const uschar*, uid_t, gid_t);
extern const uschar * exim_errstr(int);
extern void exim_exit(int) NORETURN;
-extern void exim_gettimg(struct timeval *);
+extern void exim_gettime(struct timeval *);
extern void exim_nullstd(void);
extern void exim_setugid(uid_t, gid_t, BOOL, uschar *);
extern void exim_underbar_exit(int) NORETURN;
--
2.24.3 (Apple Git-128)

View file

@ -1,193 +0,0 @@
From de99158d2927863a6826c9f5f2c6fa4547326e75 Mon Sep 17 00:00:00 2001
From: Guillaume Outters <guillaume-exim@outters.eu>
Date: Mon, 6 Jul 2020 22:31:51 +0100
Subject: [PATCH 22/26] Fix DKIM signing to always ;-terminate. Bug 2295
(cherry picked from commit 65fe780259d0009354b5dfc9a4f1b48ad6513db2)
---
doc/ChangeLog | 5 ++
src/pdkim/pdkim.c | 116 ++++++++++++++++--------------------------
diff --git doc/ChangeLog doc/ChangeLog
index 80277f979..08c6638a9 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -67,6 +67,11 @@ JH/16 Bug 2615: Fix pause during message reception, on systems that have been
post-message next-tick-wait. Also change to using CLOCK_BOOTTIME if it
exists, just to get a clock slightly more aligned to reality.
+JH/17 Bug 2295: Fix DKIM signing to always semicolon-terminate. Although the
+ RFC says it is optional some validators care. The missing char was not
+ intended but triggered by a line-wrap alignement. Discovery and fix by
+ Guillaume Outters, hacked on by JH.
+
Exim version 4.94
-----------------
diff --git src/pdkim/pdkim.c src/pdkim/pdkim.c
index 7712409b5..3a6ca4e91 100644
--- src/pdkim/pdkim.c
+++ src/pdkim/pdkim.c
@@ -1111,14 +1111,14 @@ return string_catn(str, US"\r\n\t", 3);
/*
* RFC 5322 specifies that header line length SHOULD be no more than 78
- * lets make it so!
* pdkim_headcat
*
- * returns uschar * (not nul-terminated)
+ * Returns gstring (not nul-terminated) appending to one supplied
*
* col: this int holds and receives column number (octets since last '\n')
* str: partial string to append to
- * pad: padding, split line or space after before or after eg: ";"
+ * pad: padding, split line or space after before or after eg: ";".
+ * Only the initial charater is used.
* intro: - must join to payload eg "h=", usually the tag name
* payload: eg base64 data - long data can be split arbitrarily.
*
@@ -1127,7 +1127,7 @@ return string_catn(str, US"\r\n\t", 3);
* pairs and inside long values. it also always spaces or breaks after the
* "pad"
*
- * no guarantees are made for output given out-of range input. like tag
+ * No guarantees are made for output given out-of range input. like tag
* names longer than 78, or bogus col. Input is assumed to be free of line breaks.
*/
@@ -1135,92 +1135,64 @@ static gstring *
pdkim_headcat(int * col, gstring * str,
const uschar * pad, const uschar * intro, const uschar * payload)
{
-size_t l;
+int len, chomp, padded = 0;
-if (pad)
- {
- l = Ustrlen(pad);
- if (*col + l > 78)
- str = pdkim_hdr_cont(str, col);
- str = string_catn(str, pad, l);
- *col += l;
- }
-
-l = (pad?1:0) + (intro?Ustrlen(intro):0);
+/* If we can fit at least the pad at the end of current line, do it now.
+Otherwise, wrap if there is a pad. */
-if (*col + l > 78)
- { /*can't fit intro - start a new line to make room.*/
- str = pdkim_hdr_cont(str, col);
- l = intro?Ustrlen(intro):0;
- }
-
-l += payload ? Ustrlen(payload):0 ;
-
-while (l>77)
- { /* this fragment will not fit on a single line */
- if (pad)
- {
- str = string_catn(str, US" ", 1);
- *col += 1;
- pad = NULL; /* only want this once */
- l--;
- }
-
- if (intro)
- {
- size_t sl = Ustrlen(intro);
-
- str = string_catn(str, intro, sl);
- *col += sl;
- l -= sl;
- intro = NULL; /* only want this once */
- }
-
- if (payload)
+if (pad)
+ if (*col + 1 <= 78)
{
- size_t sl = Ustrlen(payload);
- size_t chomp = *col+sl < 77 ? sl : 78-*col;
-
- str = string_catn(str, payload, chomp);
- *col += chomp;
- payload += chomp;
- l -= chomp-1;
+ str = string_catn(str, pad, 1);
+ (*col)++;
+ pad = NULL;
+ padded = 1;
}
+ else
+ str = pdkim_hdr_cont(str, col);
- /* the while precondition tells us it didn't fit. */
- str = pdkim_hdr_cont(str, col);
- }
+/* Special case: if the whole addition does not fit at the end of the current
+line, but could fit on a new line, wrap to give it its full, dedicated line. */
-if (*col + l > 78)
+len = (pad ? 2 : padded)
+ + (intro ? Ustrlen(intro) : 0)
+ + (payload ? Ustrlen(payload) : 0);
+if (len <= 77 && *col+len > 78)
{
str = pdkim_hdr_cont(str, col);
- pad = NULL;
+ padded = 0;
}
+/* Either we already dealt with the pad or we know there is room */
+
if (pad)
{
+ str = string_catn(str, pad, 1);
str = string_catn(str, US" ", 1);
- *col += 1;
- pad = NULL;
+ *col += 2;
}
-
-if (intro)
+else if (padded && *col < 78)
{
- size_t sl = Ustrlen(intro);
-
- str = string_catn(str, intro, sl);
- *col += sl;
- l -= sl;
- intro = NULL;
+ str = string_catn(str, US" ", 1);
+ (*col)++;
}
-if (payload)
- {
- size_t sl = Ustrlen(payload);
+/* Call recursively with intro as payload: it gets the same, special treatment
+(that is, not split if < 78). */
- str = string_catn(str, payload, sl);
- *col += sl;
- }
+if (intro)
+ str = pdkim_headcat(col, str, NULL, NULL, intro);
+
+if (payload)
+ for (len = Ustrlen(payload); len; len -= chomp)
+ {
+ if (*col >= 78)
+ str = pdkim_hdr_cont(str, col);
+ chomp = *col+len > 78 ? 78 - *col : len;
+ str = string_catn(str, payload, chomp);
+ *col += chomp;
+ payload += chomp;
+ }
return str;
}
--
2.24.3 (Apple Git-128)

View file

@ -1,366 +0,0 @@
From 86ba540670517109809d93cd73716d320a6a0923 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 9 Jul 2020 15:30:55 +0100
Subject: [PATCH 23/26] Fix taint trap in parse_fix_phrase(). Bug 2617
(cherry picked from commit 3c90bbcdc7cf73298156f7bcd5f5e750e7814e72)
---
doc/ChangeLog | 6 +++
src/acl.c | 3 +-
src/exim.c | 3 +-
src/expand.c | 5 +--
src/functions.h | 4 +-
src/parse.c | 89 +++++++++++++++----------------------------
src/rewrite.c | 9 +----
src/sieve.c | 17 ++-------
diff --git doc/ChangeLog doc/ChangeLog
index 08c6638a9..a1f39459e 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -72,6 +72,12 @@ JH/17 Bug 2295: Fix DKIM signing to always semicolon-terminate. Although the
intended but triggered by a line-wrap alignement. Discovery and fix by
Guillaume Outters, hacked on by JH.
+JH/18 Bug 2617: Fix a taint trap in parse_fix_phrase(). Previously when the
+ name being quoted was tainted a trap would be taken. Fix by using
+ dynamicaly created buffers. The routine could have been called by a
+ rewrite with the "h" flag, by using the "-F" command-line option, or
+ by using a "name=" option on a control=submission ACL modifier.
+
Exim version 4.94
-----------------
diff --git src/acl.c src/acl.c
index 62cb68561..105b1b473 100644
--- src/acl.c
+++ src/acl.c
@@ -3199,8 +3199,7 @@ for (; cb; cb = cb->next)
{
const uschar *pp = p + 6;
while (*pp) pp++;
- submission_name = string_copy(parse_fix_phrase(p+6, pp-p-6,
- big_buffer, big_buffer_size));
+ submission_name = parse_fix_phrase(p+6, pp-p-6);
p = pp;
}
else break;
diff --git src/exim.c src/exim.c
index dde991065..ac0ff5523 100644
--- src/exim.c
+++ src/exim.c
@@ -4769,8 +4769,7 @@ if (originator_login == NULL || f.running_in_test_harness)
/* Ensure that the user name is in a suitable form for use as a "phrase" in an
RFC822 address.*/
-originator_name = string_copy(parse_fix_phrase(originator_name,
- Ustrlen(originator_name), big_buffer, big_buffer_size));
+originator_name = parse_fix_phrase(originator_name, Ustrlen(originator_name));
/* If a message is created by this call of Exim, the uid/gid of its originator
are those of the caller. These values are overridden if an existing message is
diff --git src/expand.c src/expand.c
index 6ed22c14d..791222324 100644
--- src/expand.c
+++ src/expand.c
@@ -7571,13 +7571,10 @@ while (*s != 0)
prescribed by the RFC, if there are characters that need to be encoded */
case EOP_RFC2047:
- {
- uschar buffer[2048];
yield = string_cat(yield,
parse_quote_2047(sub, Ustrlen(sub), headers_charset,
- buffer, sizeof(buffer), FALSE));
+ FALSE));
continue;
- }
/* RFC 2047 decode */
diff --git src/functions.h src/functions.h
index afe9f1bf4..f4d1622dc 100644
--- src/functions.h
+++ src/functions.h
@@ -366,9 +366,9 @@ extern int parse_forward_list(uschar *, int, address_item **, uschar **,
const uschar *, uschar *, error_block **);
extern uschar *parse_find_address_end(uschar *, BOOL);
extern uschar *parse_find_at(uschar *);
-extern const uschar *parse_fix_phrase(const uschar *, int, uschar *, int);
+extern const uschar *parse_fix_phrase(const uschar *, int);
extern uschar *parse_message_id(uschar *, uschar **, uschar **);
-extern const uschar *parse_quote_2047(const uschar *, int, uschar *, uschar *, int, BOOL);
+extern const uschar *parse_quote_2047(const uschar *, int, uschar *, BOOL);
extern uschar *parse_date_time(uschar *str, time_t *t);
extern int vaguely_random_number(int);
#ifndef DISABLE_TLS
diff --git src/parse.c src/parse.c
index e3b471f1a..3ea758ac9 100644
--- src/parse.c
+++ src/parse.c
@@ -843,8 +843,7 @@ return NULL;
/* This function is used for quoting text in headers according to RFC 2047.
If the only characters that strictly need quoting are spaces, we return the
-original string, unmodified. If a quoted string is too long for the buffer, it
-is truncated. (This shouldn't happen: this is normally handling short strings.)
+original string, unmodified.
Hmmph. As always, things get perverted for other uses. This function was
originally for the "phrase" part of addresses. Now it is being used for much
@@ -856,77 +855,57 @@ Arguments:
chars
len the length of the string
charset the name of the character set; NULL => iso-8859-1
- buffer the buffer to put the answer in
- buffer_size the size of the buffer
fold if TRUE, a newline is inserted before the separating space when
more than one encoded-word is generated
Returns: pointer to the original string, if no quoting needed, or
- pointer to buffer containing the quoted string, or
- a pointer to "String too long" if the buffer can't even hold
- the introduction
+ pointer to allocated memory containing the quoted string
*/
const uschar *
-parse_quote_2047(const uschar *string, int len, uschar *charset, uschar *buffer,
- int buffer_size, BOOL fold)
+parse_quote_2047(const uschar *string, int len, uschar *charset, BOOL fold)
{
-const uschar *s = string;
-uschar *p, *t;
-int hlen;
+const uschar * s = string;
+int hlen, l;
BOOL coded = FALSE;
BOOL first_byte = FALSE;
+gstring * g =
+ string_fmt_append(NULL, "=?%s?Q?", charset ? charset : US"iso-8859-1");
-if (!charset) charset = US"iso-8859-1";
+hlen = l = g->ptr;
-/* We don't expect this to fail! */
-
-if (!string_format(buffer, buffer_size, "=?%s?Q?", charset))
- return US"String too long";
-
-hlen = Ustrlen(buffer);
-t = buffer + hlen;
-p = buffer;
-
-for (; len > 0; len--)
+for (s = string; len > 0; s++, len--)
{
- int ch = *s++;
- if (t > buffer + buffer_size - hlen - 8) break;
+ int ch = *s;
- if ((t - p > 67) && !first_byte)
+ if (g->ptr - l > 67 && !first_byte)
{
- *t++ = '?';
- *t++ = '=';
- if (fold) *t++ = '\n';
- *t++ = ' ';
- p = t;
- Ustrncpy(p, buffer, hlen);
- t += hlen;
+ g = fold ? string_catn(g, US"?=\n ", 4) : string_catn(g, US"?= ", 3);
+ l = g->ptr;
+ g = string_catn(g, g->s, hlen);
}
- if (ch < 33 || ch > 126 ||
- Ustrchr("?=()<>@,;:\\\".[]_", ch) != NULL)
+ if ( ch < 33 || ch > 126
+ || Ustrchr("?=()<>@,;:\\\".[]_", ch) != NULL)
{
if (ch == ' ')
{
- *t++ = '_';
+ g = string_catn(g, US"_", 1);
first_byte = FALSE;
}
else
{
- t += sprintf(CS t, "=%02X", ch);
+ g = string_fmt_append(g, "=%02X", ch);
coded = TRUE;
first_byte = !first_byte;
}
}
- else { *t++ = ch; first_byte = FALSE; }
+ else
+ { g = string_catn(g, s, 1); first_byte = FALSE; }
}
-*t++ = '?';
-*t++ = '=';
-*t = 0;
-
-return coded ? buffer : string;
+g = string_catn(g, US"?=", 2);
+return coded ? string_from_gstring(g) : string;
}
@@ -969,32 +948,25 @@ August 2000: Additional code added:
We *could* use this for all cases, getting rid of the messy original code,
but leave it for now. It would complicate simple cases like "John Q. Smith".
-The result is passed back in the buffer; it is usually going to be added to
-some other string. In order to be sure there is going to be no overflow,
-restrict the length of the input to 1/4 of the buffer size - this allows for
-every single character to be quoted or encoded without overflowing, and that
-wouldn't happen because of amalgamation. If the phrase is too long, return a
-fixed string.
+The result is passed back in allocated memory.
Arguments:
phrase an RFC822 phrase
len the length of the phrase
- buffer a buffer to put the result in
- buffer_size the size of the buffer
Returns: the fixed RFC822 phrase
*/
const uschar *
-parse_fix_phrase(const uschar *phrase, int len, uschar *buffer, int buffer_size)
+parse_fix_phrase(const uschar *phrase, int len)
{
int ch, i;
BOOL quoted = FALSE;
const uschar *s, *end;
+uschar * buffer;
uschar *t, *yield;
while (len > 0 && isspace(*phrase)) { phrase++; len--; }
-if (len > buffer_size/4) return US"Name too long";
/* See if there are any non-printing characters, and if so, use the RFC 2047
encoding for the whole thing. */
@@ -1002,11 +974,13 @@ encoding for the whole thing. */
for (i = 0, s = phrase; i < len; i++, s++)
if ((*s < 32 && *s != '\t') || *s > 126) break;
-if (i < len) return parse_quote_2047(phrase, len, headers_charset, buffer,
- buffer_size, FALSE);
+if (i < len)
+ return parse_quote_2047(phrase, len, headers_charset, FALSE);
/* No non-printers; use the RFC 822 quoting rules */
+buffer = store_get(len*4, is_tainted(phrase));
+
s = phrase;
end = s + len;
yield = t = buffer + 1;
@@ -1173,6 +1147,7 @@ while (s < end)
}
*t = 0;
+store_release_above(t+1);
return yield;
}
@@ -2102,7 +2077,6 @@ int main(void)
{
int start, end, domain;
uschar buffer[1024];
-uschar outbuff[1024];
big_buffer = store_malloc(big_buffer_size);
@@ -2115,8 +2089,7 @@ while (Ufgets(buffer, sizeof(buffer), stdin) != NULL)
{
buffer[Ustrlen(buffer)-1] = 0;
if (buffer[0] == 0) break;
- printf("%s\n", CS parse_fix_phrase(buffer, Ustrlen(buffer), outbuff,
- sizeof(outbuff)));
+ printf("%s\n", CS parse_fix_phrase(buffer, Ustrlen(buffer)));
}
printf("Testing parse_extract_address without group syntax and without UTF-8\n");
diff --git src/rewrite.c src/rewrite.c
index f942bec05..7bff8a273 100644
--- src/rewrite.c
+++ src/rewrite.c
@@ -292,16 +292,11 @@ for (rewrite_rule * rule = rewrite_rules;
uschar *p1 = new + start - 1;
uschar *p2 = new + end + 1;
const uschar *pf1, *pf2;
- uschar buff1[256], buff2[256];
while (p1 > new && p1[-1] == ' ') p1--;
- pf1 = parse_fix_phrase(new, p1 - new, buff1, sizeof(buff1));
+ pf1 = parse_fix_phrase(new, p1 - new);
while (*p2 == ' ') p2++;
- pf2 = parse_fix_phrase(p2, Ustrlen(p2), buff2, sizeof(buff2));
-
- /* Note that pf1 and pf2 are NOT necessarily buff1 and buff2. For
- a non-RFC 2047 phrase that does not need to be RFC 2822 quoted, they
- will be buff1+1 and buff2+1. */
+ pf2 = parse_fix_phrase(p2, Ustrlen(p2));
start = Ustrlen(pf1) + start + new - p1;
end = start + Ustrlen(newparsed);
diff --git src/sieve.c src/sieve.c
index 18aa3e609..2038f336b 100644
--- src/sieve.c
+++ src/sieve.c
@@ -3087,11 +3087,8 @@ while (*filter->pc)
if ((pid = child_open_exim2(&fd, envelope_from, envelope_from,
US"sieve-notify")) >= 1)
{
- FILE *f;
- uschar *buffer;
- int buffer_capacity;
+ FILE * f = fdopen(fd, "wb");
- f = fdopen(fd, "wb");
fprintf(f,"From: %s\n", from.length == -1
? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
: from.character);
@@ -3104,12 +3101,9 @@ while (*filter->pc)
message.character=US"Notification";
message.length=Ustrlen(message.character);
}
- /* Allocation is larger than necessary, but enough even for split MIME words */
- buffer_capacity = 32 + 4*message.length;
- buffer=store_get(buffer_capacity, TRUE);
if (message.length != -1)
fprintf(f, "Subject: %s\n", parse_quote_2047(message.character,
- message.length, US"utf-8", buffer, buffer_capacity, TRUE));
+ message.length, US"utf-8", TRUE));
fprintf(f,"\n");
if (body.length>0) fprintf(f,"%s\n",body.character);
fflush(f);
@@ -3263,8 +3257,6 @@ while (*filter->pc)
if (exec)
{
address_item *addr;
- uschar *buffer;
- int buffer_capacity;
md5 base;
uschar digest[16];
uschar hexdigest[33];
@@ -3342,11 +3334,8 @@ while (*filter->pc)
addr->reply->from = expand_string(US"$local_part@$domain");
else
addr->reply->from = from.character;
- /* Allocation is larger than necessary, but enough even for split MIME words */
- buffer_capacity=32+4*subject.length;
- buffer = store_get(buffer_capacity, is_tainted(subject.character));
/* deconst cast safe as we pass in a non-const item */
- addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity, TRUE);
+ addr->reply->subject = US parse_quote_2047(subject.character, subject.length, US"utf-8", TRUE);
addr->reply->oncelog = string_from_gstring(once);
addr->reply->once_repeat=days*86400;
--
2.24.3 (Apple Git-128)

View file

@ -1,74 +0,0 @@
From 9681a2140b43cfc028e61b4e7ffb13539cecffe5 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Mon, 13 Jul 2020 13:46:14 +0100
Subject: [PATCH 24/26] Taint: fix ACL "spam" condition, to permit tainted
name arguments
Follow-on from: 62b2ccce05
(cherry picked from commit 532800c8bf0e4bc2c27739477e70e0d7eef7df21)
---
doc/ChangeLog | 6 +++---
src/spam.c | 15 +++++++--------
diff --git doc/ChangeLog doc/ChangeLog
index a1f39459e..aaea04caf 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -55,9 +55,9 @@ JH/13 Fix dsearch "subdir" filter to ignore ".". Previously only ".." was
JH/14 Bug 2606: Fix a segfault in sqlite lookups. When no, or a bad, filename
was given for the sqlite_dbfile a trap resulted.
-JH/15 Fix "spam" ACL condition. Previously, tainted values for the "name"
- argument resulted in a trap. There is no reason to disallow such; this
- was a coding error.
+JH/15 Bug 2620: Fix "spam" ACL condition. Previously, tainted values for the
+ "name" argument resulted in a trap. There is no reason to disallow such;
+ this was a coding error.
JH/16 Bug 2615: Fix pause during message reception, on systems that have been
suspended/resumed. The Linux CLOCK_MONOTONIC does not account for time
diff --git src/spam.c src/spam.c
index 63ced4f65..340f8b92f 100644
--- src/spam.c
+++ src/spam.c
@@ -18,7 +18,7 @@ uschar spam_score_int_buffer[16];
uschar spam_bar_buffer[128];
uschar spam_action_buffer[32];
uschar spam_report_buffer[32600];
-uschar prev_user_name[128] = "";
+uschar * prev_user_name = NULL;
int spam_ok = 0;
int spam_rc = 0;
uschar *prev_spamd_address_work = NULL;
@@ -393,13 +393,12 @@ if (sd->is_rspamd)
}
else
{ /* spamassassin variant */
- (void)string_format(spamd_buffer,
- sizeof(spamd_buffer),
- "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n",
- user_name,
- mbox_size);
+ int n;
+ uschar * s = string_sprintf(
+ "REPORT SPAMC/1.2\r\nUser: %s\r\nContent-length: %ld\r\n\r\n%n",
+ user_name, mbox_size, &n);
/* send our request */
- wrote = send(spamd_cctx.sock, spamd_buffer, Ustrlen(spamd_buffer), 0);
+ wrote = send(spamd_cctx.sock, s, n, 0);
}
if (wrote == -1)
@@ -630,7 +629,7 @@ if (spamd_address_work != spamd_address)
prev_spamd_address_work = string_copy(spamd_address_work);
/* remember user name and "been here" for it */
-Ustrcpy(prev_user_name, user_name);
+prev_user_name = user_name;
spam_ok = 1;
return override
--
2.24.3 (Apple Git-128)

View file

@ -1,79 +0,0 @@
From 81cc39a7f5c17099f93b5c611bde5f58daaab71b Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 16 Jul 2020 23:45:55 +0200
Subject: [PATCH 25/26] Fix debug_print_socket()
debug_print_socket() crashed on AF_UNIX sockets
---
src/debug.c | 34 +++++++++++++++++++---------------
diff --git src/debug.c src/debug.c
index 3a7d6a6f5..acc723a29 100644
--- src/debug.c
+++ src/debug.c
@@ -328,20 +328,21 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
gstring * g = NULL;
int val;
socklen_t vlen = sizeof(val);
- struct sockaddr a;
+ struct sockaddr_storage a;
socklen_t alen = sizeof(a);
struct sockaddr_in * sinp = (struct sockaddr_in *)&a;
struct sockaddr_in6 * sin6p = (struct sockaddr_in6 *)&a;
- struct sockaddr_un * sa_unp ; (struct sockaddr_un *)&a;
+ struct sockaddr_un * sunp = (struct sockaddr_un *)&a;
- if (getsockname(fd, &a, &alen) == 0)
- switch (sinp->sin_family)
+ if (getsockname(fd, (struct sockaddr*)&a, &alen) == 0)
+ switch (a.ss_family)
{
case AF_INET:
g = string_cat(g, US" domain AF_INET");
g = string_fmt_append(g, " lcl [%s]:%u",
inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
- if (getpeername(fd, &a, &alen) == 0)
+ alen = sizeof(*sinp);
+ if (getpeername(fd, sinp, &alen) == 0)
g = string_fmt_append(g, " rmt [%s]:%u",
inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
break;
@@ -352,22 +353,25 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
g = string_fmt_append(g, " lcl [%s]:%u",
inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
ntohs(sin6p->sin6_port));
- if (getpeername(fd, &a, &alen) == 0)
+ alen = sizeof(*sin6p);
+ if (getpeername(fd, sin6p, &alen) == 0)
g = string_fmt_append(g, " rmt [%s]:%u",
inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
ntohs(sin6p->sin6_port));
break;
}
case AF_UNIX:
- g = string_cat(g, US" domain AF_UNIX");
- g = string_fmt_append(g, " lcl %s%s",
- sa_unp->sun_path[0] ? US"" : US"@",
- sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1);
- if (getpeername(fd, &a, &alen) == 0)
- g = string_fmt_append(g, " rmt %s%s",
- sa_unp->sun_path[0] ? US"" : US"@",
- sa_unp->sun_path[0] ? sa_unp->sun_path : sa_unp->sun_path+1);
- break;
+ g = string_cat(g, US"domain AF_UNIX");
+ if (alen > sizeof(sa_family_t)) /* not unix(7) "unnamed socket" */
+ g = string_fmt_append(g, " lcl %s%s",
+ sunp->sun_path[0] ? US"" : US"@",
+ sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
+ alen = sizeof(*sunp);
+ if (getpeername(fd, sunp, &alen) == 0)
+ g = string_fmt_append(g, " rmt %s%s",
+ sunp->sun_path[0] ? US"" : US"@",
+ sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
+ break;
default:
g = string_fmt_append(g, " domain %u", sinp->sin_family);
break;
--
2.24.3 (Apple Git-128)

View file

@ -1,51 +0,0 @@
From 73b748711caf8a4b18dd1c0d7c662b5d57798dfe Mon Sep 17 00:00:00 2001
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
Date: Thu, 16 Jul 2020 23:53:27 +0200
Subject: [PATCH 26/26] debug_print_socket(): output formatting
---
src/debug.c | 8 ++++----
diff --git src/debug.c src/debug.c
index acc723a29..6d6132e39 100644
--- src/debug.c
+++ src/debug.c
@@ -338,7 +338,7 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
switch (a.ss_family)
{
case AF_INET:
- g = string_cat(g, US" domain AF_INET");
+ g = string_cat(g, US"domain AF_INET");
g = string_fmt_append(g, " lcl [%s]:%u",
inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
alen = sizeof(*sinp);
@@ -349,7 +349,7 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
case AF_INET6:
{
uschar buf[46];
- g = string_cat(g, US" domain AF_INET6");
+ g = string_cat(g, US"domain AF_INET6");
g = string_fmt_append(g, " lcl [%s]:%u",
inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
ntohs(sin6p->sin6_port));
@@ -373,7 +373,7 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
break;
default:
- g = string_fmt_append(g, " domain %u", sinp->sin_family);
+ g = string_fmt_append(g, "domain %u", sinp->sin_family);
break;
}
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &val, &vlen) == 0)
@@ -388,7 +388,7 @@ if (fstat(fd, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK)
{
struct protoent * p = getprotobynumber(val);
g = p
- ? string_fmt_append(g, " proto %s\n", p->p_name)
+ ? string_fmt_append(g, " proto %s", p->p_name)
: string_fmt_append(g, " proto %d", val);
}
#endif
--
2.24.3 (Apple Git-128)

View file

@ -1,54 +0,0 @@
From d08a4ba2c5216195c107b123842da17bc1b0559f Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 9 Aug 2020 01:38:00 +0100
Subject: [PATCH 27/37] Fix spelling of local_part_data in docs and debug
output
(cherry picked from commit ccec2d82e2fda6d764f6cd1a9dd21c4f6285b614)
---
doc/ChangeLog | 2 +-
doc/NewStuff | 2 +-
src/routers/rf_queue_add.c | 2 +-
diff --git doc/ChangeLog doc/ChangeLog
index aaea04caf..703f4b9ee 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -6700,7 +6700,7 @@ Exim version 4.31
same list, then the first domain was re-checked, the value of $domain_data
after the final check could be wrong. In particular, if the second check
failed, it could be set empty. This bug probably also applied to
- $localpart_data.
+ $local_part_data.
41. The strip_trailing_dot option was not being applied to the address given
with the -f command-line option.
diff --git doc/NewStuff doc/NewStuff
index 43e170e11..16dec8808 100644
--- doc/NewStuff
+++ doc/NewStuff
@@ -57,7 +57,7 @@ Version 4.94
16. An option on all single-key lookups, to return (on a hit) a de-tainted
version of the lookup key rather than the looked-up data.
-17. $domain_data and $localpart_data are now set by all list-match successes.
+17. $domain_data and $local_part_data are now set by all list-match successes.
Previously only list items that performed lookups did so.
Also, matching list items that are tail-match or RE-match now set the
numeric variables $0 (etc) in the same way os other RE matches.
diff --git src/routers/rf_queue_add.c src/routers/rf_queue_add.c
index 938eee30a..4dab60dfe 100644
--- src/routers/rf_queue_add.c
+++ src/routers/rf_queue_add.c
@@ -98,7 +98,7 @@ DEBUG(D_route)
" errors_to=%s\n",
addr->transport ? addr->transport->name : US"<unset>",
addr->local_part, addr->domain, addr->prop.errors_address);
- debug_printf(" domain_data=%s localpart_data=%s\n", addr->prop.domain_data,
+ debug_printf(" domain_data=%s local_part_data=%s\n", addr->prop.domain_data,
addr->prop.localpart_data);
}
--
2.28.0

View file

@ -1,216 +0,0 @@
From 18a352ae8a799bb7be3a03b14bbf3ce9e0ba4945 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 14 Aug 2020 13:09:53 +0100
Subject: [PATCH 28/37] Fix ${readsocket } eol-replacement. Bug 2630
(cherry picked from commit 7f83b348ccf4cd815e9758ab9ca1012e66324e9d)
---
doc/ChangeLog | 4 ++++
src/expand.c | 11 +++++++----
src/functions.h | 2 +-
src/lookups/readsock.c | 6 ++++--
src/macros.h | 6 ++++--
src/readconf.c | 4 ++--
src/string.c | 30 +++++++++++++++++-----------
diff --git doc/ChangeLog doc/ChangeLog
index 703f4b9ee..2d2dc1f9f 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -78,6 +78,10 @@ JH/18 Bug 2617: Fix a taint trap in parse_fix_phrase(). Previously when the
rewrite with the "h" flag, by using the "-F" command-line option, or
by using a "name=" option on a control=submission ACL modifier.
+JH/21 Bug 2630: Fix eol-replacement string for the ${readsocket } expansion.
+ Previously when a whitespace character was specified it was not inserted
+ after removing the newline.
+
Exim version 4.94
-----------------
diff --git src/expand.c src/expand.c
index 791222324..bb9fd79ef 100644
--- src/expand.c
+++ src/expand.c
@@ -4920,7 +4920,7 @@ while (*s != 0)
{
expand_string_message =
string_sprintf("lookup of \"%s\" gave DEFER: %s",
- string_printing2(key, FALSE), search_error_message);
+ string_printing2(key, SP_TAB), search_error_message);
goto EXPAND_FAILED;
}
if (expand_setup > 0) expand_nmax = expand_setup;
@@ -5334,11 +5334,14 @@ while (*s != 0)
while ((item = string_nextinlist(&list, &sep, NULL, 0)))
g = string_append_listele(g, ',', item);
- /* possibly plus an EOL string */
+ /* possibly plus an EOL string. Process with escapes, to protect
+ from list-processing. The only current user of eol= in search
+ options is the readsock expansion. */
+
if (sub_arg[3] && *sub_arg[3])
g = string_append_listele(g, ',',
- string_sprintf("eol=%s", sub_arg[3]));
-
+ string_sprintf("eol=%s",
+ string_printing2(sub_arg[3], SP_TAB|SP_SPACE)));
}
/* Gat a (possibly cached) handle for the connection */
diff --git src/functions.h src/functions.h
index f4d1622dc..51bb17a09 100644
--- src/functions.h
+++ src/functions.h
@@ -529,7 +529,7 @@ extern int string_is_ip_address(const uschar *, int *);
#ifdef SUPPORT_I18N
extern BOOL string_is_utf8(const uschar *);
#endif
-extern const uschar *string_printing2(const uschar *, BOOL);
+extern const uschar *string_printing2(const uschar *, int);
extern uschar *string_split_message(uschar *);
extern uschar *string_unprinting(uschar *);
#ifdef SUPPORT_I18N
diff --git src/lookups/readsock.c src/lookups/readsock.c
index c2088b7a5..cfc9b4ad8 100644
--- src/lookups/readsock.c
+++ src/lookups/readsock.c
@@ -186,7 +186,9 @@ FILE * fp;
gstring * yield;
int ret = DEFER;
-DEBUG(D_lookup) debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n", filename, keystring, length, opts);
+DEBUG(D_lookup)
+ debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n",
+ filename, keystring, length, opts);
/* Parse options */
@@ -200,7 +202,7 @@ if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); )
lf.do_tls = TRUE;
#endif
else if (Ustrncmp(s, "eol=", 4) == 0)
- eol = s + 4;
+ eol = string_unprinting(s + 4);
else if (Ustrcmp(s, "cache=yes") == 0)
lf.cache = TRUE;
else if (Ustrcmp(s, "send=no") == 0)
diff --git src/macros.h src/macros.h
index a507bbf83..2378773cb 100644
--- src/macros.h
+++ src/macros.h
@@ -41,9 +41,11 @@ manipulate them. */
/* For almost all calls to convert things to printing characters, we want to
-allow tabs. A macro just makes life a bit easier. */
+allow tabs & spaces. A macro just makes life a bit easier. */
-#define string_printing(s) string_printing2((s), TRUE)
+#define string_printing(s) string_printing2((s), 0)
+#define SP_TAB BIT(0)
+#define SP_SPACE BIT(1)
/* We need a special return code for "no recipients and failed to send an error
diff --git src/readconf.c src/readconf.c
index 0d0769c88..948fa2403 100644
--- src/readconf.c
+++ src/readconf.c
@@ -1546,7 +1546,7 @@ if (flags & opt_fn_print)
{
if (flags & opt_fn_print_label) printf("%s = ", name);
printf("%s\n", smtp_receive_timeout_s
- ? string_printing2(smtp_receive_timeout_s, FALSE)
+ ? string_printing2(smtp_receive_timeout_s, SP_TAB)
: readconf_printtime(smtp_receive_timeout));
}
else if (*str == '$')
@@ -2463,7 +2463,7 @@ switch(ol->type & opt_mask)
case opt_rewrite: /* Show the text value */
s = *(USS value);
if (!no_labels) printf("%s = ", name);
- printf("%s\n", s ? string_printing2(s, FALSE) : US"");
+ printf("%s\n", s ? string_printing2(s, SP_TAB) : US"");
break;
case opt_int:
diff --git src/string.c src/string.c
index 5acee1b00..f91a6a428 100644
--- src/string.c
+++ src/string.c
@@ -281,17 +281,17 @@ return ch;
/* This function is called for critical strings. It checks for any
non-printing characters, and if any are found, it makes a new copy
of the string with suitable escape sequences. It is most often called by the
-macro string_printing(), which sets allow_tab TRUE.
+macro string_printing(), which sets flags to 0.
Arguments:
s the input string
- allow_tab TRUE to allow tab as a printing character
+ flags Bit 0: convert tabs. Bit 1: convert spaces.
Returns: string with non-printers encoded as printing sequences
*/
const uschar *
-string_printing2(const uschar *s, BOOL allow_tab)
+string_printing2(const uschar *s, int flags)
{
int nonprintcount = 0;
int length = 0;
@@ -301,7 +301,10 @@ uschar *ss, *tt;
while (*t != 0)
{
int c = *t++;
- if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++;
+ if ( !mac_isprint(c)
+ || flags & SP_TAB && c == '\t'
+ || flags & SP_SPACE && c == ' '
+ ) nonprintcount++;
length++;
}
@@ -310,17 +313,19 @@ if (nonprintcount == 0) return s;
/* Get a new block of store guaranteed big enough to hold the
expanded string. */
-ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
+tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
/* Copy everything, escaping non printers. */
-t = s;
-tt = ss;
-
-while (*t != 0)
+for (t = s; *t; )
{
int c = *t;
- if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else
+ if ( mac_isprint(c)
+ && (!(flags & SP_TAB) || c != '\t')
+ && (!(flags & SP_SPACE) || c != ' ')
+ )
+ *tt++ = *t++;
+ else
{
*tt++ = '\\';
switch (*t)
@@ -947,7 +952,10 @@ else
s = ss;
if (!*s || *++s != sep || sep_is_special) break;
}
- while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
+ /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
+ while ( g->ptr > 0 && isspace(g->s[g->ptr-1])
+ && (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
+ g->ptr--;
buffer = string_from_gstring(g);
gstring_release_unused(g);
}
--
2.28.0

View file

@ -1,51 +0,0 @@
From d2671b04d025dee3b8311d2d83e0a0342c670f52 Mon Sep 17 00:00:00 2001
From: Gavan <gavan@coolfactor.org>
Date: Fri, 21 Aug 2020 15:46:01 +0100
Subject: [PATCH 29/37] Taint: fix off-by-one in is_tainted(). Bug 2634
(cherry picked from commit e0ae68c8ee6788508da4989ee0d6fcbaf40c7b97)
---
doc/ChangeLog | 5 +++++
src/store.c | 4 ++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git doc/ChangeLog doc/ChangeLog
index 2d2dc1f9f..6d944f204 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -82,6 +82,11 @@ JH/21 Bug 2630: Fix eol-replacement string for the ${readsocket } expansion.
Previously when a whitespace character was specified it was not inserted
after removing the newline.
+JH/24 Bug 2634: Fix a taint trap seen on NetBSD: the testing coded for
+ is_tainted() had an off-by-one error in the overenthusiastic direction.
+ Find and fix by Gavan. Although NetBSD is not a supported platform for
+ 4.94 this bug could affect other platforms.
+
Exim version 4.94
-----------------
diff --git src/store.c src/store.c
index c460ba383..7d08c9804 100644
--- src/store.c
+++ src/store.c
@@ -188,14 +188,14 @@ for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
if ((b = current_block[pool]))
{
uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
- if (US p >= bc && US p <= bc + b->length) return TRUE;
+ if (US p >= bc && US p < bc + b->length) return TRUE;
}
for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
for (b = chainbase[pool]; b; b = b->next)
{
uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
- if (US p >= bc && US p <= bc + b->length) return TRUE;
+ if (US p >= bc && US p < bc + b->length) return TRUE;
}
return FALSE;
}
--
2.28.0

View file

@ -1,32 +0,0 @@
From 4970c58b394eb0778542c97e3f86b565f9e3daa7 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Mon, 24 Aug 2020 20:14:34 +0100
Subject: [PATCH 30/37] Build: ifdef guard for EXPERIMENTAL_QUEUEFILE
(cherry picked from commit 1f5d0a9551205febf6729c7ee36c27626a76b4a4)
---
src/transports/queuefile.c | 4 ++++
diff --git src/transports/queuefile.c src/transports/queuefile.c
index 21ed3527f..97218548b 100644
--- src/transports/queuefile.c
+++ src/transports/queuefile.c
@@ -8,7 +8,10 @@
/* See the file NOTICE for conditions of use and distribution. */
+
#include "../exim.h"
+
+#ifdef EXPERIMENTAL_QUEUEFILE /* whole file */
#include "queuefile.h"
/* Options specific to the appendfile transport. They must be in alphabetic
@@ -276,3 +279,4 @@ return FALSE;
}
#endif /*!MACRO_PREDEF*/
+#endif /*EXPERIMENTAL_QUEUEFILE*/
--
2.28.0

View file

@ -1,28 +0,0 @@
From 976ef0e5fa7896394fe045e824dfb3e7d7502a68 Mon Sep 17 00:00:00 2001
From: Gavan <gavan@coolfactor.org>
Date: Fri, 21 Aug 2020 15:46:01 +0100
Subject: [PATCH 31/37] Taint: fix off-by-one in is_tainted(). Bug 2634
(cherry picked from commit e0ae68c8ee6788508da4989ee0d6fcbaf40c7b97)
---
doc/ChangeLog | 5 +++++
diff --git doc/ChangeLog doc/ChangeLog
index 6d944f204..ae4050322 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -87,6 +87,11 @@ JH/24 Bug 2634: Fix a taint trap seen on NetBSD: the testing coded for
Find and fix by Gavan. Although NetBSD is not a supported platform for
4.94 this bug could affect other platforms.
+JH/24 Bug 2634: Fix a taint trap seen on NetBSD: the testing coded for
+ is_tainted() had an off-by-one error in the overenthusiastic direction.
+ Find and fix by Gavan. Although NetBSD is not a supported platform for
+ 4.94 this bug could affect other platforms.
+
Exim version 4.94
-----------------
--
2.28.0

View file

@ -1,102 +0,0 @@
From d8e99d6047e709b35eabb1395c2046100d1a1dda Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Wed, 19 Aug 2020 21:09:04 +0100
Subject: [PATCH 32/37] DANE: force SNI to use $domain. Bug 2265
Note: this is not a complete fix for the issue
(cherry picked from commit 7044dd8fd62e215572ecf5a2c7f1bb9581cf6628)
---
doc/ChangeLog | 10 ++++++++++
src/receive.c | 2 +-
src/smtp_in.c | 2 +-
src/tls-gnu.c | 2 +-
src/tls-openssl.c | 1 +
src/transports/smtp.c | 1 +
diff --git doc/ChangeLog doc/ChangeLog
index ae4050322..ec1b03304 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -91,6 +91,16 @@ JH/24 Bug 2634: Fix a taint trap seen on NetBSD: the testing coded for
is_tainted() had an off-by-one error in the overenthusiastic direction.
Find and fix by Gavan. Although NetBSD is not a supported platform for
4.94 this bug could affect other platforms.
+JH/21 Bug 2630: Fix eol-replacement string for the ${readsocket } expansion.
+ Previously when a whitespace character was specified it was not inserted
+ after removing the newline.
+
+JH/22 Bug 2265: Force SNI usage for smtp transport DANE'd connections, to be
+ the domain part of the recipient address. This overrides any tls_sni
+ option set, which was previously used.
+
+JH/23 Logging: with the +tls_sni log_selector, do not wrap the received SNI
+ in quotes.
Exim version 4.94
diff --git src/receive.c src/receive.c
index 0db897e9e..ec90e93cd 100644
--- src/receive.c
+++ src/receive.c
@@ -4004,7 +4004,7 @@ if (LOGGING(tls_certificate_verified) && tls_in.cipher)
if (LOGGING(tls_peerdn) && tls_in.peerdn)
g = string_append(g, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\"");
if (LOGGING(tls_sni) && tls_in.sni)
- g = string_append(g, 3, US" SNI=\"", string_printing(tls_in.sni), US"\"");
+ g = string_append(g, 2, US" SNI=", string_printing2(tls_in.sni, SP_TAB|SP_SPACE));
#endif
if (sender_host_authenticated)
diff --git src/smtp_in.c src/smtp_in.c
index 526164c46..a13f0ed63 100644
--- src/smtp_in.c
+++ src/smtp_in.c
@@ -1811,7 +1811,7 @@ if (LOGGING(tls_certificate_verified) && tls_in.cipher)
if (LOGGING(tls_peerdn) && tls_in.peerdn)
g = string_append(g, 3, US" DN=\"", string_printing(tls_in.peerdn), US"\"");
if (LOGGING(tls_sni) && tls_in.sni)
- g = string_append(g, 3, US" SNI=\"", string_printing(tls_in.sni), US"\"");
+ g = string_append(g, 2, US" SNI=", string_printing2(tls_in.sni, SP_TAB|SP_SPACE));
return g;
}
#endif
diff --git src/tls-gnu.c src/tls-gnu.c
index 875c82efa..a34633390 100644
--- src/tls-gnu.c
+++ src/tls-gnu.c
@@ -2863,7 +2863,7 @@ DEBUG(D_tls) debug_printf("initialising GnuTLS as a client on fd %d\n", cctx->so
/* If dane is flagged, have either request or require dane for this host, and
a TLSA record found. Therefore, dane verify required. Which implies cert must
be requested and supplied, dane verify must pass, and cert verify irrelevant
-(incl. hostnames), and (caller handled) require_tls */
+(incl. hostnames), and (caller handled) require_tls and sni=$domain */
if (conn_args->dane && ob->dane_require_tls_ciphers)
{
diff --git src/tls-openssl.c src/tls-openssl.c
index a62322928..054b23d0c 100644
--- src/tls-openssl.c
+++ src/tls-openssl.c
@@ -3197,6 +3197,7 @@ tlsp->tlsa_usage = 0;
#ifndef DISABLE_OCSP
{
# ifdef SUPPORT_DANE
+ /*XXX this should be moved to caller, to be common across gnutls/openssl */
if ( conn_args->dane
&& ob->hosts_request_ocsp[0] == '*'
&& ob->hosts_request_ocsp[1] == '\0'
diff --git src/transports/smtp.c src/transports/smtp.c
index 8492a7f25..28dd8ff24 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -2020,6 +2020,7 @@ if (!continue_hostname)
{
case OK: sx->conn_args.dane = TRUE;
ob->tls_tempfail_tryclear = FALSE;
+ ob->tls_sni = sx->addrlist->domain;
break;
case FAIL_FORCED: break;
default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
--
2.28.0

View file

@ -1,217 +0,0 @@
From a505cf777f90755bce69ab53a899b284a304127b Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 23 Aug 2020 15:32:48 +0100
Subject: [PATCH 33/37] DANE: Fix 2-rcpt message, diff domins case. Bug 2265
(cherry picked from commit 99350dede64ad634300ddf15d0d97a81fd75d330)
---
src/debug.c | 11 ++++-
src/deliver.c | 3 ++
src/macros.h | 1 +
src/transports/smtp.c | 71 ++++++++++++++++++++++++----
src/verify.c | 2 +-
diff --git src/debug.c src/debug.c
index 6d6132e39..819e83331 100644
--- src/debug.c
+++ src/debug.c
@@ -30,7 +30,16 @@ const uschar * rc_names[] = { /* Mostly for debug output */
[UNEXPECTED] = US"UNEXPECTED",
[CANCELLED] = US"CANCELLED",
[FAIL_SEND] = US"FAIL_SEND",
- [FAIL_DROP] = US"FAIL_DROP"
+ [FAIL_DROP] = US"FAIL_DROP",
+ [DANE] = US"DANE",
+};
+
+const uschar * dns_rc_names[] = {
+ [DNS_SUCCEED] = US"DNS_SUCCEED",
+ [DNS_NOMATCH] = US"DNS_NOMATCH",
+ [DNS_NODATA] = US"DNS_NODATA",
+ [DNS_AGAIN] = US"DNS_AGAIN",
+ [DNS_FAIL] = US"DNS_FAIL",
};
diff --git src/deliver.c src/deliver.c
index 40db50084..f5e28941f 100644
--- src/deliver.c
+++ src/deliver.c
@@ -460,6 +460,9 @@ TRUE if the lists refer to the same hosts in the same order, except that
This enables Exim to use a single SMTP transaction for sending to two entirely
different domains that happen to end up pointing at the same hosts.
+We do not try to batch up different A-record host names that refer to the
+same IP.
+
Arguments:
one points to the first host list
two points to the second host list
diff --git src/macros.h src/macros.h
index 2378773cb..6fd5db94c 100644
--- src/macros.h
+++ src/macros.h
@@ -304,6 +304,7 @@ Use rc_names[] for debug strings. */
#define CANCELLED 13 /* Authentication cancelled */
#define FAIL_SEND 14 /* send() failed in authenticator */
#define FAIL_DROP 15 /* Fail and drop connection (used in ACL) */
+#define DANE 16 /* Deferred for domain mismatch (used in transport) */
/* Returns from the deliver_message() function */
diff --git src/transports/smtp.c src/transports/smtp.c
index 28dd8ff24..6ca4552a6 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -2019,11 +2019,12 @@ if (!continue_hostname)
switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required))
{
case OK: sx->conn_args.dane = TRUE;
- ob->tls_tempfail_tryclear = FALSE;
- ob->tls_sni = sx->addrlist->domain;
+ ob->tls_tempfail_tryclear = FALSE; /* force TLS */
+ ob->tls_sni = sx->first_addr->domain; /* force SNI */
break;
case FAIL_FORCED: break;
- default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
+ default:
+ set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: tlsa lookup %s",
rc_to_string(rc)),
rc, FALSE, &sx->delivery_start);
@@ -3430,6 +3431,7 @@ BOOL pass_message = FALSE;
uschar *message = NULL;
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
smtp_context * sx = store_get(sizeof(*sx), TRUE); /* tainted, for the data buffers */
+BOOL dane_held;
suppress_tls = suppress_tls; /* stop compiler warning when no TLS support */
*message_defer = FALSE;
@@ -3446,13 +3448,36 @@ sx->conn_args.tblock = tblock;
gettimeofday(&sx->delivery_start, NULL);
sx->sync_addr = sx->first_addr = addrlist;
-/* Get the channel set up ready for a message (MAIL FROM being the next
-SMTP command to send */
+DANE_DOMAINS:
+dane_held = FALSE;
+
+/* Get the channel set up ready for a message, MAIL FROM being the next
+SMTP command to send. */
if ((rc = smtp_setup_conn(sx, suppress_tls)) != OK)
{
timesince(&addrlist->delivery_time, &sx->delivery_start);
- return rc;
+ yield = rc;
+ goto TIDYUP;
+ }
+
+/*XXX*/
+/* If the connection used DANE, ignore for now any addresses with incompatible
+domains. The SNI has to be the domain. Arrange a whole new TCP conn later,
+just in case only TLS isn't enough. */
+
+if (sx->conn_args.dane)
+ {
+ const uschar * dane_domain = sx->first_addr->domain;
+
+ for (address_item * a = sx->first_addr->next; a; a = a->next)
+ if ( a->transport_return == PENDING_DEFER
+ && Ustrcmp(dane_domain, a->domain) != 0)
+ {
+ DEBUG(D_transport) debug_printf("DANE: holding %s for later\n", a->domain);
+ dane_held = TRUE;
+ a->transport_return = DANE;
+ }
}
/* If there is a filter command specified for this transport, we can now
@@ -4203,7 +4228,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
if (sx->first_addr != NULL) /* More addresses still to be sent */
- { /* in this run of the transport */
+ { /* on this connection */
continue_sequence++; /* Causes * in logging */
pipelining_active = sx->pipelining_used; /* was cleared at DATA */
goto SEND_MESSAGE;
@@ -4235,7 +4260,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
'2', ob->command_timeout);
if (sx->ok && f.continue_more)
- return yield; /* More addresses for another run */
+ goto TIDYUP; /* More addresses for another run */
}
else
{
@@ -4255,7 +4280,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
else
#endif
if (f.continue_more)
- return yield; /* More addresses for another run */
+ goto TIDYUP; /* More addresses for another run */
/* If the socket is successfully passed, we mustn't send QUIT (or
indeed anything!) from here. */
@@ -4295,7 +4320,7 @@ propagate it from the initial
sx->cctx.sock = -1;
continue_transport = NULL;
continue_hostname = NULL;
- return yield;
+ goto TIDYUP;
}
log_write(0, LOG_PANIC_DIE, "fork failed");
}
@@ -4370,9 +4395,35 @@ if (sx->send_quit)
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
+/*XXX*/
+if (dane_held)
+ {
+ sx->first_addr = NULL;
+ for (address_item * a = sx->addrlist->next; a; a = a->next)
+ if (a->transport_return == DANE)
+ {
+ a->transport_return = PENDING_DEFER;
+ if (!sx->first_addr)
+ {
+ /* Remember the new start-point in the addrlist, for smtp_setup_conn()
+ to get the domain string for SNI */
+
+ sx->first_addr = a;
+ DEBUG(D_transport) debug_printf("DANE: go-around for %s\n", a->domain);
+ }
+ }
+ goto DANE_DOMAINS;
+ }
+
continue_transport = NULL;
continue_hostname = NULL;
return yield;
+
+TIDYUP:
+if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next)
+ if (a->transport_return == DANE)
+ a->transport_return = PENDING_DEFER;
+return yield;
}
diff --git src/verify.c src/verify.c
index 5f4181de9..43343a646 100644
--- src/verify.c
+++ src/verify.c
@@ -674,7 +674,7 @@ coding means skipping this whole loop and doing the append separately. */
if (!sx) sx = store_get(sizeof(*sx), TRUE); /* tainted buffers */
memset(sx, 0, sizeof(*sx));
- sx->addrlist = addr;
+ sx->addrlist = sx->first_addr = addr;
sx->conn_args.host = host;
sx->conn_args.host_af = host_af,
sx->port = port;
--
2.28.0

View file

@ -1,92 +0,0 @@
From 7dad62cced33eebd10d13fd1f6cd59696175fa44 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 23 Aug 2020 17:27:30 +0100
Subject: [PATCH 34/37] Fix non-DANE build
(cherry picked from commit 79b19a30d9fc64a7b7f70928cdefe4f51064280b)
---
src/transports/smtp.c | 15 +++++++++++----
diff --git src/transports/smtp.c src/transports/smtp.c
index 6ca4552a6..d63379e37 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -2023,8 +2023,7 @@ if (!continue_hostname)
ob->tls_sni = sx->first_addr->domain; /* force SNI */
break;
case FAIL_FORCED: break;
- default:
- set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
+ default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
string_sprintf("DANE error: tlsa lookup %s",
rc_to_string(rc)),
rc, FALSE, &sx->delivery_start);
@@ -3431,7 +3430,9 @@ BOOL pass_message = FALSE;
uschar *message = NULL;
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
smtp_context * sx = store_get(sizeof(*sx), TRUE); /* tainted, for the data buffers */
+#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
BOOL dane_held;
+#endif
suppress_tls = suppress_tls; /* stop compiler warning when no TLS support */
*message_defer = FALSE;
@@ -3448,8 +3449,10 @@ sx->conn_args.tblock = tblock;
gettimeofday(&sx->delivery_start, NULL);
sx->sync_addr = sx->first_addr = addrlist;
+#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
DANE_DOMAINS:
dane_held = FALSE;
+#endif
/* Get the channel set up ready for a message, MAIL FROM being the next
SMTP command to send. */
@@ -3461,7 +3464,7 @@ if ((rc = smtp_setup_conn(sx, suppress_tls)) != OK)
goto TIDYUP;
}
-/*XXX*/
+#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
/* If the connection used DANE, ignore for now any addresses with incompatible
domains. The SNI has to be the domain. Arrange a whole new TCP conn later,
just in case only TLS isn't enough. */
@@ -3479,6 +3482,7 @@ if (sx->conn_args.dane)
a->transport_return = DANE;
}
}
+#endif
/* If there is a filter command specified for this transport, we can now
set it up. This cannot be done until the identity of the host is known. */
@@ -4395,7 +4399,7 @@ if (sx->send_quit)
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
-/*XXX*/
+#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
if (dane_held)
{
sx->first_addr = NULL;
@@ -4414,15 +4418,18 @@ if (dane_held)
}
goto DANE_DOMAINS;
}
+#endif
continue_transport = NULL;
continue_hostname = NULL;
return yield;
TIDYUP:
+#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next)
if (a->transport_return == DANE)
a->transport_return = PENDING_DEFER;
+#endif
return yield;
}
--
2.28.0

View file

@ -1,525 +0,0 @@
From 569be4bc51fd4806edcf6b3abcf550dbbba90df5 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Wed, 26 Aug 2020 23:43:54 +0100
Subject: [PATCH 35/37] DANE: Fix 2 messages from queue case
(cherry picked from commit b6054898ace169a0e5143117397a4f666a5e7283)
---
src/deliver.c | 12 +++-
src/exim.c | 14 +++-
src/globals.c | 2 +
src/globals.h | 2 +
src/spool_in.c | 24 +++----
src/tls-gnu.c | 6 +-
src/transport.c | 32 ++++++---
src/transports/smtp.c | 89 ++++++++++++++++++++---
src/transports/smtp.h | 2 +-
diff --git src/deliver.c src/deliver.c
index f5e28941f..8f21c607e 100644
--- src/deliver.c
+++ src/deliver.c
@@ -1195,7 +1195,7 @@ else
if (addr->host_used)
{
g = d_hostlog(g, addr);
- if (continue_sequence > 1)
+ if (continue_sequence > 1) /*XXX this is wrong for a dropped proxyconn. Would have to pass back from transport */
g = string_catn(g, US"*", 1);
#ifndef DISABLE_EVENT
@@ -4275,6 +4275,10 @@ for (int delivery_count = 0; addr_remote; delivery_count++)
}
}
+/*XXX need to defeat this when DANE is used - but we don't know that yet.
+So look out for the place it gets used.
+*/
+
/* Get the flag which specifies whether the transport can handle different
domains that nevertheless resolve to the same set of hosts. If it needs
expanding, get variables set: $address_data, $domain_data, $localpart_data,
@@ -4353,6 +4357,11 @@ for (int delivery_count = 0; addr_remote; delivery_count++)
/************************************************************************/
+/*XXX don't know yet if DANE will be used. So tpt will have to
+check at the point if gets next addr from list, and skip/defer any
+nonmatch domains
+*/
+
/* Pick off all addresses which have the same transport, errors address,
destination, and extra headers. In some cases they point to the same host
list, but we also need to check for identical host lists generated from
@@ -4499,6 +4508,7 @@ for (int delivery_count = 0; addr_remote; delivery_count++)
if (continue_transport)
{
BOOL ok = Ustrcmp(continue_transport, tp->name) == 0;
+/*XXX do we need to check for a DANEd conn vs. a change of domain? */
/* If the transport is about to override the host list do not check
it here but take the cost of running the transport process to discover
diff --git src/exim.c src/exim.c
index ac0ff5523..630ac4038 100644
--- src/exim.c
+++ src/exim.c
@@ -2806,10 +2806,22 @@ on the second character (the one after '-'), to save some effort. */
case 'S': smtp_peer_options |= OPTION_SIZE; break;
#ifndef DISABLE_TLS
+ /* -MCs: used with -MCt; SNI was sent */
+ /* -MCr: ditto, DANE */
+
+ case 'r':
+ case 's': if (++i < argc)
+ {
+ continue_proxy_sni = string_copy_taint(argv[i], TRUE);
+ if (argrest[1] == 'r') continue_proxy_dane = TRUE;
+ }
+ else badarg = TRUE;
+ break;
+
/* -MCt: similar to -MCT below but the connection is still open
via a proxy process which handles the TLS context and coding.
Require three arguments for the proxied local address and port,
- and the TLS cipher. */
+ and the TLS cipher. */
case 't': if (++i < argc)
sending_ip_address = string_copy_taint(argv[i], TRUE);
diff --git src/globals.c src/globals.c
index fc3086f72..c34ac9ddd 100644
--- src/globals.c
+++ src/globals.c
@@ -729,6 +729,8 @@ uid_t config_uid = 0;
int connection_max_messages= -1;
uschar *continue_proxy_cipher = NULL;
+BOOL continue_proxy_dane = FALSE;
+uschar *continue_proxy_sni = NULL;
uschar *continue_hostname = NULL;
uschar *continue_host_address = NULL;
int continue_sequence = 1;
diff --git src/globals.h src/globals.h
index c80c8532f..a4c1143b7 100644
--- src/globals.h
+++ src/globals.h
@@ -425,6 +425,8 @@ extern uschar *config_main_filename; /* File name actually used */
extern uschar *config_main_directory; /* Directory where the main config file was found */
extern uid_t config_uid; /* Additional owner */
extern uschar *continue_proxy_cipher; /* TLS cipher for proxied continued delivery */
+extern BOOL continue_proxy_dane; /* proxied conn is DANE */
+extern uschar *continue_proxy_sni; /* proxied conn SNI */
extern uschar *continue_hostname; /* Host for continued delivery */
extern uschar *continue_host_address; /* IP address for ditto */
extern int continue_sequence; /* Sequence num for continued delivery */
diff --git src/spool_in.c src/spool_in.c
index a0147d5ee..1b4cefdb2 100644
--- src/spool_in.c
+++ src/spool_in.c
@@ -55,7 +55,7 @@ for (int i = 0; i < 2; i++)
set_subdir_str(message_subdir, id, i);
fname = spool_fname(US"input", message_subdir, id, US"-D");
- DEBUG(D_deliver) debug_printf("Trying spool file %s\n", fname);
+ DEBUG(D_deliver) debug_printf_indent("Trying spool file %s\n", fname);
/* We protect against symlink attacks both in not propagating the
* file-descriptor to other processes as we exec, and also ensuring that we
@@ -367,7 +367,7 @@ for (int n = 0; n < 2; n++)
errno = 0;
#ifndef COMPILE_UTILITY
-DEBUG(D_deliver) debug_printf("reading spool file %s\n", name);
+DEBUG(D_deliver) debug_printf_indent("reading spool file %s\n", name);
#endif /* COMPILE_UTILITY */
/* The first line of a spool file contains the message id followed by -H (i.e.
@@ -430,7 +430,7 @@ if (f.running_in_test_harness)
#endif
#ifndef COMPILE_UTILITY
-DEBUG(D_deliver) debug_printf("user=%s uid=%ld gid=%ld sender=%s\n",
+DEBUG(D_deliver) debug_printf_indent("user=%s uid=%ld gid=%ld sender=%s\n",
originator_login, (long int)originator_uid, (long int)originator_gid,
sender_address);
#endif
@@ -715,7 +715,7 @@ host_build_sender_fullhost();
#ifndef COMPILE_UTILITY
DEBUG(D_deliver)
- debug_printf("sender_local=%d ident=%s\n", f.sender_local,
+ debug_printf_indent("sender_local=%d ident=%s\n", f.sender_local,
sender_ident ? sender_ident : US"unset");
#endif /* COMPILE_UTILITY */
@@ -743,7 +743,7 @@ if (sscanf(CS big_buffer, "%d", &rcount) != 1 || rcount > 16384)
goto SPOOL_FORMAT_ERROR;
#ifndef COMPILE_UTILITY
-DEBUG(D_deliver) debug_printf("recipients_count=%d\n", rcount);
+DEBUG(D_deliver) debug_printf_indent("recipients_count=%d\n", rcount);
#endif /* COMPILE_UTILITY */
recipients_list_max = rcount;
@@ -814,7 +814,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
{
int dummy;
#if !defined (COMPILE_UTILITY)
- DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 3 spool file\n");
+ DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - Exim 3 spool file\n");
#endif
while (isdigit(*(--p)) || *p == ',');
if (*p == ' ')
@@ -829,7 +829,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
else if (*p == ' ')
{
#if !defined (COMPILE_UTILITY)
- DEBUG(D_deliver) debug_printf("**** SPOOL_IN - early Exim 4 spool file\n");
+ DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - early Exim 4 spool file\n");
#endif
*p++ = 0;
(void)sscanf(CS p, "%d", &pno);
@@ -842,7 +842,7 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
int flags;
#if !defined (COMPILE_UTILITY)
- DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim standard format spoolfile\n");
+ DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - Exim standard format spoolfile\n");
#endif
(void)sscanf(CS p+1, "%d", &flags);
@@ -878,13 +878,13 @@ for (recipients_count = 0; recipients_count < rcount; recipients_count++)
}
#if !defined(COMPILE_UTILITY)
else
- { DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n"); }
+ { DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - No additional fields\n"); }
if (orcpt || dsn_flags)
- DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: <%s> orcpt: <%s> dsn_flags: 0x%x\n",
+ DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> orcpt: <%s> dsn_flags: 0x%x\n",
big_buffer, orcpt, dsn_flags);
if (errors_to)
- DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: <%s> errorsto: <%s>\n",
+ DEBUG(D_deliver) debug_printf_indent("**** SPOOL_IN - address: <%s> errorsto: <%s>\n",
big_buffer, errors_to);
#endif
@@ -956,7 +956,7 @@ line count by adding the body linecount to the header linecount. Close the file
and give a positive response. */
#ifndef COMPILE_UTILITY
-DEBUG(D_deliver) debug_printf("body_linecount=%d message_linecount=%d\n",
+DEBUG(D_deliver) debug_printf_indent("body_linecount=%d message_linecount=%d\n",
body_linecount, message_linecount);
#endif /* COMPILE_UTILITY */
diff --git src/tls-gnu.c src/tls-gnu.c
index a34633390..dafe1be0c 100644
--- src/tls-gnu.c
+++ src/tls-gnu.c
@@ -545,7 +545,10 @@ else
/* peercert is set in peer_status() */
tlsp->peerdn = state->peerdn;
-tlsp->sni = state->received_sni;
+
+/* do not corrupt sni sent by client; record sni rxd by server */
+if (!state->host)
+ tlsp->sni = state->received_sni;
/* record our certificate */
{
@@ -2890,6 +2893,7 @@ if (!cipher_list)
cipher_list, &state, tlsp, errstr) != OK)
return FALSE;
+
#ifdef MEASURE_TIMING
report_time_since(&t0, US"client tls_init (delta)");
#endif
diff --git src/transport.c src/transport.c
index 2d8426f29..b1cda55fd 100644
--- src/transport.c
+++ src/transport.c
@@ -1661,6 +1661,7 @@ DEBUG(D_transport)
debug_printf("transport_check_waiting entered\n");
debug_printf(" sequence=%d local_max=%d global_max=%d\n",
continue_sequence, local_message_max, connection_max_messages);
+ acl_level++;
}
/* Do nothing if we have hit the maximum number that can be send down one
@@ -1670,23 +1671,23 @@ if (connection_max_messages >= 0) local_message_max = connection_max_messages;
if (local_message_max > 0 && continue_sequence >= local_message_max)
{
DEBUG(D_transport)
- debug_printf("max messages for one connection reached: returning\n");
- return FALSE;
+ debug_printf_indent("max messages for one connection reached: returning\n");
+ goto retfalse;
}
/* Open the waiting information database. */
if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name),
O_RDWR, &dbblock, TRUE, TRUE)))
- return FALSE;
+ goto retfalse;
/* See if there is a record for this host; if not, there's nothing to do. */
if (!(host_record = dbfn_read(dbm_file, hostname)))
{
dbfn_close(dbm_file);
- DEBUG(D_transport) debug_printf("no messages waiting for %s\n", hostname);
- return FALSE;
+ DEBUG(D_transport) debug_printf_indent("no messages waiting for %s\n", hostname);
+ goto retfalse;
}
/* If the data in the record looks corrupt, just log something and
@@ -1697,7 +1698,7 @@ if (host_record->count > WAIT_NAME_MAX)
dbfn_close(dbm_file);
log_write(0, LOG_MAIN|LOG_PANIC, "smtp-wait database entry for %s has bad "
"count=%d (max=%d)", hostname, host_record->count, WAIT_NAME_MAX);
- return FALSE;
+ goto retfalse;
}
/* Scan the message ids in the record from the end towards the beginning,
@@ -1835,8 +1836,8 @@ while (1)
if (host_length <= 0)
{
dbfn_close(dbm_file);
- DEBUG(D_transport) debug_printf("waiting messages already delivered\n");
- return FALSE;
+ DEBUG(D_transport) debug_printf_indent("waiting messages already delivered\n");
+ goto retfalse;
}
/* we were not able to find an acceptable message, nor was there a
@@ -1847,7 +1848,7 @@ while (1)
{
Ustrcpy(new_message_id, message_id);
dbfn_close(dbm_file);
- return FALSE;
+ goto retfalse;
}
} /* we need to process a continuation record */
@@ -1865,7 +1866,12 @@ if (host_length > 0)
}
dbfn_close(dbm_file);
+DEBUG(D_transport) {acl_level--; debug_printf("transport_check_waiting: TRUE\n"); }
return TRUE;
+
+retfalse:
+DEBUG(D_transport) {acl_level--; debug_printf("transport_check_waiting: FALSE\n"); }
+return FALSE;
}
/*************************************************
@@ -1877,7 +1883,7 @@ void
transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
const uschar *hostaddress, uschar *id, int socket_fd)
{
-int i = 20;
+int i = 22;
const uschar **argv;
/* Set up the calling arguments; use the standard function for the basics,
@@ -1898,6 +1904,12 @@ if (smtp_peer_options & OPTION_TLS)
argv[i++] = sending_ip_address;
argv[i++] = string_sprintf("%d", sending_port);
argv[i++] = tls_out.active.sock >= 0 ? tls_out.cipher : continue_proxy_cipher;
+
+ if (tls_out.sni)
+ {
+ argv[i++] = tls_out.dane_verified ? US"-MCr" : US"-MCs";
+ argv[i++] = tls_out.sni;
+ }
}
else
argv[i++] = US"-MCT";
diff --git src/transports/smtp.c src/transports/smtp.c
index d63379e37..7fc2a48bb 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -1620,8 +1620,8 @@ return FALSE;
typedef struct smtp_compare_s
{
- uschar *current_sender_address;
- struct transport_instance *tblock;
+ uschar * current_sender_address;
+ struct transport_instance * tblock;
} smtp_compare_t;
@@ -1991,6 +1991,74 @@ if (sx->smtps)
}
#endif
+#ifdef SUPPORT_DANE
+/* If we have a proxied TLS connection, check usability for this message */
+
+if (continue_hostname && continue_proxy_cipher)
+ {
+ int rc;
+ const uschar * sni = US"";
+
+ /* Check if the message will be DANE-verified; if so force its SNI */
+
+ smtp_port_for_connect(sx->conn_args.host, sx->port);
+ if ( sx->conn_args.host->dnssec == DS_YES
+ && ( sx->dane_required
+ || verify_check_given_host(CUSS &ob->hosts_try_dane, sx->conn_args.host) == OK
+ ) )
+ switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required))
+ {
+ case OK: sx->conn_args.dane = TRUE;
+ ob->tls_tempfail_tryclear = FALSE; /* force TLS */
+ ob->tls_sni = sx->first_addr->domain; /* force SNI */
+ break;
+ case FAIL_FORCED: break;
+ default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
+ string_sprintf("DANE error: tlsa lookup %s",
+ rc_to_string(rc)),
+ rc, FALSE, &sx->delivery_start);
+# ifndef DISABLE_EVENT
+ (void) event_raise(sx->conn_args.tblock->event_action,
+ US"dane:fail", sx->dane_required
+ ? US"dane-required" : US"dnssec-invalid");
+# endif
+ return rc;
+ }
+
+ /* If the SNI required for the new message differs from the existing conn
+ drop the connection to force a new one. */
+
+ if (ob->tls_sni && !(sni = expand_cstring(ob->tls_sni)))
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "<%s>: failed to expand transport's tls_sni value: %s",
+ sx->addrlist->address, expand_string_message);
+
+ if ( (continue_proxy_sni ? (Ustrcmp(continue_proxy_sni, sni) == 0) : !*sni)
+ && continue_proxy_dane == sx->conn_args.dane)
+ {
+ tls_out.sni = US sni;
+ if ((tls_out.dane_verified = continue_proxy_dane))
+ sx->conn_args.host->dnssec = DS_YES;
+ }
+ else
+ {
+ DEBUG(D_transport)
+ debug_printf("Closing proxied-TLS connection due to SNI mismatch\n");
+
+ HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n");
+ write(0, "QUIT\r\n", 6);
+ close(0);
+ tls_out.dane_verified = FALSE;
+ continue_hostname = continue_proxy_cipher = NULL;
+ f.continue_more = FALSE;
+ continue_sequence = 1; /* Unfortunately, this process cannot affect success log
+ which is done by delivery proc. Would have to pass this
+ back through reporting pipe. */
+ }
+ }
+#endif
+
+
/* Make a connection to the host if this isn't a continued delivery, and handle
the initial interaction and HELO/EHLO/LHLO. Connect timeout errors are handled
specially so they can be identified for retries. */
@@ -3430,7 +3498,7 @@ BOOL pass_message = FALSE;
uschar *message = NULL;
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
smtp_context * sx = store_get(sizeof(*sx), TRUE); /* tainted, for the data buffers */
-#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
+#ifdef SUPPORT_DANE
BOOL dane_held;
#endif
@@ -3449,7 +3517,7 @@ sx->conn_args.tblock = tblock;
gettimeofday(&sx->delivery_start, NULL);
sx->sync_addr = sx->first_addr = addrlist;
-#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
+#ifdef SUPPORT_DANE
DANE_DOMAINS:
dane_held = FALSE;
#endif
@@ -3464,7 +3532,7 @@ if ((rc = smtp_setup_conn(sx, suppress_tls)) != OK)
goto TIDYUP;
}
-#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
+#ifdef SUPPORT_DANE
/* If the connection used DANE, ignore for now any addresses with incompatible
domains. The SNI has to be the domain. Arrange a whole new TCP conn later,
just in case only TLS isn't enough. */
@@ -4184,8 +4252,8 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
t_compare.tblock = tblock;
t_compare.current_sender_address = sender_address;
- if ( sx->first_addr != NULL
- || f.continue_more
+ if ( sx->first_addr != NULL /* more addrs for this message */
+ || f.continue_more /* more addrs for coninued-host */
|| (
#ifndef DISABLE_TLS
( tls_out.active.sock < 0 && !continue_proxy_cipher
@@ -4232,7 +4300,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
if (sx->first_addr != NULL) /* More addresses still to be sent */
- { /* on this connection */
+ { /* for this message */
continue_sequence++; /* Causes * in logging */
pipelining_active = sx->pipelining_used; /* was cleared at DATA */
goto SEND_MESSAGE;
@@ -4256,6 +4324,7 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
sx->cctx.tls_ctx = NULL;
+ tls_out.active.sock = -1;
smtp_peer_options = smtp_peer_options_wrap;
sx->ok = !sx->smtps
&& smtp_write_command(sx, SCMD_FLUSH, "EHLO %s\r\n", sx->helo_data)
@@ -4399,7 +4468,7 @@ if (sx->send_quit)
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
#endif
-#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
+#ifdef SUPPORT_DANE
if (dane_held)
{
sx->first_addr = NULL;
@@ -4425,7 +4494,7 @@ continue_hostname = NULL;
return yield;
TIDYUP:
-#if !defined(DISABLE_TLS) && defined(SUPPORT_DANE)
+#ifdef SUPPORT_DANE
if (dane_held) for (address_item * a = sx->addrlist->next; a; a = a->next)
if (a->transport_return == DANE)
a->transport_return = PENDING_DEFER;
diff --git src/transports/smtp.h src/transports/smtp.h
index 6e63a002d..213bca1a8 100644
--- src/transports/smtp.h
+++ src/transports/smtp.h
@@ -87,7 +87,7 @@ typedef struct {
# ifdef EXPERIMENTAL_TLS_RESUME
uschar *tls_resumption_hosts;
# endif
- uschar *tls_sni;
+ const uschar *tls_sni;
uschar *tls_verify_certificates;
int tls_dh_min_bits;
BOOL tls_tempfail_tryclear;
--
2.28.0

View file

@ -1,114 +0,0 @@
From 6742503035564e057edc7d3eba88b108f7d3d74c Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Wed, 26 Aug 2020 23:59:28 +0100
Subject: [PATCH 36/37] Fix non-DANE build
(cherry picked from commit 651946cbf8e3849687332049730e5fa23d42b4b7)
---
src/smtp_out.c | 2 +-
src/transport.c | 6 +++++-
src/transports/smtp.c | 15 ++++++++++-----
diff --git src/smtp_out.c src/smtp_out.c
index 86c3e4127..c4c409677 100644
--- src/smtp_out.c
+++ src/smtp_out.c
@@ -375,7 +375,7 @@ smtp_port_for_connect(host_item * host, int port)
{
if (host->port != PORT_NONE)
{
- HDEBUG(D_transport|D_acl|D_v)
+ HDEBUG(D_transport|D_acl|D_v) if (port != host->port)
debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
host->port);
port = host->port;
diff --git src/transport.c src/transport.c
index b1cda55fd..609fd128c 100644
--- src/transport.c
+++ src/transport.c
@@ -1907,7 +1907,11 @@ if (smtp_peer_options & OPTION_TLS)
if (tls_out.sni)
{
- argv[i++] = tls_out.dane_verified ? US"-MCr" : US"-MCs";
+ argv[i++] =
+#ifdef SUPPORT_DANE
+ tls_out.dane_verified ? US"-MCr" :
+#endif
+ US"-MCs";
argv[i++] = tls_out.sni;
}
}
diff --git src/transports/smtp.c src/transports/smtp.c
index 7fc2a48bb..77335af09 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -1991,7 +1991,6 @@ if (sx->smtps)
}
#endif
-#ifdef SUPPORT_DANE
/* If we have a proxied TLS connection, check usability for this message */
if (continue_hostname && continue_proxy_cipher)
@@ -1999,8 +1998,10 @@ if (continue_hostname && continue_proxy_cipher)
int rc;
const uschar * sni = US"";
+#ifdef SUPPORT_DANE
/* Check if the message will be DANE-verified; if so force its SNI */
+ tls_out.dane_verified = FALSE;
smtp_port_for_connect(sx->conn_args.host, sx->port);
if ( sx->conn_args.host->dnssec == DS_YES
&& ( sx->dane_required
@@ -2024,15 +2025,17 @@ if (continue_hostname && continue_proxy_cipher)
# endif
return rc;
}
+#endif
- /* If the SNI required for the new message differs from the existing conn
- drop the connection to force a new one. */
+ /* If the SNI or the DANE status required for the new message differs from the
+ existing conn drop the connection to force a new one. */
if (ob->tls_sni && !(sni = expand_cstring(ob->tls_sni)))
log_write(0, LOG_MAIN|LOG_PANIC,
"<%s>: failed to expand transport's tls_sni value: %s",
sx->addrlist->address, expand_string_message);
+#ifdef SUPPORT_DANE
if ( (continue_proxy_sni ? (Ustrcmp(continue_proxy_sni, sni) == 0) : !*sni)
&& continue_proxy_dane == sx->conn_args.dane)
{
@@ -2040,6 +2043,10 @@ if (continue_hostname && continue_proxy_cipher)
if ((tls_out.dane_verified = continue_proxy_dane))
sx->conn_args.host->dnssec = DS_YES;
}
+#else
+ if ((continue_proxy_sni ? (Ustrcmp(continue_proxy_sni, sni) == 0) : !*sni))
+ tls_out.sni = US sni;
+#endif
else
{
DEBUG(D_transport)
@@ -2048,7 +2055,6 @@ if (continue_hostname && continue_proxy_cipher)
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n");
write(0, "QUIT\r\n", 6);
close(0);
- tls_out.dane_verified = FALSE;
continue_hostname = continue_proxy_cipher = NULL;
f.continue_more = FALSE;
continue_sequence = 1; /* Unfortunately, this process cannot affect success log
@@ -2056,7 +2062,6 @@ if (continue_hostname && continue_proxy_cipher)
back through reporting pipe. */
}
}
-#endif
/* Make a connection to the host if this isn't a continued delivery, and handle
--
2.28.0

View file

@ -1,41 +0,0 @@
From 49d173f4e4c05bbc9e6f256f8914979dad85e9d3 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sun, 6 Sep 2020 12:15:10 +0100
Subject: [PATCH 38/42] GnuTLS: clear errno before any data i/o op, so error
logging does not see stale values
(cherry picked from commit d52a8ce8499fbb88f4670623df9f52d3e790292b)
---
src/tls-gnu.c | 3 +++
diff --git src/tls-gnu.c src/tls-gnu.c
index dafe1be0c..6ee603595 100644
--- src/tls-gnu.c
+++ src/tls-gnu.c
@@ -3162,6 +3162,7 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, buf
sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
+errno = 0;
do
inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
MIN(ssl_xfer_buffer_size, lim));
@@ -3322,6 +3323,7 @@ DEBUG(D_tls)
debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, len=" SIZE_T_FMT ")\n",
state->session, buff, len);
+errno = 0;
do
inbytes = gnutls_record_recv(state->session, buff, len);
while (inbytes == GNUTLS_E_AGAIN);
@@ -3385,6 +3387,7 @@ while (left > 0)
DEBUG(D_tls) debug_printf("gnutls_record_send(session=%p, buffer=%p, left=" SIZE_T_FMT ")\n",
state->session, buff, left);
+ errno = 0;
do
outbytes = gnutls_record_send(state->session, buff, left);
while (outbytes == GNUTLS_E_AGAIN);
--
2.29.2

View file

@ -1,83 +0,0 @@
From 7a534c812646a7a6f680827352d6209c6ff7be96 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Thu, 27 Aug 2020 21:15:19 +0100
Subject: [PATCH 39/42] Fix non-TLS build
(cherry picked from commit b38a477da0a5248ed1d2b7590922c89c6337ec3b)
---
src/transports/smtp.c | 18 +++++++++---------
diff --git src/transports/smtp.c src/transports/smtp.c
index 77335af09..b0dedfa8c 100644
--- src/transports/smtp.c
+++ src/transports/smtp.c
@@ -1989,7 +1989,7 @@ if (sx->smtps)
DEFER, FALSE, &sx->delivery_start);
return ERROR;
}
-#endif
+#else
/* If we have a proxied TLS connection, check usability for this message */
@@ -1998,7 +1998,7 @@ if (continue_hostname && continue_proxy_cipher)
int rc;
const uschar * sni = US"";
-#ifdef SUPPORT_DANE
+# ifdef SUPPORT_DANE
/* Check if the message will be DANE-verified; if so force its SNI */
tls_out.dane_verified = FALSE;
@@ -2018,14 +2018,14 @@ if (continue_hostname && continue_proxy_cipher)
string_sprintf("DANE error: tlsa lookup %s",
rc_to_string(rc)),
rc, FALSE, &sx->delivery_start);
-# ifndef DISABLE_EVENT
+# ifndef DISABLE_EVENT
(void) event_raise(sx->conn_args.tblock->event_action,
US"dane:fail", sx->dane_required
? US"dane-required" : US"dnssec-invalid");
-# endif
+# endif
return rc;
}
-#endif
+# endif
/* If the SNI or the DANE status required for the new message differs from the
existing conn drop the connection to force a new one. */
@@ -2035,7 +2035,7 @@ if (continue_hostname && continue_proxy_cipher)
"<%s>: failed to expand transport's tls_sni value: %s",
sx->addrlist->address, expand_string_message);
-#ifdef SUPPORT_DANE
+# ifdef SUPPORT_DANE
if ( (continue_proxy_sni ? (Ustrcmp(continue_proxy_sni, sni) == 0) : !*sni)
&& continue_proxy_dane == sx->conn_args.dane)
{
@@ -2043,10 +2043,10 @@ if (continue_hostname && continue_proxy_cipher)
if ((tls_out.dane_verified = continue_proxy_dane))
sx->conn_args.host->dnssec = DS_YES;
}
-#else
+# else
if ((continue_proxy_sni ? (Ustrcmp(continue_proxy_sni, sni) == 0) : !*sni))
tls_out.sni = US sni;
-#endif
+# endif
else
{
DEBUG(D_transport)
@@ -2062,7 +2062,7 @@ if (continue_hostname && continue_proxy_cipher)
back through reporting pipe. */
}
}
-
+#endif /*!DISABLE_TLS*/
/* Make a connection to the host if this isn't a continued delivery, and handle
the initial interaction and HELO/EHLO/LHLO. Connect timeout errors are handled
--
2.29.2

View file

@ -1,25 +0,0 @@
From f521f0d2120be2ccfb93306cc05790b9b0f162c1 Mon Sep 17 00:00:00 2001
From: Richard Clayton <richard@highwayman.com>
Date: Sat, 12 Sep 2020 22:10:04 +0100
Subject: [PATCH 40/42] eximon: fix FreeBSD build
(cherry picked from commit ba00bdd4609501dd3ffe187074ff7f8197a9059f)
---
exim_monitor/em_menu.c | 2 +-
diff --git exim_monitor/em_menu.c exim_monitor/em_menu.c
index 33b3e0c94..2a70a1831 100644
--- exim_monitor/em_menu.c
+++ exim_monitor/em_menu.c
@@ -670,7 +670,7 @@ if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
sprintf(CS big_buffer, "%s/input/%s", spool_directory, buffer);
if (Ustat(big_buffer, &statbuf) == 0)
text_showf(text, "Format error in spool file %s: size=%lu\n", buffer,
- (ulong)statbuf.st_size);
+ (unsigned long)statbuf.st_size);
else text_showf(text, "Format error in spool file %s\n", buffer);
}
else text_showf(text, "Read error for spool file %s\n", buffer);
--
2.29.2

View file

@ -1,51 +0,0 @@
From e12d2e7bc2e9f0c30a1029602e57e5ae8df1b9db Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Fri, 30 Oct 2020 13:58:01 +0000
Subject: [PATCH 41/42] LDAP: fix taint-check in server list walk. Bug
2646
(cherry picked from commit 51b611aa81d7ee01243b196abc34a0e2eabd293c)
---
doc/ChangeLog | 5 +++++
src/lookups/ldap.c | 3 +--
diff --git doc/ChangeLog doc/ChangeLog
index ec1b03304..9924fca5c 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -102,6 +102,11 @@ JH/22 Bug 2265: Force SNI usage for smtp transport DANE'd connections, to be
JH/23 Logging: with the +tls_sni log_selector, do not wrap the received SNI
in quotes.
+JH/26 Bug 2646: fix a memory usage issue in ldap lookups. Previously, when more
+ than one server was defined and depending on the platform memory layout
+ details, an internal consistency trap could be hit while walking the list
+ of servers.
+
Exim version 4.94
-----------------
diff --git src/lookups/ldap.c src/lookups/ldap.c
index ef550a08d..34908a351 100644
--- src/lookups/ldap.c
+++ src/lookups/ldap.c
@@ -1093,7 +1093,6 @@ uschar *password = NULL;
uschar *local_servers = NULL;
uschar *server;
const uschar *list;
-uschar buffer[512];
while (isspace(*url)) url++;
@@ -1254,7 +1253,7 @@ if (!eldap_default_servers && !local_servers || p[3] != '/')
/* Loop through the default servers until OK or FAIL. Use local_servers list
* if defined in the lookup, otherwise use the global default list */
list = !local_servers ? eldap_default_servers : local_servers;
-while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
+while ((server = string_nextinlist(&list, &sep, NULL, 0)))
{
int rc;
int port = 0;
--
2.29.2

View file

@ -1,107 +0,0 @@
From a3ab48f23ee4a83f796440ef67d7ac7b43aad4b5 Mon Sep 17 00:00:00 2001
From: Jeremy Harris <jgh146exb@wizmail.org>
Date: Sat, 31 Oct 2020 23:58:11 +0000
Subject: [PATCH 42/42] Pass authenticator pubname through spool. Bug 2648
(cherry picked from commit a75ebe0dcc5faeb915cacb0d9db66d2475789116)
---
doc/ChangeLog | 4 ++++
exim_monitor/em_globals.c | 1 +
src/smtp_in.c | 12 +++++++-----
src/spool_in.c | 4 +++-
src/spool_out.c | 6 ++++--
diff --git doc/ChangeLog doc/ChangeLog
index 9924fca5c..4759e018e 100644
--- doc/ChangeLog
+++ doc/ChangeLog
@@ -107,6 +107,10 @@ JH/26 Bug 2646: fix a memory usage issue in ldap lookups. Previously, when more
details, an internal consistency trap could be hit while walking the list
of servers.
+JH/27 Bug 2648: fix the passing of an authenticator public-name through spool
+ files. The value is used by the authresults expansion item. Previously
+ if this was used in a router or transport, a crash could result.
+
Exim version 4.94
-----------------
diff --git exim_monitor/em_globals.c exim_monitor/em_globals.c
index 925e88e05..30d22b5eb 100644
--- exim_monitor/em_globals.c
+++ exim_monitor/em_globals.c
@@ -205,6 +205,7 @@ uschar *sender_address = NULL;
uschar *sender_fullhost = NULL;
uschar *sender_helo_name = NULL;
uschar *sender_host_address = NULL;
+uschar *sender_host_auth_pubname = NULL;
uschar *sender_host_authenticated = NULL;
uschar *sender_host_name = NULL;
int sender_host_port = 0;
diff --git src/smtp_in.c src/smtp_in.c
index a13f0ed63..f53c3cf65 100644
--- src/smtp_in.c
+++ src/smtp_in.c
@@ -5935,12 +5935,14 @@ if (!sender_host_authenticated)
g = string_append(g, 2, US";\n\tauth=pass (", sender_host_auth_pubname);
-if (Ustrcmp(sender_host_auth_pubname, "tls") != 0)
- g = string_append(g, 2, US") smtp.auth=", authenticated_id);
-else if (authenticated_id)
- g = string_append(g, 2, US") x509.auth=", authenticated_id);
+if (Ustrcmp(sender_host_auth_pubname, "tls") == 0)
+ g = authenticated_id
+ ? string_append(g, 2, US") x509.auth=", authenticated_id)
+ : string_cat(g, US") reason=x509.auth");
else
- g = string_catn(g, US") reason=x509.auth", 17);
+ g = authenticated_id
+ ? string_append(g, 2, US") smtp.auth=", authenticated_id)
+ : string_cat(g, US", no id saved)");
if (authenticated_sender)
g = string_append(g, 2, US" smtp.mailfrom=", authenticated_sender);
diff --git src/spool_in.c src/spool_in.c
index 1b4cefdb2..35e44df26 100644
--- src/spool_in.c
+++ src/spool_in.c
@@ -253,7 +253,7 @@ sender_helo_name = NULL;
sender_host_address = NULL;
sender_host_name = NULL;
sender_host_port = 0;
-sender_host_authenticated = NULL;
+sender_host_authenticated = sender_host_auth_pubname = NULL;
sender_ident = NULL;
f.sender_local = FALSE;
f.sender_set_untrusted = FALSE;
@@ -580,6 +580,8 @@ for (;;)
host_lookup_deferred = TRUE;
else if (Ustrcmp(p, "ost_lookup_failed") == 0)
host_lookup_failed = TRUE;
+ else if (Ustrncmp(p, "ost_auth_pubname", 16) == 0)
+ sender_host_auth_pubname = string_copy_taint(var + 18, tainted);
else if (Ustrncmp(p, "ost_auth", 8) == 0)
sender_host_authenticated = string_copy_taint(var + 10, tainted);
else if (Ustrncmp(p, "ost_name", 8) == 0)
diff --git src/spool_out.c src/spool_out.c
index 4b6539ecd..0851ce956 100644
--- src/spool_out.c
+++ src/spool_out.c
@@ -174,9 +174,11 @@ if (sender_host_address)
fprintf(fp, "-host_address %s.%d\n", sender_host_address, sender_host_port);
if (sender_host_name)
spool_var_write(fp, US"host_name", sender_host_name);
- if (sender_host_authenticated)
- spool_var_write(fp, US"host_auth", sender_host_authenticated);
}
+if (sender_host_authenticated)
+ spool_var_write(fp, US"host_auth", sender_host_authenticated);
+if (sender_host_auth_pubname)
+ spool_var_write(fp, US"host_auth_pubname", sender_host_auth_pubname);
/* Also about the interface a message came in on */
--
2.29.2

View file

@ -18,6 +18,7 @@ OPTIONS_DEFINE+= ALT_CONFIG_PREFIX \
PRDR \
READLINE \
SUID \
TAINTWARN \
TCP_WRAPPERS \
WISHLIST \
EVENT \
@ -125,6 +126,7 @@ SPF_DESC= Enable Sender Policy Framework checking
SQLITE_DESC= Enable SQLite lookups
SRS_DESC= Enable Sender Rewriting Scheme
SUID_DESC= Install the exim binary suid root
TAINTWARN_DESC= Allow insecure tainted data (pre-4.93 config style, deprecated)
TCP_WRAPPERS_DESC= Enable /etc/hosts.allow access control
GNUTLS_DESC= Use GnuTLS instead of OpenSSL for TLS
WISHLIST_DESC= Include the unsupported patches