aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDima Panov <fluffy@FreeBSD.org>2021-12-28 19:23:16 +0000
committerDima Panov <fluffy@FreeBSD.org>2021-12-28 19:23:16 +0000
commit99c5dc1049a23570016dcb5ac44882e408800622 (patch)
tree1d60d86c8ebcd69cb5183826c0eb8faf7936b82a
parent84b05d67fd1dccaa3fc8f710a9a94d60afae6876 (diff)
downloadports-99c5dc1049a23570016dcb5ac44882e408800622.tar.gz
ports-99c5dc1049a23570016dcb5ac44882e408800622.zip
mail/exim: update to 4.95 release (+)
Finally, Exim will be pushed to 4.95 release. Long wait was caused by some criticals errors in vanilla release, upstream fixes got a some time to come. * Apply sendfile patch, fixes SIGSEGV using clamd via TCP [1] * Convert select() to poll(), fixes crashes (SIGSEV) on FreeBSD 12.2 [2] PR: 258848 [1], 259822 [2] Sponsored by: Netzkommune GmbH
-rw-r--r--mail/exim/Makefile35
-rw-r--r--mail/exim/distinfo6
-rw-r--r--mail/exim/files/debian/75_01-Introduce-main-config-option-allow_insecure_tainted_.patch230
-rw-r--r--mail/exim/files/debian/75_02-search.patch39
-rw-r--r--mail/exim/files/debian/75_03-dbstuff.patch30
-rw-r--r--mail/exim/files/debian/75_04-acl.patch67
-rw-r--r--mail/exim/files/debian/75_05-parse.patch30
-rw-r--r--mail/exim/files/debian/75_06-rda.patch28
-rw-r--r--mail/exim/files/debian/75_07-appendfile.patch34
-rw-r--r--mail/exim/files/debian/75_08-autoreply.patch70
-rw-r--r--mail/exim/files/debian/75_09-pipe.patch36
-rw-r--r--mail/exim/files/debian/75_10-deliver.patch49
-rw-r--r--mail/exim/files/debian/75_11-directory.patch26
-rw-r--r--mail/exim/files/debian/75_12-expand.patch34
-rw-r--r--mail/exim/files/debian/75_13-lf_sqlperform.patch49
-rw-r--r--mail/exim/files/debian/75_14-rf_get_transport.patch28
-rw-r--r--mail/exim/files/debian/75_15-deliver.patch31
-rw-r--r--mail/exim/files/debian/75_16-smtp_out.patch38
-rw-r--r--mail/exim/files/debian/75_17-smtp.patch29
-rw-r--r--mail/exim/files/debian/75_18-update-doc.patch154
-rw-r--r--mail/exim/files/debian/75_20-Set-mainlog_name-and-rejectlog_name-unconditionally.patch42
-rw-r--r--mail/exim/files/debian/75_21-tidy-log.c.patch124
-rw-r--r--mail/exim/files/debian/75_22-Silence-compiler.patch222
-rw-r--r--mail/exim/files/debian/75_23-Do-not-close-the-main-_log-if-we-do-not-see-a-chance.patch166
-rw-r--r--mail/exim/files/debian/75_24-Silence-the-compiler.patch57
-rw-r--r--mail/exim/files/debian/75_26-Disable-taintchecks-for-mkdir-this-isn-t-part-of-4.9.patch27
-rw-r--r--mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch616
-rw-r--r--mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch931
-rw-r--r--mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch140
-rw-r--r--mail/exim/files/patch-OS_os.c-FreeBSD15
-rw-r--r--mail/exim/files/patch-OS_os.h-FreeBSD17
-rw-r--r--mail/exim/files/patch-src__EDITME46
-rw-r--r--mail/exim/options1
33 files changed, 1736 insertions, 1711 deletions
diff --git a/mail/exim/Makefile b/mail/exim/Makefile
index 874f352e5ae3..efb374f816e3 100644
--- a/mail/exim/Makefile
+++ b/mail/exim/Makefile
@@ -2,7 +2,7 @@
PORTNAME= exim
PORTVERSION?= ${EXIM_VERSION}
-PORTREVISION?= 2
+PORTREVISION?= 0
CATEGORIES= mail
MASTER_SITES= EXIM:exim
MASTER_SITE_SUBDIR= /exim4/:exim \
@@ -65,32 +65,11 @@ 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
+DEBIAN_PATCHES_PREFIX= ${FILESDIR}/debian/75
+EXTRA_PATCHES= \
+ ${DEBIAN_PATCHES_PREFIX}_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch:-p1 \
+ ${DEBIAN_PATCHES_PREFIX}_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch:-p1 \
+ ${DEBIAN_PATCHES_PREFIX}_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch:-p1
.include <bsd.port.options.mk>
@@ -131,7 +110,7 @@ EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.c
EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.conf
.endif
-EXIM_VERSION= 4.94.2
+EXIM_VERSION= 4.95
SA_EXIM_VERSION=4.2.1
EXIM_INSTALL_ARG+= "-no_chown" "-no_symlink"
EXTRA_PATCHES+= `${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`
diff --git a/mail/exim/distinfo b/mail/exim/distinfo
index cf1ae320eaa8..c007834ea4bb 100644
--- a/mail/exim/distinfo
+++ b/mail/exim/distinfo
@@ -1,5 +1,5 @@
-TIMESTAMP = 1620141511
-SHA256 (exim/exim-4.94.2.tar.bz2) = 902e611486400608691dff31e1d8725eb9e23602399ad75670ec18878643bc4f
-SIZE (exim/exim-4.94.2.tar.bz2) = 2007178
+TIMESTAMP = 1632918983
+SHA256 (exim/exim-4.95.tar.bz2) = 7f4716cc1b3fee66930d83b249f1c7b119fa1957f6f46e3f4372805cbc97ea63
+SIZE (exim/exim-4.95.tar.bz2) = 2035738
SHA256 (exim/sa-exim-4.2.1.tar.gz) = 24d4bf7b0fdddaea11f132981cebb6a86a4ab20ef54111a8ebd481b421c6e2c1
SIZE (exim/sa-exim-4.2.1.tar.gz) = 68933
diff --git a/mail/exim/files/debian/75_01-Introduce-main-config-option-allow_insecure_tainted_.patch b/mail/exim/files/debian/75_01-Introduce-main-config-option-allow_insecure_tainted_.patch
deleted file mode 100644
index 0295ec18fa6e..000000000000
--- a/mail/exim/files/debian/75_01-Introduce-main-config-option-allow_insecure_tainted_.patch
+++ /dev/null
@@ -1,230 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_02-search.patch b/mail/exim/files/debian/75_02-search.patch
deleted file mode 100644
index 226a350af10d..000000000000
--- a/mail/exim/files/debian/75_02-search.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_03-dbstuff.patch b/mail/exim/files/debian/75_03-dbstuff.patch
deleted file mode 100644
index dc9da8e44c54..000000000000
--- a/mail/exim/files/debian/75_03-dbstuff.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_04-acl.patch b/mail/exim/files/debian/75_04-acl.patch
deleted file mode 100644
index 810b2e591675..000000000000
--- a/mail/exim/files/debian/75_04-acl.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-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)
diff --git a/mail/exim/files/debian/75_05-parse.patch b/mail/exim/files/debian/75_05-parse.patch
deleted file mode 100644
index f9dab900f88e..000000000000
--- a/mail/exim/files/debian/75_05-parse.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_06-rda.patch b/mail/exim/files/debian/75_06-rda.patch
deleted file mode 100644
index f4ca2afc13f1..000000000000
--- a/mail/exim/files/debian/75_06-rda.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_07-appendfile.patch b/mail/exim/files/debian/75_07-appendfile.patch
deleted file mode 100644
index 5a9e37861d7f..000000000000
--- a/mail/exim/files/debian/75_07-appendfile.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_08-autoreply.patch b/mail/exim/files/debian/75_08-autoreply.patch
deleted file mode 100644
index de5eb1dd3c20..000000000000
--- a/mail/exim/files/debian/75_08-autoreply.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_09-pipe.patch b/mail/exim/files/debian/75_09-pipe.patch
deleted file mode 100644
index 0ec9bcfaed19..000000000000
--- a/mail/exim/files/debian/75_09-pipe.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_10-deliver.patch b/mail/exim/files/debian/75_10-deliver.patch
deleted file mode 100644
index ea4a54239e31..000000000000
--- a/mail/exim/files/debian/75_10-deliver.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_11-directory.patch b/mail/exim/files/debian/75_11-directory.patch
deleted file mode 100644
index 4c3a68418c0b..000000000000
--- a/mail/exim/files/debian/75_11-directory.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_12-expand.patch b/mail/exim/files/debian/75_12-expand.patch
deleted file mode 100644
index ebb099d284f2..000000000000
--- a/mail/exim/files/debian/75_12-expand.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_13-lf_sqlperform.patch b/mail/exim/files/debian/75_13-lf_sqlperform.patch
deleted file mode 100644
index 67283a02676e..000000000000
--- a/mail/exim/files/debian/75_13-lf_sqlperform.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_14-rf_get_transport.patch b/mail/exim/files/debian/75_14-rf_get_transport.patch
deleted file mode 100644
index 9e8b69d3ad6a..000000000000
--- a/mail/exim/files/debian/75_14-rf_get_transport.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_15-deliver.patch b/mail/exim/files/debian/75_15-deliver.patch
deleted file mode 100644
index 0c2ca2772d10..000000000000
--- a/mail/exim/files/debian/75_15-deliver.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_16-smtp_out.patch b/mail/exim/files/debian/75_16-smtp_out.patch
deleted file mode 100644
index a0280afd30a8..000000000000
--- a/mail/exim/files/debian/75_16-smtp_out.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_17-smtp.patch b/mail/exim/files/debian/75_17-smtp.patch
deleted file mode 100644
index c77a284a9ff0..000000000000
--- a/mail/exim/files/debian/75_17-smtp.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_18-update-doc.patch b/mail/exim/files/debian/75_18-update-doc.patch
deleted file mode 100644
index 2edba6916744..000000000000
--- a/mail/exim/files/debian/75_18-update-doc.patch
+++ /dev/null
@@ -1,154 +0,0 @@
-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
diff --git a/mail/exim/files/debian/75_20-Set-mainlog_name-and-rejectlog_name-unconditionally.patch b/mail/exim/files/debian/75_20-Set-mainlog_name-and-rejectlog_name-unconditionally.patch
deleted file mode 100644
index a660aeb3dd6e..000000000000
--- a/mail/exim/files/debian/75_20-Set-mainlog_name-and-rejectlog_name-unconditionally.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_21-tidy-log.c.patch b/mail/exim/files/debian/75_21-tidy-log.c.patch
deleted file mode 100644
index b99f0c60988d..000000000000
--- a/mail/exim/files/debian/75_21-tidy-log.c.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_22-Silence-compiler.patch b/mail/exim/files/debian/75_22-Silence-compiler.patch
deleted file mode 100644
index ce6e89894f9a..000000000000
--- a/mail/exim/files/debian/75_22-Silence-compiler.patch
+++ /dev/null
@@ -1,222 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_23-Do-not-close-the-main-_log-if-we-do-not-see-a-chance.patch b/mail/exim/files/debian/75_23-Do-not-close-the-main-_log-if-we-do-not-see-a-chance.patch
deleted file mode 100644
index 12d91633c4bb..000000000000
--- a/mail/exim/files/debian/75_23-Do-not-close-the-main-_log-if-we-do-not-see-a-chance.patch
+++ /dev/null
@@ -1,166 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_24-Silence-the-compiler.patch b/mail/exim/files/debian/75_24-Silence-the-compiler.patch
deleted file mode 100644
index 14c3d5b433d2..000000000000
--- a/mail/exim/files/debian/75_24-Silence-the-compiler.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_26-Disable-taintchecks-for-mkdir-this-isn-t-part-of-4.9.patch b/mail/exim/files/debian/75_26-Disable-taintchecks-for-mkdir-this-isn-t-part-of-4.9.patch
deleted file mode 100644
index cee6066f9200..000000000000
--- a/mail/exim/files/debian/75_26-Disable-taintchecks-for-mkdir-this-isn-t-part-of-4.9.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-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
-
diff --git a/mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch b/mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch
new file mode 100644
index 000000000000..ac72e532ebea
--- /dev/null
+++ b/mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch
@@ -0,0 +1,616 @@
+From 1843f70b733127fcba3321d9d69359e05905f8cc Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Sat, 16 Oct 2021 00:12:16 +0100
+Subject: [PATCH] Avoid calling gettimeofday(), select() per char for cmdline
+ message submission. Bug 2819
+
+Broken-by: 3c55eef240
+---
+ doc/ChangeLog | 4 ++
+ src/exim.c | 7 ++-
+ src/filtertest.c | 16 +++----
+ src/functions.h | 4 ++
+ src/globals.c | 21 +++++----
+ src/globals.h | 3 ++
+ src/receive.c | 78 ++++++++++++++++++++++------------
+ src/smtp_in.c | 24 ++++++++++-
+ src/tls-gnu.c | 9 ++++
+ src/tls-openssl.c | 8 ++++
+ src/transports/autoreply.c | 13 +++---
+ 11 files changed, 133 insertions(+), 54 deletions(-)
+
+--- a/doc/ChangeLog
++++ b/doc/ChangeLog
+@@ -1,9 +1,13 @@
+ This document describes *changes* to previous versions, that might
+ affect Exim's operation, with an unchanged configuration file. For new
+ options, and new features, see the NewStuff file next to this ChangeLog.
+
++JH/05 Bug 2819: speed up command-line messages being read in. Previously a
++ time check was being done for every character; replace that with one
++ per buffer.
++
+
+ Exim version 4.95
+ -----------------
+
+ JH/01 Bug 1329: Fix format of Maildir-format filenames to match other mail-
+--- a/src/exim.c
++++ b/src/exim.c
+@@ -5382,11 +5382,11 @@
+
+ if (smtp_input)
+ {
+ if (!f.is_inetd) set_process_info("accepting a local %sSMTP message from <%s>",
+ smtp_batched_input? "batched " : "",
+- (sender_address!= NULL)? sender_address : originator_login);
++ sender_address ? sender_address : originator_login);
+ }
+ else
+ {
+ int old_pool = store_pool;
+ store_pool = POOL_PERM;
+@@ -5432,11 +5432,12 @@
+ mac_smtp_fflush();
+ exim_exit(EXIT_SUCCESS);
+ }
+ }
+
+-/* Otherwise, set up the input size limit here. */
++/* Otherwise, set up the input size limit here and set no stdin stdio buffer
++(we handle buferring so as to have visibility of fill level). */
+
+ else
+ {
+ thismessage_size_limit = expand_string_integer(message_size_limit, TRUE);
+ if (expand_string_message)
+@@ -5444,10 +5445,12 @@
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand "
+ "message_size_limit: %s", expand_string_message);
+ else
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
+ "message_size_limit: %s", expand_string_message);
++
++ setvbuf(stdin, NULL, _IONBF, 0);
+ }
+
+ /* Loop for several messages when reading SMTP input. If we fork any child
+ processes, we don't want to wait for them unless synchronous delivery is
+ requested, so set SIGCHLD to SIG_IGN in that case. This is not necessarily the
+--- a/src/filtertest.c
++++ b/src/filtertest.c
+@@ -43,15 +43,15 @@
+ s = message_body_end;
+ body_len = 0;
+ body_linecount = 0;
+ header_size = message_size;
+
+-if (!dot_ended && !feof(stdin))
++if (!dot_ended && !stdin_feof())
+ {
+ if (!f.dot_ends)
+ {
+- while ((ch = getc(stdin)) != EOF)
++ while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
+ {
+ if (ch == 0) body_zerocount++;
+ if (ch == '\n') body_linecount++;
+ if (body_len < message_body_visible) message_body[body_len++] = ch;
+ *s++ = ch;
+@@ -60,11 +60,11 @@
+ }
+ }
+ else
+ {
+ int ch_state = 1;
+- while ((ch = getc(stdin)) != EOF)
++ while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
+ {
+ if (ch == 0) body_zerocount++;
+ switch (ch_state)
+ {
+ case 0: /* Normal state */
+@@ -97,10 +97,11 @@
+ }
+ READ_END: ;
+ }
+ if (s == message_body_end || s[-1] != '\n') body_linecount++;
+ }
++debug_printf("%s %d\n", __FUNCTION__, __LINE__);
+
+ message_body[body_len] = 0;
+ message_body_size = message_size - header_size;
+
+ /* body_len stops at message_body_visible; it if got there, we may have
+@@ -248,11 +249,11 @@
+ }
+
+ /* For a filter, set up the message_body variables and the message size if this
+ is the first time this function has been called. */
+
+-if (message_body == NULL) read_message_body(dot_ended);
++if (!message_body) read_message_body(dot_ended);
+
+ /* Now pass the filter file to the function that interprets it. Because
+ filter_test is not FILTER_NONE, the interpreter will output comments about what
+ it is doing. No need to clean up store. Indeed, we must not, because we may be
+ testing a system filter that is going to be followed by a user filter test. */
+@@ -267,14 +268,13 @@
+ f.enable_dollar_recipients = FALSE;
+ f.system_filtering = FALSE;
+ }
+ else
+ {
+- yield = (filter_type == FILTER_SIEVE)?
+- sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
+- :
+- filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
++ yield = filter_type == FILTER_SIEVE
++ ? sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
++ : filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
+ }
+
+ return yield != FF_ERROR;
+ }
+
+--- a/src/functions.h
++++ b/src/functions.h
+@@ -66,10 +66,11 @@
+ extern uschar *tls_field_from_dn(uschar *, const uschar *);
+ extern void tls_free_cert(void **);
+ extern int tls_getc(unsigned);
+ extern uschar *tls_getbuf(unsigned *);
+ extern void tls_get_cache(unsigned);
++extern BOOL tls_hasc(void);
+ extern BOOL tls_import_cert(const uschar *, void **);
+ extern BOOL tls_is_name_for_cert(const uschar *, void *);
+ # ifdef USE_OPENSSL
+ extern BOOL tls_openssl_options_parse(uschar *, long *);
+ # endif
+@@ -148,10 +149,11 @@
+ extern uschar *b64encode(const uschar *, int);
+ extern uschar *b64encode_taint(const uschar *, int, BOOL);
+ extern int b64decode(const uschar *, uschar **);
+ extern int bdat_getc(unsigned);
+ extern uschar *bdat_getbuf(unsigned *);
++extern BOOL bdat_hasc(void);
+ extern int bdat_ungetc(int);
+ extern void bdat_flush_data(void);
+
+ extern void bits_clear(unsigned int *, size_t, int *);
+ extern void bits_set(unsigned int *, size_t, int *);
+@@ -492,10 +494,11 @@
+ uschar **, uschar *);
+ extern BOOL smtp_get_port(uschar *, address_item *, int *, uschar *);
+ extern int smtp_getc(unsigned);
+ extern uschar *smtp_getbuf(unsigned *);
+ extern void smtp_get_cache(unsigned);
++extern BOOL smtp_hasc(void);
+ extern int smtp_handle_acl_fail(int, int, uschar *, uschar *);
+ extern void smtp_log_no_mail(void);
+ extern void smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
+ extern void smtp_proxy_tls(void *, uschar *, size_t, int *, int) NORETURN;
+ extern BOOL smtp_read_response(void *, uschar *, int, int, int);
+@@ -521,10 +524,11 @@
+ extern uschar *spool_sender_from_msgid(const uschar *);
+ extern int spool_write_header(uschar *, int, uschar **);
+ extern int stdin_getc(unsigned);
+ extern int stdin_feof(void);
+ extern int stdin_ferror(void);
++extern BOOL stdin_hasc(void);
+ extern int stdin_ungetc(int);
+
+ extern void store_exit(void);
+ extern void store_init(void);
+ extern void store_writeprotect(int);
+--- a/src/globals.c
++++ b/src/globals.c
+@@ -169,20 +169,23 @@
+ /* Input-reading functions for messages, so we can use special ones for
+ incoming TCP/IP. The defaults use stdin. We never need these for any
+ stand-alone tests. */
+
+ #if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
+-int (*lwr_receive_getc)(unsigned) = stdin_getc;
++int (*lwr_receive_getc)(unsigned) = stdin_getc;
+ uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
+-int (*lwr_receive_ungetc)(int) = stdin_ungetc;
+-int (*receive_getc)(unsigned) = stdin_getc;
+-uschar * (*receive_getbuf)(unsigned *) = NULL;
+-void (*receive_get_cache)(unsigned) = NULL;
+-int (*receive_ungetc)(int) = stdin_ungetc;
+-int (*receive_feof)(void) = stdin_feof;
+-int (*receive_ferror)(void) = stdin_ferror;
+-BOOL (*receive_smtp_buffered)(void) = NULL; /* Only used for SMTP */
++int (*lwr_receive_ungetc)(int) = stdin_ungetc;
++BOOL (*lwr_receive_hasc)(void) = stdin_hasc;
++
++int (*receive_getc)(unsigned) = stdin_getc;
++uschar * (*receive_getbuf)(unsigned *) = NULL;
++void (*receive_get_cache)(unsigned) = NULL;
++BOOL (*receive_hasc)(void) = stdin_hasc;
++int (*receive_ungetc)(int) = stdin_ungetc;
++int (*receive_feof)(void) = stdin_feof;
++int (*receive_ferror)(void) = stdin_ferror;
++BOOL (*receive_smtp_buffered)(void) = NULL; /* Only used for SMTP */
+ #endif
+
+
+ /* List of per-address expansion variables for clearing and saving/restoring
+ when verifying one address while routing/verifying another. We have to have
+--- a/src/globals.h
++++ b/src/globals.h
+@@ -159,13 +159,16 @@
+ /* Input-reading functions for messages, so we can use special ones for
+ incoming TCP/IP. */
+
+ extern int (*lwr_receive_getc)(unsigned);
+ extern uschar * (*lwr_receive_getbuf)(unsigned *);
++extern BOOL (*lwr_receive_hasc)(void);
+ extern int (*lwr_receive_ungetc)(int);
++
+ extern int (*receive_getc)(unsigned);
+ extern uschar * (*receive_getbuf)(unsigned *);
++extern BOOL (*receive_hasc)(void);
+ extern void (*receive_get_cache)(unsigned);
+ extern int (*receive_ungetc)(int);
+ extern int (*receive_feof)(void);
+ extern int (*receive_ferror)(void);
+ extern BOOL (*receive_smtp_buffered)(void);
+--- a/src/receive.c
++++ b/src/receive.c
+@@ -42,46 +42,75 @@
+ /* These are the default functions that are set up in the variables such as
+ receive_getc initially. They just call the standard functions, passing stdin as
+ the file. (When SMTP input is occurring, different functions are used by
+ changing the pointer variables.) */
+
++uschar stdin_buf[4096];
++uschar * stdin_inptr = stdin_buf;
++uschar * stdin_inend = stdin_buf;
++
++static BOOL
++stdin_refill(void)
++{
++size_t rc = fread(stdin_buf, 1, sizeof(stdin_buf), stdin);
++if (rc <= 0)
++ {
++ if (had_data_timeout)
++ {
++ fprintf(stderr, "exim: timed out while reading - message abandoned\n");
++ log_write(L_lost_incoming_connection,
++ LOG_MAIN, "timed out while reading local message");
++ receive_bomb_out(US"data-timeout", NULL); /* Does not return */
++ }
++ if (had_data_sigint)
++ {
++ if (filter_test == FTEST_NONE)
++ {
++ fprintf(stderr, "\nexim: %s received - message abandoned\n",
++ had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
++ log_write(0, LOG_MAIN, "%s received while reading local message",
++ had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
++ }
++ receive_bomb_out(US"signal-exit", NULL); /* Does not return */
++ }
++ return FALSE;
++ }
++stdin_inend = stdin_buf + rc;
++stdin_inptr = stdin_buf;
++return TRUE;
++}
++
+ int
+ stdin_getc(unsigned lim)
+ {
+-int c = getc(stdin);
++if (stdin_inptr >= stdin_inend)
++ if (!stdin_refill())
++ return EOF;
++return *stdin_inptr++;
++}
+
+-if (had_data_timeout)
+- {
+- fprintf(stderr, "exim: timed out while reading - message abandoned\n");
+- log_write(L_lost_incoming_connection,
+- LOG_MAIN, "timed out while reading local message");
+- receive_bomb_out(US"data-timeout", NULL); /* Does not return */
+- }
+-if (had_data_sigint)
+- {
+- if (filter_test == FTEST_NONE)
+- {
+- fprintf(stderr, "\nexim: %s received - message abandoned\n",
+- had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
+- log_write(0, LOG_MAIN, "%s received while reading local message",
+- had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
+- }
+- receive_bomb_out(US"signal-exit", NULL); /* Does not return */
+- }
+-return c;
++
++BOOL
++stdin_hasc(void)
++{
++return stdin_inptr < stdin_inend;
+ }
+
+ int
+ stdin_ungetc(int c)
+ {
+-return ungetc(c, stdin);
++if (stdin_inptr <= stdin_buf)
++ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in stdin_ungetc");
++
++*--stdin_inptr = c;
++return c;
+ }
+
+ int
+ stdin_feof(void)
+ {
+-return feof(stdin);
++return stdin_hasc() ? FALSE : feof(stdin);
+ }
+
+ int
+ stdin_ferror(void)
+ {
+@@ -586,11 +615,11 @@
+ the file copy. */
+
+ static void
+ log_close_chk(void)
+ {
+-if (!receive_timeout)
++if (!receive_timeout && !receive_hasc())
+ {
+ struct timeval t;
+ timesince(&t, &received_time);
+ if (t.tv_sec > 30*60)
+ mainlog_close();
+@@ -652,15 +681,10 @@
+
+ if (!f.dot_ends)
+ {
+ int last_ch = '\n';
+
+-/*XXX we do a gettimeofday before checking for every received char,
+-which is hardly clever. The function-indirection doesn't help, but
+-an additional function to check for nonempty read buffer would help.
+-See stdin_getc() / smtp_getc() / tls_getc() / bdat_getc(). */
+-
+ for ( ;
+ log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF;
+ last_ch = ch)
+ {
+ if (ch == 0) body_zerocount++;
+--- a/src/smtp_in.c
++++ b/src/smtp_in.c
+@@ -561,10 +561,16 @@
+ if (!smtp_refill(lim))
+ return EOF;
+ return *smtp_inptr++;
+ }
+
++BOOL
++smtp_hasc(void)
++{
++return smtp_inptr < smtp_inend;
++}
++
+ uschar *
+ smtp_getbuf(unsigned * len)
+ {
+ unsigned size;
+ uschar * buf;
+@@ -743,10 +749,18 @@
+ }
+ }
+ }
+ }
+
++BOOL
++bdat_hasc(void)
++{
++if (chunking_data_left > 0)
++ return lwr_receive_hasc();
++return TRUE;
++}
++
+ uschar *
+ bdat_getbuf(unsigned * len)
+ {
+ uschar * buf;
+
+@@ -782,40 +796,44 @@
+ bdat_push_receive_functions(void)
+ {
+ /* push the current receive_* function on the "stack", and
+ replace them by bdat_getc(), which in turn will use the lwr_receive_*
+ functions to do the dirty work. */
+-if (lwr_receive_getc == NULL)
++if (!lwr_receive_getc)
+ {
+ lwr_receive_getc = receive_getc;
+ lwr_receive_getbuf = receive_getbuf;
++ lwr_receive_hasc = receive_hasc;
+ lwr_receive_ungetc = receive_ungetc;
+ }
+ else
+ {
+ DEBUG(D_receive) debug_printf("chunking double-push receive functions\n");
+ }
+
+ receive_getc = bdat_getc;
+ receive_getbuf = bdat_getbuf;
++receive_hasc = bdat_hasc;
+ receive_ungetc = bdat_ungetc;
+ }
+
+ static inline void
+ bdat_pop_receive_functions(void)
+ {
+-if (lwr_receive_getc == NULL)
++if (!lwr_receive_getc)
+ {
+ DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
+ return;
+ }
+ receive_getc = lwr_receive_getc;
+ receive_getbuf = lwr_receive_getbuf;
++receive_hasc = lwr_receive_hasc;
+ receive_ungetc = lwr_receive_ungetc;
+
+ lwr_receive_getc = NULL;
+ lwr_receive_getbuf = NULL;
++lwr_receive_hasc = NULL;
+ lwr_receive_ungetc = NULL;
+ }
+
+ /*************************************************
+ * SMTP version of ungetc() *
+@@ -2574,16 +2592,18 @@
+ smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0';
+
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
++receive_hasc = smtp_hasc;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+ lwr_receive_getc = NULL;
+ lwr_receive_getbuf = NULL;
++lwr_receive_hasc = NULL;
+ lwr_receive_ungetc = NULL;
+ smtp_inptr = smtp_inend = smtp_inbuffer;
+ smtp_had_eof = smtp_had_error = 0;
+
+ /* Set up the message size limit; this may be host-specific */
+--- a/src/tls-gnu.c
++++ b/src/tls-gnu.c
+@@ -3136,10 +3136,11 @@
+ state->xfer_buffer = store_malloc(ssl_xfer_buffer_size);
+
+ receive_getc = tls_getc;
+ receive_getbuf = tls_getbuf;
+ receive_get_cache = tls_get_cache;
++receive_hasc = tls_hasc;
+ receive_ungetc = tls_ungetc;
+ receive_feof = tls_feof;
+ receive_ferror = tls_ferror;
+ receive_smtp_buffered = tls_smtp_buffered;
+
+@@ -3738,10 +3739,11 @@
+ if (!ct_ctx) /* server */
+ {
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
++ receive_hasc = smtp_hasc;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+ }
+@@ -3852,10 +3854,17 @@
+ /* Something in the buffer; return next uschar */
+
+ return state->xfer_buffer[state->xfer_buffer_lwm++];
+ }
+
++BOOL
++tls_hasc(void)
++{
++exim_gnutls_state_st * state = &state_server;
++return state->xfer_buffer_lwm < state->xfer_buffer_hwm;
++}
++
+ uschar *
+ tls_getbuf(unsigned * len)
+ {
+ exim_gnutls_state_st * state = &state_server;
+ unsigned size;
+--- a/src/tls-openssl.c
++++ b/src/tls-openssl.c
+@@ -3348,10 +3348,11 @@
+ ssl_xfer_eof = ssl_xfer_error = FALSE;
+
+ receive_getc = tls_getc;
+ receive_getbuf = tls_getbuf;
+ receive_get_cache = tls_get_cache;
++receive_hasc = tls_hasc;
+ receive_ungetc = tls_ungetc;
+ receive_feof = tls_feof;
+ receive_ferror = tls_ferror;
+ receive_smtp_buffered = tls_smtp_buffered;
+
+@@ -4124,10 +4125,16 @@
+ /* Something in the buffer; return next uschar */
+
+ return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+ }
+
++BOOL
++tls_hasc(void)
++{
++return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm;
++}
++
+ uschar *
+ tls_getbuf(unsigned * len)
+ {
+ unsigned size;
+ uschar * buf;
+@@ -4413,10 +4420,11 @@
+ #endif
+
+ receive_getc = smtp_getc;
+ receive_getbuf = smtp_getbuf;
+ receive_get_cache = smtp_get_cache;
++ receive_hasc = smtp_hasc;
+ receive_ungetc = smtp_ungetc;
+ receive_feof = smtp_feof;
+ receive_ferror = smtp_ferror;
+ receive_smtp_buffered = smtp_buffered;
+ tls_in.active.tls_ctx = NULL;
+--- a/src/transports/autoreply.c
++++ b/src/transports/autoreply.c
+@@ -644,10 +644,11 @@
+ if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n");
+ }
+
+ if (ff)
+ {
++debug_printf("%s %d: ff\n", __FUNCTION__, __LINE__);
+ while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
+ {
+ if (file_expand)
+ {
+ uschar *s = expand_string(big_buffer);
+@@ -667,16 +668,16 @@
+ /* Copy the original message if required, observing the return size
+ limit if we are returning the body. */
+
+ if (return_message)
+ {
+- uschar *rubric = (tblock->headers_only)?
+- US"------ This is a copy of the message's header lines.\n"
+- : (tblock->body_only)?
+- US"------ This is a copy of the body of the message, without the headers.\n"
+- :
+- US"------ This is a copy of the message, including all the headers.\n";
++debug_printf("%s %d: ret msg\n", __FUNCTION__, __LINE__);
++ uschar *rubric = tblock->headers_only
++ ? US"------ This is a copy of the message's header lines.\n"
++ : tblock->body_only
++ ? US"------ This is a copy of the body of the message, without the headers.\n"
++ : US"------ This is a copy of the message, including all the headers.\n";
+ transport_ctx tctx = {
+ .u = {.fd = fileno(fp)},
+ .tblock = tblock,
+ .addr = addr,
+ .check_string = NULL,
diff --git a/mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch b/mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch
new file mode 100644
index 000000000000..93c99a4ef8f2
--- /dev/null
+++ b/mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch
@@ -0,0 +1,931 @@
+From dd19ce4f24eec64177cdcfcf294b8efbb631a24b Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Wed, 17 Nov 2021 17:19:54 +0000
+Subject: [PATCH] select() -> poll(). Bug 2831
+
+---
+ doc/ChangeLog | 8 +++
+ src/daemon.c | 126 +++++++++++++++++++-------------------
+ src/deliver.c | 54 ++++++++--------
+ src/exim.c | 9 +--
+ src/expand.c | 6 +-
+ src/functions.h | 7 +++
+ src/ip.c | 12 +---
+ src/malware.c | 6 +-
+ src/receive.c | 15 +----
+ src/smtp_in.c | 18 +-----
+ src/spam.c | 42 ++++---------
+ src/transport.c | 4 +-
+ src/transports/smtp.c | 37 ++++-------
+ 13 files changed, 142 insertions(+), 202 deletions(-)
+
+diff --git a/doc/ChangeLog b/doc/ChangeLog
+index 7f6814d5e..58996c3f8 100644
+--- a/doc/ChangeLog
++++ b/doc/ChangeLog
+@@ -40,6 +40,14 @@ JH/09 Fix macro-definition during "-be" expansion testing. The move to
+ write-protected store for macros had not accounted for these runtime
+ additions; fix by removing this protection for "-be" mode.
+
++JH/10 Convert all uses of select() to poll(). FreeBSD 12.2 was found to be
++ handing out large-numbered file descriptors, violating the usual Unix
++ assumption (and required by Posix) that the lowest possible number will be
++ allocated by the kernel when a new one is needed. In the daemon, and any
++ child procesees, values higher than 1024 (being bigger than FD_SETSIZE)
++ are not useable for FD_SET() [and hence select()] and overwrite the stack.
++ Assorted crashes happen.
++
+
+ Exim version 4.95
+ -----------------
+diff --git a/src/daemon.c b/src/daemon.c
+index 0b8d5d595..a248a4f40 100644
+--- a/src/daemon.c
++++ b/src/daemon.c
+@@ -87,7 +87,7 @@ sigchld_seen = TRUE;
+ }
+
+
+-/* SIGTERM handler. Try to get the damon pif file removed
++/* SIGTERM handler. Try to get the damon pid file removed
+ before exiting. */
+
+ static void
+@@ -141,7 +141,7 @@ Uunlink(s);
+
+ static void
+ close_daemon_sockets(int daemon_notifier_fd,
+- int * listen_sockets, int listen_socket_count)
++ struct pollfd * fd_polls, int listen_socket_count)
+ {
+ if (daemon_notifier_fd >= 0)
+ {
+@@ -152,7 +152,7 @@ if (daemon_notifier_fd >= 0)
+ #endif
+ }
+
+-for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]);
++for (int i = 0; i < listen_socket_count; i++) (void) close(fd_polls[i].fd);
+ }
+
+
+@@ -167,7 +167,7 @@ is required so that they can be closed in the sub-process. Take care not to
+ leak store in this process - reset the stacking pool at the end.
+
+ Arguments:
+- listen_sockets sockets which are listening for incoming calls
++ fd_polls sockets which are listening for incoming calls
+ listen_socket_count count of listening sockets
+ accept_socket socket of the current accepted call
+ accepted socket information about the current call
+@@ -176,7 +176,7 @@ Returns: nothing
+ */
+
+ static void
+-handle_smtp_call(int *listen_sockets, int listen_socket_count,
++handle_smtp_call(struct pollfd *fd_polls, int listen_socket_count,
+ int accept_socket, struct sockaddr *accepted)
+ {
+ pid_t pid;
+@@ -459,7 +459,7 @@ if (pid == 0)
+ extensive comment before the reception loop in exim.c for a fuller
+ explanation of this logic. */
+
+- close_daemon_sockets(daemon_notifier_fd, listen_sockets, listen_socket_count);
++ close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
+
+ /* Set FD_CLOEXEC on the SMTP socket. We don't want any rogue child processes
+ to be able to communicate with them, under any circumstances. */
+@@ -1305,13 +1305,6 @@ return FALSE;
+
+
+
+-static void
+-add_listener_socket(int fd, fd_set * fds, int * fd_max)
+-{
+-FD_SET(fd, fds);
+-if (fd > *fd_max) *fd_max = fd;
+-}
+-
+ /*************************************************
+ * Exim Daemon Mainline *
+ *************************************************/
+@@ -1339,9 +1332,8 @@ void
+ daemon_go(void)
+ {
+ struct passwd * pw;
+-int * listen_sockets = NULL;
+-int listen_socket_count = 0, listen_fd_max = 0;
+-fd_set select_listen;
++struct pollfd * fd_polls, * tls_watch_poll = NULL, * dnotify_poll = NULL;
++int listen_socket_count = 0, poll_fd_count;
+ ip_address_item * addresses = NULL;
+ time_t last_connection_time = (time_t)0;
+ int local_queue_run_max = atoi(CS expand_string(queue_run_max));
+@@ -1353,17 +1345,21 @@ debugging lines get the pid added. */
+
+ DEBUG(D_any|D_v) debug_selector |= D_pid;
+
+-FD_ZERO(&select_listen);
++/* Allocate enough pollstructs for inetd mode plus the ancillary sockets;
++also used when there are no listen sockets. */
++
++fd_polls = store_get(sizeof(struct pollfd) * 3, FALSE);
++
+ if (f.inetd_wait_mode)
+ {
+ listen_socket_count = 1;
+- listen_sockets = store_get(sizeof(int), FALSE);
+ (void) close(3);
+ if (dup2(0, 3) == -1)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "failed to dup inetd socket safely away: %s", strerror(errno));
+
+- listen_sockets[0] = 3;
++ fd_polls[0].fd = 3;
++ fd_polls[0].events = POLLIN;
+ (void) close(0);
+ (void) close(1);
+ (void) close(2);
+@@ -1390,9 +1386,6 @@ if (f.inetd_wait_mode)
+ if (setsockopt(3, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to set socket NODELAY: %s",
+ strerror(errno));
+-
+- FD_SET(3, &select_listen);
+- listen_fd_max = 3;
+ }
+
+
+@@ -1686,11 +1679,16 @@ if (f.daemon_listen && !f.inetd_wait_mode)
+ }
+ }
+
+- /* Get a vector to remember all the sockets in */
++ /* Get a vector to remember all the sockets in.
++ Two extra elements for the ancillary sockets */
+
+ for (ipa = addresses; ipa; ipa = ipa->next)
+ listen_socket_count++;
+- listen_sockets = store_get(sizeof(int) * listen_socket_count, FALSE);
++ fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2),
++ FALSE);
++ for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2;
++ p++)
++ { p->fd = -1; p->events = POLLIN; }
+
+ } /* daemon_listen but not inetd_wait_mode */
+
+@@ -1795,7 +1793,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
+ wildcard = ipa->address[0] == 0;
+ }
+
+- if ((listen_sockets[sk] = fd = ip_socket(SOCK_STREAM, af)) < 0)
++ if ((fd_polls[sk].fd = fd = ip_socket(SOCK_STREAM, af)) < 0)
+ {
+ if (check_special_case(0, addresses, ipa, FALSE))
+ {
+@@ -1804,7 +1802,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
+ goto SKIP_SOCKET;
+ }
+ log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
+- (af == AF_INET6)? '6' : '4', strerror(errno));
++ af == AF_INET6 ? '6' : '4', strerror(errno));
+ }
+
+ /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
+@@ -1903,8 +1901,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
+ f.tcp_fastopen_ok = FALSE;
+ }
+ #endif
+-
+- add_listener_socket(fd, &select_listen, &listen_fd_max);
++ fd_polls[sk].fd = fd;
+ continue;
+ }
+
+@@ -2187,14 +2184,21 @@ tls_daemon_init();
+
+ /* Add ancillary sockets to the set for select */
+
++poll_fd_count = listen_socket_count;
+ #ifndef DISABLE_TLS
+ if (tls_watch_fd >= 0)
+- add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max);
++ {
++ tls_watch_poll = &fd_polls[poll_fd_count++];
++ tls_watch_poll->fd = tls_watch_fd;
++ tls_watch_poll->events = POLLIN;
++ }
+ #endif
+ if (daemon_notifier_fd >= 0)
+- add_listener_socket(daemon_notifier_fd, &select_listen, &listen_fd_max);
+-
+-listen_fd_max++;
++ {
++ dnotify_poll = &fd_polls[poll_fd_count++];
++ dnotify_poll->fd = daemon_notifier_fd;
++ dnotify_poll->events = POLLIN;
++ }
+
+ /* Close the log so it can be renamed and moved. In the few cases below where
+ this long-running process writes to the log (always exceptional conditions), it
+@@ -2293,7 +2297,7 @@ for (;;)
+ /* Close any open listening sockets in the child */
+
+ close_daemon_sockets(daemon_notifier_fd,
+- listen_sockets, listen_socket_count);
++ fd_polls, listen_socket_count);
+
+ /* Reset SIGHUP and SIGCHLD in the child in both cases. */
+
+@@ -2421,9 +2425,8 @@ for (;;)
+
+ if (f.daemon_listen)
+ {
+- int check_lsk = 0, lcount;
++ int lcount;
+ BOOL select_failed = FALSE;
+- fd_set fds = select_listen;
+
+ DEBUG(D_any) debug_printf("Listening...\n");
+
+@@ -2440,8 +2443,7 @@ for (;;)
+ errno = EINTR;
+ }
+ else
+- lcount = select(listen_fd_max, (SELECT_ARG2_TYPE *)&fds,
+- NULL, NULL, NULL);
++ lcount = poll(fd_polls, poll_fd_count, -1);
+
+ if (lcount < 0)
+ {
+@@ -2461,15 +2463,15 @@ for (;;)
+ handle_ending_processes();
+
+ #ifndef DISABLE_TLS
++ {
++ int old_tfd;
+ /* Create or rotate any required keys; handle (delayed) filewatch event */
+- for (int old_tfd = tls_daemon_tick(); old_tfd >= 0; )
+- {
+- FD_CLR(old_tfd, &select_listen);
+- if (old_tfd == listen_fd_max - 1) listen_fd_max = old_tfd;
+- if (tls_watch_fd >= 0)
+- add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max);
+- break;
+- }
++
++ if ((old_tfd = tls_daemon_tick()) >= 0)
++ for (struct pollfd * p = &fd_polls[listen_socket_count];
++ p < fd_polls + poll_fd_count; p++)
++ if (p->fd == old_tfd) { p->fd = tls_watch_fd ; break; }
++ }
+ #endif
+ errno = select_errno;
+ }
+@@ -2490,22 +2492,23 @@ for (;;)
+ if (!select_failed)
+ {
+ #if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
+- if (tls_watch_fd >= 0 && FD_ISSET(tls_watch_fd, &fds))
++ if (tls_watch_poll && tls_watch_poll->revents & POLLIN)
+ {
++ tls_watch_poll->revents = 0;
+ tls_watch_trigger_time = time(NULL); /* Set up delayed event */
+ tls_watch_discard_event(tls_watch_fd);
+ break; /* to top of daemon loop */
+ }
+ #endif
+- if (daemon_notifier_fd >= 0 && FD_ISSET(daemon_notifier_fd, &fds))
++ if (dnotify_poll && dnotify_poll->revents & POLLIN)
+ {
++ dnotify_poll->revents = 0;
+ sigalrm_seen = daemon_notification();
+ break; /* to top of daemon loop */
+ }
+- while (check_lsk < listen_socket_count)
+- {
+- int lfd = listen_sockets[check_lsk++];
+- if (FD_ISSET(lfd, &fds))
++ for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count;
++ p++)
++ if (p->revents & POLLIN)
+ {
+ EXIM_SOCKLEN_T alen = sizeof(accepted);
+ #ifdef TCP_INFO
+@@ -2516,23 +2519,23 @@ for (;;)
+
+ smtp_listen_backlog = 0;
+ if ( smtp_backlog_monitor > 0
+- && getsockopt(lfd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0)
++ && getsockopt(p->fd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0)
+ {
+ # ifdef EXIM_HAVE_TCPI_UNACKED
+ DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
+- lfd, ti.tcpi_sacked, ti.tcpi_unacked);
++ p->fd, ti.tcpi_sacked, ti.tcpi_unacked);
+ smtp_listen_backlog = ti.tcpi_unacked;
+ # elif defined(__FreeBSD__) /* This does not work. Investigate kernel sourcecode. */
+ DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
+- lfd, ti.__tcpi_sacked, ti.__tcpi_unacked);
++ p->fd, ti.__tcpi_sacked, ti.__tcpi_unacked);
+ smtp_listen_backlog = ti.__tcpi_unacked;
+ # endif
+ }
+ #endif
+- accept_socket = accept(lfd, (struct sockaddr *)&accepted, &alen);
++ p->revents = 0;
++ accept_socket = accept(p->fd, (struct sockaddr *)&accepted, &alen);
+ break;
+ }
+- }
+ }
+
+ /* If select or accept has failed and this was not caused by an
+@@ -2591,7 +2594,7 @@ for (;;)
+ #endif
+ if (inetd_wait_timeout)
+ last_connection_time = time(NULL);
+- handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,
++ handle_smtp_call(fd_polls, listen_socket_count, accept_socket,
+ (struct sockaddr *)&accepted);
+ }
+ }
+@@ -2606,10 +2609,8 @@ for (;;)
+
+ else
+ {
+- struct timeval tv;
+- tv.tv_sec = queue_interval;
+- tv.tv_usec = 0;
+- select(0, NULL, NULL, NULL, &tv);
++ struct pollfd p;
++ poll(&p, 0, queue_interval * 1000);
+ handle_ending_processes();
+ }
+
+@@ -2634,8 +2635,7 @@ for (;;)
+ {
+ log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
+ getpid());
+- close_daemon_sockets(daemon_notifier_fd,
+- listen_sockets, listen_socket_count);
++ close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
+ ALARM_CLR(0);
+ signal(SIGHUP, SIG_IGN);
+ sighup_argv[0] = exim_path;
+diff --git a/src/deliver.c b/src/deliver.c
+index 4594c4a1d..8aad811c6 100644
+--- a/src/deliver.c
++++ b/src/deliver.c
+@@ -74,6 +74,7 @@ static BOOL update_spool;
+ static BOOL remove_journal;
+ static int parcount = 0;
+ static pardata *parlist = NULL;
++static struct pollfd *parpoll;
+ static int return_count;
+ static uschar *frozen_info = US"";
+ static uschar *used_return_path = NULL;
+@@ -3306,7 +3307,7 @@ BOOL done = p->done;
+
+ /* Loop through all items, reading from the pipe when necessary. The pipe
+ used to be non-blocking. But I do not see a reason for using non-blocking I/O
+-here, as the preceding select() tells us, if data is available for reading.
++here, as the preceding poll() tells us, if data is available for reading.
+
+ A read() on a "selected" handle should never block, but(!) it may return
+ less data then we expected. (The buffer size we pass to read() shouldn't be
+@@ -3840,7 +3841,7 @@ static address_item *
+ par_wait(void)
+ {
+ int poffset, status;
+-address_item *addr, *addrlist;
++address_item * addr, * addrlist;
+ pid_t pid;
+
+ set_process_info("delivering %s: waiting for a remote delivery subprocess "
+@@ -3850,18 +3851,18 @@ set_process_info("delivering %s: waiting for a remote delivery subprocess "
+ existence - in which case give an error return. We cannot proceed just by
+ waiting for a completion, because a subprocess may have filled up its pipe, and
+ be waiting for it to be emptied. Therefore, if no processes have finished, we
+-wait for one of the pipes to acquire some data by calling select(), with a
++wait for one of the pipes to acquire some data by calling poll(), with a
+ timeout just in case.
+
+ The simple approach is just to iterate after reading data from a ready pipe.
+ This leads to non-ideal behaviour when the subprocess has written its final Z
+ item, closed the pipe, and is in the process of exiting (the common case). A
+-call to waitpid() yields nothing completed, but select() shows the pipe ready -
++call to waitpid() yields nothing completed, but poll() shows the pipe ready -
+ reading it yields EOF, so you end up with busy-waiting until the subprocess has
+ actually finished.
+
+ To avoid this, if all the data that is needed has been read from a subprocess
+-after select(), an explicit wait() for it is done. We know that all it is doing
++after poll(), an explicit wait() for it is done. We know that all it is doing
+ is writing to the pipe and then exiting, so the wait should not be long.
+
+ The non-blocking waitpid() is to some extent just insurance; if we could
+@@ -3881,9 +3882,7 @@ for (;;) /* Normally we do not repeat this loop */
+ {
+ while ((pid = waitpid(-1, &status, WNOHANG)) <= 0)
+ {
+- struct timeval tv;
+- fd_set select_pipes;
+- int maxpipe, readycount;
++ int readycount;
+
+ /* A return value of -1 can mean several things. If errno != ECHILD, it
+ either means invalid options (which we discount), or that this process was
+@@ -3907,7 +3906,7 @@ for (;;) /* Normally we do not repeat this loop */
+ subprocesses are still in existence. If kill() gives an OK return, we know
+ it must be for one of our processes - it can't be for a re-use of the pid,
+ because if our process had finished, waitpid() would have found it. If any
+- of our subprocesses are in existence, we proceed to use select() as if
++ of our subprocesses are in existence, we proceed to use poll() as if
+ waitpid() had returned zero. I think this is safe. */
+
+ if (pid < 0)
+@@ -3931,7 +3930,7 @@ for (;;) /* Normally we do not repeat this loop */
+ if (poffset >= remote_max_parallel)
+ {
+ DEBUG(D_deliver) debug_printf("*** no delivery children found\n");
+- return NULL; /* This is the error return */
++ return NULL; /* This is the error return */
+ }
+ }
+
+@@ -3940,28 +3939,23 @@ for (;;) /* Normally we do not repeat this loop */
+ subprocess, but there are no completed subprocesses. See if any pipes are
+ ready with any data for reading. */
+
+- DEBUG(D_deliver) debug_printf("selecting on subprocess pipes\n");
++ DEBUG(D_deliver) debug_printf("polling subprocess pipes\n");
+
+- maxpipe = 0;
+- FD_ZERO(&select_pipes);
+ for (poffset = 0; poffset < remote_max_parallel; poffset++)
+ if (parlist[poffset].pid != 0)
+- {
+- int fd = parlist[poffset].fd;
+- FD_SET(fd, &select_pipes);
+- if (fd > maxpipe) maxpipe = fd;
+- }
++ {
++ parpoll[poffset].fd = parlist[poffset].fd;
++ parpoll[poffset].events = POLLIN;
++ }
++ else
++ parpoll[poffset].fd = -1;
+
+ /* Stick in a 60-second timeout, just in case. */
+
+- tv.tv_sec = 60;
+- tv.tv_usec = 0;
+-
+- readycount = select(maxpipe + 1, (SELECT_ARG2_TYPE *)&select_pipes,
+- NULL, NULL, &tv);
++ readycount = poll(parpoll, remote_max_parallel, 60 * 1000);
+
+ /* Scan through the pipes and read any that are ready; use the count
+- returned by select() to stop when there are no more. Select() can return
++ returned by poll() to stop when there are no more. Select() can return
+ with no processes (e.g. if interrupted). This shouldn't matter.
+
+ If par_read_pipe() returns TRUE, it means that either the terminating Z was
+@@ -3978,7 +3972,7 @@ for (;;) /* Normally we do not repeat this loop */
+ poffset++)
+ {
+ if ( (pid = parlist[poffset].pid) != 0
+- && FD_ISSET(parlist[poffset].fd, &select_pipes)
++ && parpoll[poffset].revents
+ )
+ {
+ readycount--;
+@@ -4016,7 +4010,7 @@ for (;;) /* Normally we do not repeat this loop */
+ "transport process list", pid);
+ } /* End of the "for" loop */
+
+-/* Come here when all the data was completely read after a select(), and
++/* Come here when all the data was completely read after a poll(), and
+ the process in pid has been wait()ed for. */
+
+ PROCESS_DONE:
+@@ -4051,7 +4045,7 @@ if ((status & 0xffff) != 0)
+ "%s %d",
+ addrlist->transport->driver_name,
+ status,
+- (msb == 0)? "terminated by signal" : "exit code",
++ msb == 0 ? "terminated by signal" : "exit code",
+ code);
+
+ if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT))
+@@ -4069,7 +4063,8 @@ if ((status & 0xffff) != 0)
+ /* Else complete reading the pipe to get the result of the delivery, if all
+ the data has not yet been obtained. */
+
+-else if (!parlist[poffset].done) (void)par_read_pipe(poffset, TRUE);
++else if (!parlist[poffset].done)
++ (void) par_read_pipe(poffset, TRUE);
+
+ /* Put the data count and return path into globals, mark the data slot unused,
+ decrement the count of subprocesses, and return the address chain. */
+@@ -4218,6 +4213,7 @@ if (!parlist)
+ parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
+ for (poffset = 0; poffset < remote_max_parallel; poffset++)
+ parlist[poffset].pid = 0;
++ parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE);
+ }
+
+ /* Now loop for each remote delivery */
+@@ -4613,7 +4609,7 @@ nonmatch domains
+ that it can use either of them, though it prefers O_NONBLOCK, which
+ distinguishes between EOF and no-more-data. */
+
+-/* The data appears in a timely manner and we already did a select on
++/* The data appears in a timely manner and we already did a poll on
+ all pipes, so I do not see a reason to use non-blocking IO here
+
+ #ifdef O_NONBLOCK
+diff --git a/src/exim.c b/src/exim.c
+index 133761de9..42db457c0 100644
+--- a/src/exim.c
++++ b/src/exim.c
+@@ -5735,13 +5735,8 @@ for (BOOL more = TRUE; more; )
+ the file copy. */
+
+ if (!receive_timeout)
+- {
+- struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 }; /* 30 minutes */
+- fd_set r;
+-
+- FD_ZERO(&r); FD_SET(0, &r);
+- if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
+- }
++ if (poll_one_fd(0, POLLIN, 30*60*1000) == 0) /* 30 minutes */
++ mainlog_close();
+
+ /* Read the data for the message. If filter_test is not FTEST_NONE, this
+ will just read the headers for the message, and not write anything onto the
+diff --git a/src/expand.c b/src/expand.c
+index 59554840e..bfae2a3c0 100644
+--- a/src/expand.c
++++ b/src/expand.c
+@@ -1760,8 +1760,6 @@ const uschar * where;
+ #ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
+ uschar * sname;
+ #endif
+-fd_set fds;
+-struct timeval tv;
+
+ if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+ {
+@@ -1805,9 +1803,7 @@ if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0)
+ buf[0] = NOTIFY_QUEUE_SIZE_REQ;
+ if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
+
+-FD_ZERO(&fds); FD_SET(fd, &fds);
+-tv.tv_sec = 2; tv.tv_usec = 0;
+-if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1)
++if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1)
+ {
+ DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
+ len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
+diff --git a/src/functions.h b/src/functions.h
+index 3dd890a00..0cf80dfbb 100644
+--- a/src/functions.h
++++ b/src/functions.h
+@@ -1255,6 +1255,13 @@ child_open(uschar **argv, uschar **envp, int newumask, int *infdptr,
+ outfdptr, make_leader, purpose);
+ }
+
++static inline int
++poll_one_fd(int fd, short pollbits, int tmo_millisec)
++{
++struct pollfd p = {.fd = fd, .events = pollbits};
++return poll(&p, 1, tmo_millisec);
++}
++
+ # endif /* !COMPILE_UTILITY */
+
+ /******************************************************************************/
+diff --git a/src/ip.c b/src/ip.c
+index d83d6f910..aa42343fb 100644
+--- a/src/ip.c
++++ b/src/ip.c
+@@ -589,9 +589,7 @@ Returns: TRUE => ready for i/o
+ BOOL
+ fd_ready(int fd, time_t timelimit)
+ {
+-fd_set select_inset;
+-int time_left = timelimit - time(NULL);
+-int rc;
++int rc, time_left = timelimit - time(NULL);
+
+ if (time_left <= 0)
+ {
+@@ -602,12 +600,8 @@ if (time_left <= 0)
+
+ do
+ {
+- struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 };
+- FD_ZERO (&select_inset);
+- FD_SET (fd, &select_inset);
+-
+ /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
+- rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv);
++ rc = poll_one_fd(fd, POLLIN, time_left * 1000);
+
+ /* If some interrupt arrived, just retry. We presume this to be rare,
+ but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes
+@@ -636,7 +630,7 @@ do
+ /* Checking the FD_ISSET is not enough, if we're interrupted, the
+ select_inset may still contain the 'input'. */
+ }
+-while (rc < 0 || !FD_ISSET(fd, &select_inset));
++while (rc < 0);
+ return TRUE;
+ }
+
+diff --git a/src/malware.c b/src/malware.c
+index 10a390dfa..d9ab3b9dd 100644
+--- a/src/malware.c
++++ b/src/malware.c
+@@ -277,11 +277,7 @@ int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
+ /* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
+ and, getting no response, wait for a long time. Impose a 5s max. */
+ if (fd >= 0)
+- {
+- struct timeval tv = {.tv_sec = 5};
+- fd_set fds;
+- FD_ZERO(&fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv);
+- }
++ (void) poll_one_fd(fd, POLLOUT, 5 * 1000);
+ #endif
+ return fd;
+ }
+diff --git a/src/receive.c b/src/receive.c
+index fab0f00c4..3adcbbd88 100644
+--- a/src/receive.c
++++ b/src/receive.c
+@@ -624,12 +624,8 @@ if (!receive_timeout && !receive_hasc())
+ if (t.tv_sec > 30*60)
+ mainlog_close();
+ else
+- {
+- fd_set r;
+- FD_ZERO(&r); FD_SET(0, &r);
+- t.tv_sec = 30*60 - t.tv_sec; t.tv_usec = 0;
+- if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
+- }
++ if (poll_one_fd(0, POLLIN, (30*60 - t.tv_sec) * 1000) == 0)
++ mainlog_close();
+ }
+ }
+
+@@ -4234,12 +4230,7 @@ response, but the chance of this happening should be small. */
+ if (smtp_input && sender_host_address && !f.sender_host_notsocket &&
+ !receive_smtp_buffered())
+ {
+- struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
+- fd_set select_check;
+- FD_ZERO(&select_check);
+- FD_SET(fileno(smtp_in), &select_check);
+-
+- if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
++ if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0)
+ {
+ int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
+ if (c != EOF) (receive_ungetc)(c); else
+diff --git a/src/smtp_in.c b/src/smtp_in.c
+index 824178e4d..7cb966f24 100644
+--- a/src/smtp_in.c
++++ b/src/smtp_in.c
+@@ -346,8 +346,6 @@ static BOOL
+ wouldblock_reading(void)
+ {
+ int fd, rc;
+-fd_set fds;
+-struct timeval tzero = {.tv_sec = 0, .tv_usec = 0};
+
+ #ifndef DISABLE_TLS
+ if (tls_in.active.sock >= 0)
+@@ -358,9 +356,7 @@ if (smtp_inptr < smtp_inend)
+ return FALSE;
+
+ fd = fileno(smtp_in);
+-FD_ZERO(&fds);
+-FD_SET(fd, &fds);
+-rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero);
++rc = poll_one_fd(fd, POLLIN, 0);
+
+ if (rc <= 0) return TRUE; /* Not ready to read */
+ rc = smtp_getc(GETC_BUFFER_UNLIMITED);
+@@ -3942,16 +3938,8 @@ log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
+ /* Pause, hoping client will FIN first so that they get the TIME_WAIT.
+ The socket should become readble (though with no data) */
+
+- {
+- int fd = fileno(smtp_in);
+- fd_set fds;
+- struct timeval t_limit = {.tv_sec = 0, .tv_usec = 200*1000};
+-
+- FD_ZERO(&fds);
+- FD_SET(fd, &fds);
+- (void) select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &t_limit);
+- }
+-#endif /*!DAEMON_CLOSE_NOWAIT*/
++(void) poll_one_fd(fileno(smtp_in), POLLIN, 200);
++#endif /*!SERVERSIDE_CLOSE_NOWAIT*/
+ }
+
+
+diff --git a/src/spam.c b/src/spam.c
+index 470e5fae7..e3316ed96 100644
+--- a/src/spam.c
++++ b/src/spam.c
+@@ -194,12 +194,6 @@ uschar *p,*q;
+ int override = 0;
+ time_t start;
+ size_t read, wrote;
+-#ifndef NO_POLL_H
+-struct pollfd pollfd;
+-#else /* Patch posted by Erik ? for OS X */
+-struct timeval select_tv; /* and applied by PH */
+-fd_set select_fd;
+-#endif
+ uschar *spamd_address_work;
+ spamd_address_container * sd;
+
+@@ -395,19 +389,19 @@ if (wrote == -1)
+ }
+
+ /* now send the file */
+-/* spamd sometimes accepts connections but doesn't read data off
+- * the connection. We make the file descriptor non-blocking so
+- * that the write will only write sufficient data without blocking
+- * and we poll the descriptor to make sure that we can write without
+- * blocking. Short writes are gracefully handled and if the whole
+- * transaction takes too long it is aborted.
+- * Note: poll() is not supported in OSX 10.2 and is reported to be
+- * broken in more recent versions (up to 10.4).
++/* spamd sometimes accepts connections but doesn't read data off the connection.
++We make the file descriptor non-blocking so that the write will only write
++sufficient data without blocking and we poll the descriptor to make sure that we
++can write without blocking. Short writes are gracefully handled and if the
++whole transaction takes too long it is aborted.
++
++Note: poll() is not supported in OSX 10.2 and is reported to be broken in more
++ recent versions (up to 10.4). Workaround using select() removed 2021/11 (jgh).
+ */
+-#ifndef NO_POLL_H
+-pollfd.fd = spamd_cctx.sock;
+-pollfd.events = POLLOUT;
++#ifdef NO_POLL_H
++# error Need poll(2) support
+ #endif
++
+ (void)fcntl(spamd_cctx.sock, F_SETFL, O_NONBLOCK);
+ do
+ {
+@@ -416,19 +410,7 @@ do
+ {
+ offset = 0;
+ again:
+-#ifndef NO_POLL_H
+- result = poll(&pollfd, 1, 1000);
+-
+-/* Patch posted by Erik ? for OS X and applied by PH */
+-#else
+- select_tv.tv_sec = 1;
+- select_tv.tv_usec = 0;
+- FD_ZERO(&select_fd);
+- FD_SET(spamd_cctx.sock, &select_fd);
+- result = select(spamd_cctx.sock+1, NULL, &select_fd, NULL, &select_tv);
+-#endif
+-/* End Erik's patch */
+-
++ result = poll_one_fd(spamd_cctx.sock, POLLOUT, 1000);
+ if (result == -1 && errno == EINTR)
+ goto again;
+ else if (result < 1)
+diff --git a/src/transport.c b/src/transport.c
+index 8c74030f0..ef523657e 100644
+--- a/src/transport.c
++++ b/src/transport.c
+@@ -253,7 +253,6 @@ for (int i = 0; i < 100; i++)
+
+ for(;;)
+ {
+- fd_set fds;
+ /* This code makes use of alarm() in order to implement the timeout. This
+ isn't a very tidy way of doing things. Using non-blocking I/O with select()
+ provides a neater approach. However, I don't know how to do this when TLS is
+@@ -281,8 +280,7 @@ for (int i = 0; i < 100; i++)
+ if (rc >= 0 || errno != ENOTCONN || connretry <= 0)
+ break;
+
+- FD_ZERO(&fds); FD_SET(fd, &fds);
+- select(fd+1, NULL, &fds, NULL, NULL); /* could set timout? */
++ poll_one_fd(fd, POLLOUT, -1); /* could set timeout? retval check? */
+ connretry--;
+ }
+
+diff --git a/src/transports/smtp.c b/src/transports/smtp.c
+index d321bd69e..c64bb7010 100644
+--- a/src/transports/smtp.c
++++ b/src/transports/smtp.c
+@@ -3550,8 +3550,8 @@ void
+ smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd,
+ int timeout)
+ {
+-fd_set rfds, efds;
+-int max_fd = MAX(pfd[0], tls_out.active.sock) + 1;
++struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN},
++ {.fd = pfd[0], .events = POLLIN}};
+ int rc, i;
+ BOOL send_tls_shutdown = TRUE;
+
+@@ -3560,23 +3560,16 @@ if ((rc = exim_fork(US"tls-proxy")))
+ _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+
+ set_process_info("proxying TLS connection for continued transport");
+-FD_ZERO(&rfds);
+-FD_SET(tls_out.active.sock, &rfds);
+-FD_SET(pfd[0], &rfds);
+
+-for (int fd_bits = 3; fd_bits; )
++do
+ {
+ time_t time_left = timeout;
+ time_t time_start = time(NULL);
+
+ /* wait for data */
+- efds = rfds;
+ do
+ {
+- struct timeval tv = { time_left, 0 };
+-
+- rc = select(max_fd,
+- (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv);
++ rc = poll(p, 2, time_left * 1000);
+
+ if (rc < 0 && errno == EINTR)
+ if ((time_left -= time(NULL) - time_start) > 0) continue;
+@@ -3589,23 +3582,22 @@ for (int fd_bits = 3; fd_bits; )
+
+ /* For errors where not readable, bomb out */
+
+- if (FD_ISSET(tls_out.active.sock, &efds) || FD_ISSET(pfd[0], &efds))
++ if (p[0].revents & POLLERR || p[1].revents & POLLERR)
+ {
+ DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
+- FD_ISSET(pfd[0], &efds) ? "proxy" : "tls");
+- if (!(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds)))
++ p[0].revents & POLLERR ? "tls" : "proxy");
++ if (!(p[0].revents & POLLIN || p[1].events & POLLIN))
+ goto done;
+ DEBUG(D_transport) debug_printf("- but also readable; no exit yet\n");
+ }
+ }
+- while (rc < 0 || !(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds)));
++ while (rc < 0 || !(p[0].revents & POLLIN || p[1].revents & POLLIN));
+
+ /* handle inbound data */
+- if (FD_ISSET(tls_out.active.sock, &rfds))
++ if (p[0].revents & POLLIN)
+ if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0) /* Expect -1 for EOF; */
+ { /* that reaps the TLS Close Notify record */
+- fd_bits &= ~1;
+- FD_CLR(tls_out.active.sock, &rfds);
++ p[0].fd = -1;
+ shutdown(pfd[0], SHUT_WR);
+ timeout = 5;
+ }
+@@ -3616,11 +3608,10 @@ for (int fd_bits = 3; fd_bits; )
+ /* Handle outbound data. We cannot combine payload and the TLS-close
+ due to the limitations of the (pipe) channel feeding us. Maybe use a unix-domain
+ socket? */
+- if (FD_ISSET(pfd[0], &rfds))
++ if (p[1].revents & POLLIN)
+ if ((rc = read(pfd[0], buf, bsize)) <= 0)
+ {
+- fd_bits &= ~2;
+- FD_CLR(pfd[0], &rfds);
++ p[1].fd = -1;
+
+ # ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */
+ (void) setsockopt(tls_out.active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
+@@ -3633,10 +3624,8 @@ for (int fd_bits = 3; fd_bits; )
+ for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
+ if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0)
+ goto done;
+-
+- if (fd_bits & 1) FD_SET(tls_out.active.sock, &rfds);
+- if (fd_bits & 2) FD_SET(pfd[0], &rfds);
+ }
++while (p[0].fd >= 0 || p[1].fd >= 0);
+
+ done:
+ if (send_tls_shutdown) tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT);
diff --git a/mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch b/mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch
new file mode 100644
index 000000000000..b156611bd0e6
--- /dev/null
+++ b/mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch
@@ -0,0 +1,140 @@
+From d73b9f478a2a5b299634acee4e05ff8ea25375a2 Mon Sep 17 00:00:00 2001
+From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+Date: Sun, 28 Nov 2021 17:26:40 +0000
+Subject: [PATCH] Fix basic memory use for SPARC. Bug 2838
+
+---
+ doc/ChangeLog | 5 +++++
+ src/store.c | 34 +++++++++++++++++++---------------
+ src/store.h | 2 +-
+ 3 files changed, 25 insertions(+), 16 deletions(-)
+
+--- a/doc/ChangeLog
++++ b/doc/ChangeLog
+@@ -14,6 +14,11 @@
+ are not useable for FD_SET() [and hence select()] and overwrite the stack.
+ Assorted crashes happen.
+
++JH/12 Bug 2838: Fix for i32lp64 hard-align platforms. Found for SPARC Linux,
++ though only once PCRE2 was introduced: the memory accounting used under
++ debug offset allocations by an int, giving a hard trap in early startup.
++ Change to using a size_t. Debug and fix by John Paul Adrian Glaubitz.
++
+
+ Exim version 4.95
+ -----------------
+--- a/src/store.c
++++ b/src/store.c
+@@ -190,11 +190,11 @@
+ [POOL_TAINT_MESSAGE] = US"tainted",
+ };
+ #endif
+
+
+-static void * internal_store_malloc(int, const char *, int);
++static void * internal_store_malloc(size_t, const char *, int);
+ static void internal_store_free(void *, const char *, int linenumber);
+
+ /******************************************************************************/
+ /* Initialisation, for things fragile with parameter channges when using
+ static initialisers. */
+@@ -859,30 +859,33 @@
+
+ Returns: pointer to gotten store (panic on failure)
+ */
+
+ static void *
+-internal_store_malloc(int size, const char *func, int line)
++internal_store_malloc(size_t size, const char *func, int line)
+ {
+ void * yield;
+
+-if (size < 0 || size >= INT_MAX/2)
++/* Check specifically for a possibly result of conversion from
++a negative int, to the (unsigned, wider) size_t */
++
++if (size >= INT_MAX/2)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+- "bad memory allocation requested (%d bytes) at %s %d",
+- size, func, line);
++ "bad memory allocation requested (%lld bytes) at %s %d",
++ (unsigned long long)size, func, line);
+
+-size += sizeof(int); /* space to store the size, used under debug */
++size += sizeof(size_t); /* space to store the size, used under debug */
+ if (size < 16) size = 16;
+
+-if (!(yield = malloc((size_t)size)))
++if (!(yield = malloc(size)))
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: "
+ "called from line %d in %s", size, line, func);
+
+ #ifndef COMPILE_UTILITY
+-DEBUG(D_any) *(int *)yield = size;
++DEBUG(D_any) *(size_t *)yield = size;
+ #endif
+-yield = US yield + sizeof(int);
++yield = US yield + sizeof(size_t);
+
+ if ((nonpool_malloc += size) > max_nonpool_malloc)
+ max_nonpool_malloc = nonpool_malloc;
+
+ /* Cut out the debugging stuff for utilities, but stop picky compilers from
+@@ -891,20 +894,20 @@
+ #ifndef COMPILE_UTILITY
+ /* If running in test harness, spend time making sure all the new store
+ is not filled with zeros so as to catch problems. */
+
+ if (f.running_in_test_harness)
+- memset(yield, 0xF0, (size_t)size - sizeof(int));
+-DEBUG(D_memory) debug_printf("--Malloc %6p %5d bytes\t%-20s %4d\tpool %5d nonpool %5d\n",
++ memset(yield, 0xF0, size - sizeof(size_t));
++DEBUG(D_memory) debug_printf("--Malloc %6p %5lld bytes\t%-20s %4d\tpool %5d nonpool %5d\n",
+ yield, size, func, line, pool_malloc, nonpool_malloc);
+ #endif /* COMPILE_UTILITY */
+
+ return yield;
+ }
+
+ void *
+-store_malloc_3(int size, const char *func, int linenumber)
++store_malloc_3(size_t size, const char *func, int linenumber)
+ {
+ if (n_nonpool_blocks++ > max_nonpool_blocks)
+ max_nonpool_blocks = n_nonpool_blocks;
+ return internal_store_malloc(size, func, linenumber);
+ }
+@@ -925,14 +928,15 @@
+ */
+
+ static void
+ internal_store_free(void * block, const char * func, int linenumber)
+ {
+-uschar * p = US block - sizeof(int);
++uschar * p = US block - sizeof(size_t);
+ #ifndef COMPILE_UTILITY
+-DEBUG(D_any) nonpool_malloc -= *(int *)p;
+-DEBUG(D_memory) debug_printf("----Free %6p %5d bytes\t%-20s %4d\n", block, *(int *)p, func, linenumber);
++DEBUG(D_any) nonpool_malloc -= *(size_t *)p;
++DEBUG(D_memory) debug_printf("----Free %6p %5lld bytes\t%-20s %4d\n",
++ block, (unsigned long long) *(size_t *)p, func, linenumber);
+ #endif
+ free(p);
+ }
+
+ void
+--- a/src/store.h
++++ b/src/store.h
+@@ -63,11 +63,11 @@
+ typedef void ** rmark;
+
+ extern BOOL store_extend_3(void *, BOOL, int, int, const char *, int);
+ extern void store_free_3(void *, const char *, int);
+ /* store_get_3 & store_get_perm_3 are in local_scan.h */
+-extern void *store_malloc_3(int, const char *, int) ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
++extern void *store_malloc_3(size_t, const char *, int) ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
+ extern rmark store_mark_3(const char *, int);
+ extern void *store_newblock_3(void *, BOOL, int, int, const char *, int);
+ extern void store_release_above_3(void *, const char *, int);
+ extern rmark store_reset_3(rmark, const char *, int);
+
diff --git a/mail/exim/files/patch-OS_os.c-FreeBSD b/mail/exim/files/patch-OS_os.c-FreeBSD
new file mode 100644
index 000000000000..99e89850ed0c
--- /dev/null
+++ b/mail/exim/files/patch-OS_os.c-FreeBSD
@@ -0,0 +1,15 @@
+--- OS/os.c-FreeBSD.orig 2021-10-11 17:03:56.119681000 +0200
++++ OS/os.c-FreeBSD 2021-10-11 17:04:27.802597000 +0200
+@@ -16,10 +16,11 @@
+ ssize_t
+ os_sendfile(int out, int in, off_t * offp, size_t cnt)
+ {
+-off_t loff = *offp, written;
++off_t loff = offp ? *offp : 0;
++off_t written;
+
+ if (sendfile(in, out, loff, cnt, NULL, &written, 0) < 0) return (ssize_t)-1;
+-*offp = loff + written;
++if (offp) *offp = loff + written;
+ return (ssize_t)written;
+ }
diff --git a/mail/exim/files/patch-OS_os.h-FreeBSD b/mail/exim/files/patch-OS_os.h-FreeBSD
deleted file mode 100644
index 0113c0c1ebb1..000000000000
--- a/mail/exim/files/patch-OS_os.h-FreeBSD
+++ /dev/null
@@ -1,17 +0,0 @@
---- OS/os.h-FreeBSD.orig 2018-04-14 23:18:10 UTC
-+++ OS/os.h-FreeBSD
-@@ -12,6 +12,14 @@
- #define SIOCGIFCONF_GIVES_ADDR
- #define HAVE_SRANDOMDEV
- #define HAVE_ARC4RANDOM
-+/* Applications should not call arc4random_stir() explicitly after
-+ FreeBSD r227520 (approximately 1000002).
-+ Set NOT_HAVE_ARC4RANDOM_STIR if the version released is past
-+ that point. */
-+#include <sys/param.h>
-+#if __FreeBSD_version >= 1000002
-+# define NOT_HAVE_ARC4RANDOM_STIR
-+#endif
-
- typedef struct flock flock_t;
-
diff --git a/mail/exim/files/patch-src__EDITME b/mail/exim/files/patch-src__EDITME
index cdbc576fda1d..ea4c1303bca9 100644
--- a/mail/exim/files/patch-src__EDITME
+++ b/mail/exim/files/patch-src__EDITME
@@ -1,6 +1,6 @@
---- src/EDITME.orig 2012-05-31 04:40:15.000000000 +0400
-+++ src/EDITME 2012-06-28 18:43:50.000000000 +0400
-@@ -98,7 +98,7 @@
+--- src/EDITME.orig 2021-09-28 10:24:46.000000000 +0200
++++ src/EDITME 2021-09-29 19:38:22.776161000 +0200
+@@ -99,7 +99,7 @@
# /usr/local/sbin. The installation script will try to create this directory,
# and any superior directories, if they do not exist.
@@ -9,7 +9,7 @@
#------------------------------------------------------------------------------
-@@ -114,7 +114,7 @@
+@@ -115,7 +115,7 @@
# don't exist. It will also install a default runtime configuration if this
# file does not exist.
@@ -18,7 +18,7 @@
# It is possible to specify a colon-separated list of files for CONFIGURE_FILE.
# In this case, Exim will use the first of them that exists when it is run.
-@@ -131,7 +131,7 @@
+@@ -132,7 +132,7 @@
# deliveries. (Local deliveries run as various non-root users, typically as the
# owner of a local mailbox.) Specifying these values as root is not supported.
@@ -27,7 +27,7 @@
# If you specify EXIM_USER as a name, this is looked up at build time, and the
# uid number is built into the binary. However, you can specify that this
-@@ -152,7 +152,7 @@
+@@ -153,7 +153,7 @@
# for EXIM_USER (e.g. EXIM_USER=exim), you don't need to set EXIM_GROUP unless
# you want to use a group other than the default group for the given user.
@@ -36,7 +36,7 @@
# Many sites define a user called "exim", with an appropriate default group,
# and use
-@@ -330,6 +330,7 @@
+@@ -451,6 +451,7 @@
# LDAP_LIB_TYPE=OPENLDAP2
# LDAP_LIB_TYPE=NETSCAPE
# LDAP_LIB_TYPE=SOLARIS
@@ -44,12 +44,13 @@
# If you don't set any of these, Exim assumes the original University of
# Michigan (OpenLDAP 1) library.
-@@ -361,8 +362,10 @@
+@@ -491,9 +492,10 @@
#
# You do not need to use this for any lookup information added via pkg-config.
-# LOOKUP_INCLUDE=-I /usr/local/ldap/include -I /usr/local/mysql/include -I /usr/local/pgsql/include
--# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lgds -lsqlite3
+-# LOOKUP_INCLUDE +=-I /usr/local/include
+-# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lgds -lsqlite3 -llmdb
+INCLUDE=-IXX_LOCALBASE_XX/include XX_DB_INCLUDES_XX XX_LMDB_INCLUDES_XX
+LOOKUP_INCLUDE=XX_MYSQL_INCLUDE_XX XX_PGSQL_INCLUDE_XX XX_LDAP_INCLUDE_XX
+LOOKUP_LIBS=XX_MYSQL_LIBS_XX XX_PGSQL_LIBS_XX XX_LDAP_LIBS_XX XX_LMDB_LIBS_XX
@@ -57,15 +58,15 @@
#------------------------------------------------------------------------------
-@@ -454,6 +457,7 @@
-
-
+@@ -633,6 +635,7 @@
+ # Uncomment the following line to add queuefile transport support
+ # EXPERIMENTAL_QUEUEFILE=yes
+# EXPERIMENTAL_DCC=yes
###############################################################################
# THESE ARE THINGS YOU MIGHT WANT TO SPECIFY #
###############################################################################
-@@ -521,6 +525,7 @@
+@@ -700,6 +703,7 @@
# ALT_CONFIG_PREFIX=/some/directory/
# ALT_CONFIG_PREFIX=/some/directory/exim.conf-
@@ -73,7 +74,7 @@
#------------------------------------------------------------------------------
-@@ -607,7 +612,7 @@
+@@ -802,7 +806,7 @@
# one that is set in the headers_charset option. The default setting is
# defined by this setting:
@@ -82,7 +83,7 @@
# If you are going to make use of $header_xxx expansions in your configuration
# file, or if your users are going to use them in filter files, and the normal
-@@ -751,7 +756,7 @@
+@@ -898,7 +902,7 @@
# Once you have done this, "make install" will build the info files and
# install them in the directory you have defined.
@@ -91,7 +92,7 @@
#------------------------------------------------------------------------------
-@@ -764,7 +769,7 @@
+@@ -911,7 +915,7 @@
# %s. This will be replaced by one of the strings "main", "panic", or "reject"
# to form the final file names. Some installations may want something like this:
@@ -100,7 +101,7 @@
# which results in files with names /var/log/exim_mainlog, etc. The directory
# in which the log files are placed must exist; Exim does not try to create
-@@ -840,7 +845,7 @@
+@@ -993,7 +997,7 @@
# that the local_scan API is made available by the linker. You may also need
# to add -ldl to EXTRALIBS so that dlopen() is available to Exim.
@@ -109,7 +110,7 @@
#------------------------------------------------------------------------------
-@@ -937,6 +942,8 @@
+@@ -1130,6 +1134,8 @@
#
# but of course there may need to be other things in CFLAGS and EXTRALIBS_EXIM
# as well.
@@ -118,7 +119,7 @@
#
# To use a name other than exim in the tcpwrappers config file,
# e.g. if you're running multiple daemons with different access lists,
-@@ -945,6 +952,14 @@
+@@ -1138,7 +1144,15 @@
#
# TCP_WRAPPERS_DAEMON_NAME="exim"
@@ -126,14 +127,15 @@
+# one or two OS. See the file README.IPV6 for the current status of this
+# support. Do not set this option unless you are working on IPv6 and know
+# what you are doing.
-+
+
+# HAVE_IPV6=YES
+
+
-
++
#------------------------------------------------------------------------------
# The default action of the exim_install script (which is run by "make
-@@ -1222,7 +1237,7 @@
+ # install") is to install the Exim binary with a unique name such as
+@@ -1424,7 +1438,7 @@
# (process id) to a file so that it can easily be identified. The path of the
# file can be specified here. Some installations may want something like this:
diff --git a/mail/exim/options b/mail/exim/options
index 56d828faa1c3..b36b0cd9c411 100644
--- a/mail/exim/options
+++ b/mail/exim/options
@@ -18,7 +18,6 @@ OPTIONS_DEFINE+= ALT_CONFIG_PREFIX \
PRDR \
READLINE \
SUID \
- TAINTWARN \
TCP_WRAPPERS \
WISHLIST \
EVENT \