FreeBSD Bugzilla – Attachment 241399 Details for
Bug 265098
mail/exim: update to 4.96
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch-v3
exim.diff (text/plain), 170.12 KB, created by
Kurt Jaeger
on 2023-04-10 11:35:07 UTC
(
hide
)
Description:
patch-v3
Filename:
MIME Type:
Creator:
Kurt Jaeger
Created:
2023-04-10 11:35:07 UTC
Size:
170.12 KB
patch
obsolete
>diff --git a/UPDATING b/UPDATING >index 38292b0b3e71..cfb88aed5ac4 100644 >--- a/UPDATING >+++ b/UPDATING >@@ -5,6 +5,15 @@ they are unavoidable. > You should get into the habit of checking this file for changes each time > you update your ports collection, before attempting any port upgrades. > >+2023xxxx: >+ AFFECTS: users of mail/exim >+ AUTHOR: pi@FreeBSD.org >+ >+ The port changes from USE_DB to USE_NDBM. Any existing configuration like >+ ${lookup{$needle}dbm{haystack.db}} >+ will need to change to >+ ${lookup{$needle}dbm{haystack}}. >+ > 20230407: > AFFECTS: users of devel/sonarqube-community > AUTHOR: netchild@FreeBSD.org >diff --git a/mail/exim/Makefile b/mail/exim/Makefile >index 2242ff7608fa..29a3f90ed571 100644 >--- a/mail/exim/Makefile >+++ b/mail/exim/Makefile >@@ -1,6 +1,6 @@ > PORTNAME= exim > PORTVERSION?= ${EXIM_VERSION} >-PORTREVISION?= 6 >+PORTREVISION?= 0 > CATEGORIES= mail > MASTER_SITES= EXIM:exim > MASTER_SITE_SUBDIR= /exim4/:exim \ >@@ -66,20 +66,30 @@ SQLITE_USES= pkgconfig sqlite > > 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}_32-Fix-PAM-auth.-Bug-2813.patch:-p1 \ >- ${DEBIAN_PATCHES_PREFIX}_35-Exiqgrep-check-arg-parsing.-Bug-2821.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 \ >- ${DEBIAN_PATCHES_PREFIX}_43-BSD-fix-resource-leak.patch:-p1 \ >- ${DEBIAN_PATCHES_PREFIX}_45-Fix-bogus-error-message-copy.-Bug-2857.patch:-p1 \ >- ${DEBIAN_PATCHES_PREFIX}_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch:-p1 \ >- ${DEBIAN_PATCHES_PREFIX}_55-Specific-check-for-null-pointer.patch:-p1 >- >-TLS_PATCHES_PREFIX= ${FILESDIR}/tls/ >-EXTRA_PATCHES+= \ >- ${TLS_PATCHES_PREFIX}patch-tls1:-p1 \ >- ${TLS_PATCHES_PREFIX}patch-tls2:-p1 >+ ${DEBIAN_PATCHES_PREFIX}_01-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_05-SPF-fix-memory-accounting-for-error-case.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_08-Fix-regex-n-use-after-free.-Bug-2915.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_09-Fix-non-WITH_CONTENT_SCAN-build.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_22-Fix-daemon-startup.-Bug-2930.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_23-Fix-reccipients-after-run.-.-Bug-2929.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_31-Fix-regext-substring-capture-variables-for-null-matc.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_32-Fix-regex-substring-capture-variables-for-null-match.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_50-Fix-logging-of-max-size-log-line.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch:-p1 \ >+ ${DEBIAN_PATCHES_PREFIX}_66-Fix-crash-in-expansions.patch:-p1 > > .include <bsd.port.options.mk> > >@@ -120,7 +130,7 @@ EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.c > EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.conf > .endif > >-EXIM_VERSION= 4.95 >+EXIM_VERSION= 4.96 > SA_EXIM_VERSION=4.2.1 > EXIM_INSTALL_ARG+= "-no_chown" "-no_symlink" > EXTRA_PATCHES+= `${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h` >@@ -210,7 +220,7 @@ WITH_DEFAULT_CHARSET?= ISO-8859-1 > > # You should not need to fiddle with anything below this point. > >-LIB_DEPENDS+= libpcre.so:devel/pcre >+LIB_DEPENDS+= libpcre2-posix.so:devel/pcre2 > > .if ! ${PORT_OPTIONS:MDKIM} > SEDLIST+= -e 's,^\# (DISABLE_DKIM=),\1,' >@@ -599,8 +609,6 @@ do-configure: > @${REINPLACE_CMD} -e 's,/usr/bin/spamc,${LOCALBASE}/bin/spamc,' \ > ${WRKSRC}/Local/sa-exim.conf > .endif >- @${REINPLACE_CMD} -E -e 's/XX_STRIPCMD_XX/${STRIP_CMD:S,/,\/,g}/' \ >- ${WRKSRC}/OS/Makefile-FreeBSD > @(cd ${WRKSRC}; ${SETENV} ${MAKE_ENV} ${MAKE} ${MAKE_FLAGS} ${MAKEFILE} ${MAKE_ARGS} configure) > > post-build: >diff --git a/mail/exim/distinfo b/mail/exim/distinfo >index c007834ea4bb..eb6b96ef513f 100644 >--- a/mail/exim/distinfo >+++ b/mail/exim/distinfo >@@ -1,5 +1,5 @@ >-TIMESTAMP = 1632918983 >-SHA256 (exim/exim-4.95.tar.bz2) = 7f4716cc1b3fee66930d83b249f1c7b119fa1957f6f46e3f4372805cbc97ea63 >-SIZE (exim/exim-4.95.tar.bz2) = 2035738 >+TIMESTAMP = 1681024359 >+SHA256 (exim/exim-4.96.tar.bz2) = c7a413fec601cc44a8f5fe9e5b64cb24a7d133f3a4a976f33741d98ff0ec6b91 >+SIZE (exim/exim-4.96.tar.bz2) = 2047632 > 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-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch b/mail/exim/files/debian/75_01-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch >new file mode 100644 >index 000000000000..bf0f64942d7d >--- /dev/null >+++ b/mail/exim/files/debian/75_01-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch >@@ -0,0 +1,57 @@ >+From e7ec503729970a03d4509921342bc81313976126 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Tue, 12 Jul 2022 22:14:04 +0100 >+Subject: [PATCH] Fix exit on attempt to rewrite a malformed address. Bug 2903 >+ >+--- >+ doc/ChangeLog | 5 + >+ src/rewrite.c | 9 +- >+ test/confs/0471 | 7 + >+ test/log/0471 | 5 + >+ test/scripts/0000-Basic/0471 | 4 +- >+ test/stderr/0471 | 245 ++++++++++++++++++++++++++++++++++- >+ 6 files changed, 267 insertions(+), 8 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -1,9 +1,14 @@ >+ 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/04 Bug 2903: avoid exit on an attempt to rewrite a malformed address. >++ Make the rewrite never match and keep the logging. Trust the >++ admin to be using verify=header-syntax (to actually reject the message). >++ >++ >+ Exim version 4.96 >+ ----------------- >+ >+ JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from >+ after reception to before a subsequent reception. This should >+--- a/src/rewrite.c >++++ b/src/rewrite.c >+@@ -493,19 +493,18 @@ >+ empty address, overlong addres. Sometimes the result matters, sometimes not. >+ It seems this function is called for *any* header we see. */ >+ >+ if (!recipient) >+ { >+- /* Handle unparesable addresses in the header. Slightly ugly because a >++ /* Log unparesable addresses in the header. Slightly ugly because a >+ null output from the extract can also result from a header without an >+- address, "To: undisclosed recpients:;" being the classic case. */ >++ address, "To: undisclosed recpients:;" being the classic case. Ignore >++ this one and carry on. */ >+ >+ if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0) >+- { >+ log_write(0, LOG_MAIN, "rewrite: %s", errmess); >+- exim_exit(EXIT_FAILURE); >+- } >++ >+ loop_reset_point = store_reset(loop_reset_point); >+ continue; >+ } >+ >+ /* If routed_old is not NULL, this is a rewrite caused by a router, >diff --git a/mail/exim/files/debian/75_05-SPF-fix-memory-accounting-for-error-case.patch b/mail/exim/files/debian/75_05-SPF-fix-memory-accounting-for-error-case.patch >new file mode 100644 >index 000000000000..e474acf6f54d >--- /dev/null >+++ b/mail/exim/files/debian/75_05-SPF-fix-memory-accounting-for-error-case.patch >@@ -0,0 +1,25 @@ >+From 93c722ce0549360af68269f088f4e59ed8fc130e Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Sun, 7 Aug 2022 17:00:27 +0100 >+Subject: [PATCH] SPF: fix memory accounting for error case >+ >+--- >+ src/spf.c | 2 +- >+ 1 file changed, 1 insertion(+), 1 deletion(-) >+ >+diff --git a/src/spf.c b/src/spf.c >+index db6eea3a8..a8c0f75c4 100644 >+--- a/src/spf.c >++++ b/src/spf.c >+@@ -204,7 +204,7 @@ spf_nxdomain = SPF_dns_rr_new_init(spf_dns_server, >+ "", ns_t_any, 24 * 60 * 60, HOST_NOT_FOUND); >+ if (!spf_nxdomain) >+ { >+- free(spf_dns_server); >++ store_free(spf_dns_server); >+ return NULL; >+ } >+ >+-- >+2.35.1 >+ >diff --git a/mail/exim/files/debian/75_08-Fix-regex-n-use-after-free.-Bug-2915.patch b/mail/exim/files/debian/75_08-Fix-regex-n-use-after-free.-Bug-2915.patch >new file mode 100644 >index 000000000000..2429e9ff55b9 >--- /dev/null >+++ b/mail/exim/files/debian/75_08-Fix-regex-n-use-after-free.-Bug-2915.patch >@@ -0,0 +1,193 @@ >+From 4e9ed49f8f12eb331b29bd5b6dc3693c520fddc2 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Wed, 31 Aug 2022 15:37:40 +0100 >+Subject: [PATCH] Fix $regex<n> use-after-free. Bug 2915 >+ >+--- >+ doc/ChangeLog | 8 +++++++- >+ src/exim.c | 4 +--- >+ src/expand.c | 2 +- >+ src/functions.h | 1 + >+ src/globals.c | 2 +- >+ src/regex.c | 29 ++++++++++++++++++----------- >+ src/smtp_in.c | 2 ++ >+ 7 files changed, 55 insertions(+), 17 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -4,15 +4,21 @@ >+ >+ JH/04 Bug 2903: avoid exit on an attempt to rewrite a malformed address. >+ Make the rewrite never match and keep the logging. Trust the >+ admin to be using verify=header-syntax (to actually reject the message). >+ >++JH/08 Bug 2915: Fix use-after-free for $regex<n> variables. Previously when >++ more than one message arrived in a single connection a reference from >++ the earlier message could be re-used. Often a sigsegv resulted. >++ These variables were introduced in Exim 4.87. >++ Debug help from Graeme Fowler. >++ >+ >+ Exim version 4.96 >+ ----------------- >+ >+-JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from >++JH/01 Move the wait-for-next-tick (needed for unique message IDs) from >+ after reception to before a subsequent reception. This should >+ mean slightly faster delivery, and also confirmation of reception >+ to senders. >+ >+ JH/02 Move from using the pcre library to pcre2. The former is no longer >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -1999,12 +1999,10 @@ >+ >+ regex_whitelisted_macro = >+ regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE); >+ #endif >+ >+-for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >+- >+ /* If the program is called as "mailq" treat it as equivalent to "exim -bp"; >+ this seems to be a generally accepted convention, since one finds symbolic >+ links called "mailq" in standard OS configurations. */ >+ >+ if ((namelen == 5 && Ustrcmp(argv[0], "mailq") == 0) || >+@@ -6082,11 +6080,11 @@ >+ callout_address = NULL; >+ sending_ip_address = NULL; >+ deliver_localpart_data = deliver_domain_data = >+ recipient_data = sender_data = NULL; >+ acl_var_m = NULL; >+- for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >++ regex_vars_clear(); >+ >+ store_reset(reset_point); >+ } >+ >+ exim_exit(EXIT_SUCCESS); /* Never returns */ >+--- a/src/expand.c >++++ b/src/expand.c >+@@ -1871,11 +1871,11 @@ >+ { >+ tree_node * node = tree_search(router_var, name + 2); >+ return node ? node->data.ptr : strict_acl_vars ? NULL : US""; >+ } >+ >+-/* Handle $auth<n> variables. */ >++/* Handle $auth<n>, $regex<n> variables. */ >+ >+ if (Ustrncmp(name, "auth", 4) == 0) >+ { >+ uschar *endptr; >+ int n = Ustrtoul(name + 4, &endptr, 10); >+--- a/src/functions.h >++++ b/src/functions.h >+@@ -436,10 +436,11 @@ >+ extern int regex(const uschar **); >+ #endif >+ extern BOOL regex_match(const pcre2_code *, const uschar *, int, uschar **); >+ extern BOOL regex_match_and_setup(const pcre2_code *, const uschar *, int, int); >+ extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL); >++extern void regex_vars_clear(void); >+ extern void retry_add_item(address_item *, uschar *, int); >+ extern BOOL retry_check_address(const uschar *, host_item *, uschar *, BOOL, >+ uschar **, uschar **); >+ extern retry_config *retry_find_config(const uschar *, const uschar *, int, int); >+ extern BOOL retry_ultimate_address_timeout(uschar *, const uschar *, >+--- a/src/globals.c >++++ b/src/globals.c >+@@ -1313,11 +1313,11 @@ >+ #ifndef DISABLE_PIPE_CONNECT >+ const pcre2_code *regex_EARLY_PIPE = NULL; >+ #endif >+ const pcre2_code *regex_ismsgid = NULL; >+ const pcre2_code *regex_smtp_code = NULL; >+-const uschar *regex_vars[REGEX_VARS]; >++const uschar *regex_vars[REGEX_VARS] = { 0 };; >+ #ifdef WHITELIST_D_MACROS >+ const pcre2_code *regex_whitelisted_macro = NULL; >+ #endif >+ #ifdef WITH_CONTENT_SCAN >+ uschar *regex_match_string = NULL; >+--- a/src/regex.c >++++ b/src/regex.c >+@@ -94,22 +94,32 @@ >+ } >+ pcre2_match_data_free(md); >+ return FAIL; >+ } >+ >++ >++/* reset expansion variables */ >++void >++regex_vars_clear(void) >++{ >++regex_match_string = NULL; >++for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >++} >++ >++ >++ >+ int >+-regex(const uschar **listptr) >++regex(const uschar ** listptr) >+ { >+ unsigned long mbox_size; >+-FILE *mbox_file; >+-pcre_list *re_list_head; >+-uschar *linebuffer; >++FILE * mbox_file; >++pcre_list * re_list_head; >++uschar * linebuffer; >+ long f_pos = 0; >+ int ret = FAIL; >+ >+-/* reset expansion variable */ >+-regex_match_string = NULL; >++regex_vars_clear(); >+ >+ if (!mime_stream) /* We are in the DATA ACL */ >+ { >+ if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL))) >+ { /* error while spooling */ >+@@ -167,18 +177,17 @@ >+ >+ >+ int >+ mime_regex(const uschar **listptr) >+ { >+-pcre_list *re_list_head = NULL; >+-FILE *f; >+-uschar *mime_subject = NULL; >++pcre_list * re_list_head = NULL; >++FILE * f; >++uschar * mime_subject = NULL; >+ int mime_subject_len = 0; >+ int ret; >+ >+-/* reset expansion variable */ >+-regex_match_string = NULL; >++regex_vars_clear(); >+ >+ /* precompile our regexes */ >+ if (!(re_list_head = compile(*listptr))) >+ return FAIL; /* no regexes -> nothing to do */ >+ >+--- a/src/smtp_in.c >++++ b/src/smtp_in.c >+@@ -2155,12 +2155,14 @@ >+ prdr_requested = FALSE; >+ #endif >+ #ifdef SUPPORT_I18N >+ message_smtputf8 = FALSE; >+ #endif >++regex_vars_clear(); >+ body_linecount = body_zerocount = 0; >+ >++lookup_value = NULL; /* Can be set by ACL */ >+ sender_rate = sender_rate_limit = sender_rate_period = NULL; >+ ratelimiters_mail = NULL; /* Updated by ratelimit ACL condition */ >+ /* Note that ratelimiters_conn persists across resets. */ >+ >+ /* Reset message ACL variables */ >diff --git a/mail/exim/files/debian/75_09-Fix-non-WITH_CONTENT_SCAN-build.patch b/mail/exim/files/debian/75_09-Fix-non-WITH_CONTENT_SCAN-build.patch >new file mode 100644 >index 000000000000..6071fa7c5bf4 >--- /dev/null >+++ b/mail/exim/files/debian/75_09-Fix-non-WITH_CONTENT_SCAN-build.patch >@@ -0,0 +1,58 @@ >+From d8ecc7bf97934a1e2244788c610c958cacd740bd Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Wed, 31 Aug 2022 17:03:37 +0100 >+Subject: [PATCH 1/3] Fix non-WITH_CONTENT_SCAN build. >+ >+Broken-by: 4e9ed49f8f >+--- >+ src/exim.c | 11 +++++++++++ >+ src/regex.c | 10 ---------- >+ 2 files changed, 11 insertions(+), 10 deletions(-) >+ >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -1677,10 +1677,21 @@ >+ if ((s = expand_string(big_buffer))) printf("%s\n", CS s); >+ else printf("Failed: %s\n", expand_string_message); >+ } >+ >+ >++/* reset regex expansion variables */ >++void >++regex_vars_clear(void) >++{ >++regex_match_string = NULL; >++for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >++} >++ >++ >++ >++ >+ >+ /************************************************* >+ * Entry point and high-level code * >+ *************************************************/ >+ >+--- a/src/regex.c >++++ b/src/regex.c >+@@ -95,20 +95,10 @@ >+ pcre2_match_data_free(md); >+ return FAIL; >+ } >+ >+ >+-/* reset expansion variables */ >+-void >+-regex_vars_clear(void) >+-{ >+-regex_match_string = NULL; >+-for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >+-} >+- >+- >+- >+ int >+ regex(const uschar ** listptr) >+ { >+ unsigned long mbox_size; >+ FILE * mbox_file; >diff --git a/mail/exim/files/debian/75_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch b/mail/exim/files/debian/75_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch >new file mode 100644 >index 000000000000..0a8ed514ffe8 >--- /dev/null >+++ b/mail/exim/files/debian/75_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch >@@ -0,0 +1,135 @@ >+From 158dff9936e36a2d31d037d3988b9353458d6471 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Wed, 31 Aug 2022 17:17:59 +0100 >+Subject: [PATCH 2/3] Fix non-WITH_CONTENT_SCAN build (2) >+ >+Broken-by: d8ecc7bf97 >+--- >+ src/exim.c | 13 +------------ >+ src/functions.h | 2 +- >+ src/globals.h | 2 +- >+ src/regex.c | 10 ++++++++++ >+ src/smtp_in.c | 2 ++ >+ 5 files changed, 15 insertions(+), 14 deletions(-) >+ >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -1677,21 +1677,10 @@ >+ if ((s = expand_string(big_buffer))) printf("%s\n", CS s); >+ else printf("Failed: %s\n", expand_string_message); >+ } >+ >+ >+-/* reset regex expansion variables */ >+-void >+-regex_vars_clear(void) >+-{ >+-regex_match_string = NULL; >+-for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >+-} >+- >+- >+- >+- >+ >+ /************************************************* >+ * Entry point and high-level code * >+ *************************************************/ >+ >+@@ -6085,17 +6074,17 @@ >+ deliver_domain_orig = NULL; >+ deliver_host = deliver_host_address = NULL; >+ dnslist_domain = dnslist_matched = NULL; >+ #ifdef WITH_CONTENT_SCAN >+ malware_name = NULL; >++ regex_vars_clear(); >+ #endif >+ callout_address = NULL; >+ sending_ip_address = NULL; >+ deliver_localpart_data = deliver_domain_data = >+ recipient_data = sender_data = NULL; >+ acl_var_m = NULL; >+- regex_vars_clear(); >+ >+ store_reset(reset_point); >+ } >+ >+ exim_exit(EXIT_SUCCESS); /* Never returns */ >+--- a/src/functions.h >++++ b/src/functions.h >+@@ -432,15 +432,15 @@ >+ extern BOOL receive_msg(BOOL); >+ extern int_eximarith_t receive_statvfs(BOOL, int *); >+ extern void receive_swallow_smtp(void); >+ #ifdef WITH_CONTENT_SCAN >+ extern int regex(const uschar **); >++extern void regex_vars_clear(void); >+ #endif >+ extern BOOL regex_match(const pcre2_code *, const uschar *, int, uschar **); >+ extern BOOL regex_match_and_setup(const pcre2_code *, const uschar *, int, int); >+ extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL); >+-extern void regex_vars_clear(void); >+ extern void retry_add_item(address_item *, uschar *, int); >+ extern BOOL retry_check_address(const uschar *, host_item *, uschar *, BOOL, >+ uschar **, uschar **); >+ extern retry_config *retry_find_config(const uschar *, const uschar *, int, int); >+ extern BOOL retry_ultimate_address_timeout(uschar *, const uschar *, >+--- a/src/globals.h >++++ b/src/globals.h >+@@ -895,16 +895,16 @@ >+ #ifndef DISABLE_PIPE_CONNECT >+ extern const pcre2_code *regex_EARLY_PIPE; /* For recognizing PIPE_CONNCT */ >+ #endif >+ extern const pcre2_code *regex_ismsgid; /* Compiled r.e. for message ID */ >+ extern const pcre2_code *regex_smtp_code; /* For recognizing SMTP codes */ >+-extern const uschar *regex_vars[]; /* $regexN variables */ >+ #ifdef WHITELIST_D_MACROS >+ extern const pcre2_code *regex_whitelisted_macro; /* For -D macro values */ >+ #endif >+ #ifdef WITH_CONTENT_SCAN >+ extern uschar *regex_match_string; /* regex that matched a line (regex ACL condition) */ >++extern const uschar *regex_vars[]; >+ #endif >+ extern int remote_delivery_count; /* Number of remote addresses */ >+ extern int remote_max_parallel; /* Maximum parallel delivery */ >+ extern uschar *remote_sort_domains; /* Remote domain sorting order */ >+ extern retry_config *retries; /* Chain of retry config information */ >+--- a/src/regex.c >++++ b/src/regex.c >+@@ -95,10 +95,20 @@ >+ pcre2_match_data_free(md); >+ return FAIL; >+ } >+ >+ >++/* reset expansion variables */ >++void >++regex_vars_clear(void) >++{ >++regex_match_string = NULL; >++for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL; >++} >++ >++ >++ >+ int >+ regex(const uschar ** listptr) >+ { >+ unsigned long mbox_size; >+ FILE * mbox_file; >+--- a/src/smtp_in.c >++++ b/src/smtp_in.c >+@@ -2155,11 +2155,13 @@ >+ prdr_requested = FALSE; >+ #endif >+ #ifdef SUPPORT_I18N >+ message_smtputf8 = FALSE; >+ #endif >++#ifdef WITH_CONTENT_SCAN >+ regex_vars_clear(); >++#endif >+ body_linecount = body_zerocount = 0; >+ >+ lookup_value = NULL; /* Can be set by ACL */ >+ sender_rate = sender_rate_limit = sender_rate_period = NULL; >+ ratelimiters_mail = NULL; /* Updated by ratelimit ACL condition */ >diff --git a/mail/exim/files/debian/75_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch b/mail/exim/files/debian/75_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch >new file mode 100644 >index 000000000000..b06d89679b7e >--- /dev/null >+++ b/mail/exim/files/debian/75_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch >@@ -0,0 +1,45 @@ >+From 32da6327e434e986a18b75a84f2d8c687ba14619 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Thu, 1 Sep 2022 15:54:35 +0100 >+Subject: [PATCH 3/3] Fix non-WITH_CONTENT_SCAN build (3) >+ >+Broken-by: d8ecc7bf97 >+--- >+ src/expand.c | 4 ++++ >+ 1 file changed, 4 insertions(+) >+ >+diff --git a/src/expand.c b/src/expand.c >+index 89de56255..831ca2b75 100644 >+--- a/src/expand.c >++++ b/src/expand.c >+@@ -1869,6 +1869,7 @@ if (Ustrncmp(name, "auth", 4) == 0) >+ if (!*endptr && n != 0 && n <= AUTH_VARS) >+ return auth_vars[n-1] ? auth_vars[n-1] : US""; >+ } >++#ifdef WITH_CONTENT_SCAN >+ else if (Ustrncmp(name, "regex", 5) == 0) >+ { >+ uschar *endptr; >+@@ -1876,6 +1877,7 @@ else if (Ustrncmp(name, "regex", 5) == 0) >+ if (!*endptr && n != 0 && n <= REGEX_VARS) >+ return regex_vars[n-1] ? regex_vars[n-1] : US""; >+ } >++#endif >+ >+ /* For all other variables, search the table */ >+ >+@@ -8715,9 +8717,11 @@ assert_variable_notin() treats as const, so deconst is safe. */ >+ for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i]) >+ assert_variable_notin(US"auth<n>", US auth_vars[i], &e); >+ >++#ifdef WITH_CONTENT_SCAN >+ /* check regex<n> variables. assert_variable_notin() treats as const. */ >+ for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i]) >+ assert_variable_notin(US"regex<n>", US regex_vars[i], &e); >++#endif >+ >+ /* check known-name variables */ >+ for (var_entry * v = var_table; v < var_table + var_table_size; v++) >+-- >+2.35.1 >+ >diff --git a/mail/exim/files/debian/75_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch b/mail/exim/files/debian/75_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch >new file mode 100644 >index 000000000000..ae2fa16f51ea >--- /dev/null >+++ b/mail/exim/files/debian/75_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch >@@ -0,0 +1,114 @@ >+From ece23f05d6a430a461a75639197271c23f6858ec Mon Sep 17 00:00:00 2001 >+From: Jasen Betts <jasen@xnet.co.nz> >+Date: Fri, 30 Sep 2022 13:49:41 +0100 >+Subject: [PATCH] GnuTLS: fix for clients offering no TLS extensions >+ >+--- >+ doc/ChangeLog | 3 +++ >+ src/tls-gnu.c | 3 ++- >+ src/tls-openssl.c | 39 +++++++++++++++--------------- >+ test/confs/2091 | 1 + >+ test/log/2091 | 3 +++ >+ test/scripts/2090-GnuTLS-ALPN/2091 | 19 +++++++++++++++ >+ test/stdout/2091 | 21 ++++++++++++++++ >+ 7 files changed, 68 insertions(+), 21 deletions(-) >+ create mode 120000 test/confs/2091 >+ create mode 100644 test/log/2091 >+ create mode 100644 test/scripts/2090-GnuTLS-ALPN/2091 >+ create mode 100644 test/stdout/2091 >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -10,10 +10,14 @@ >+ more than one message arrived in a single connection a reference from >+ the earlier message could be re-used. Often a sigsegv resulted. >+ These variables were introduced in Exim 4.87. >+ Debug help from Graeme Fowler. >+ >++JH/10 GnuTLS: fix for (IOT?) clients offering no TLS extensions at all. >++ Find and fix by Jasen Betts. >++ >++ >+ >+ Exim version 4.96 >+ ----------------- >+ >+ JH/01 Move the wait-for-next-tick (needed for unique message IDs) from >+--- a/src/tls-gnu.c >++++ b/src/tls-gnu.c >+@@ -1130,12 +1130,13 @@ >+ static int >+ tls_server_clienthello_cb(gnutls_session_t session, unsigned int htype, >+ unsigned when, unsigned int incoming, const gnutls_datum_t * msg) >+ { >+ /* Call fn for each extension seen. 3.6.3 onwards */ >+-return gnutls_ext_raw_parse(NULL, tls_server_clienthello_ext, msg, >++int rc = gnutls_ext_raw_parse(NULL, tls_server_clienthello_ext, msg, >+ GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO); >++return rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE ? 0 : rc; >+ } >+ >+ >+ # ifdef notdef_crashes >+ /* Make a note that we saw a status-response */ >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -940,40 +940,39 @@ >+ >+ Returns: nothing >+ */ >+ >+ static void >+-info_callback(SSL *s, int where, int ret) >++info_callback(SSL * s, int where, int ret) >+ { >+ DEBUG(D_tls) >+ { >+- const uschar * str; >++ gstring * g = NULL; >+ >+- if (where & SSL_ST_CONNECT) >+- str = US"SSL_connect"; >+- else if (where & SSL_ST_ACCEPT) >+- str = US"SSL_accept"; >+- else >+- str = US"SSL info (undefined)"; >++ if (where & SSL_ST_CONNECT) g = string_append_listele(g, ',', US"SSL_connect"); >++ if (where & SSL_ST_ACCEPT) g = string_append_listele(g, ',', US"SSL_accept"); >++ if (where & SSL_CB_LOOP) g = string_append_listele(g, ',', US"state_chg"); >++ if (where & SSL_CB_EXIT) g = string_append_listele(g, ',', US"hshake_exit"); >++ if (where & SSL_CB_READ) g = string_append_listele(g, ',', US"read"); >++ if (where & SSL_CB_WRITE) g = string_append_listele(g, ',', US"write"); >++ if (where & SSL_CB_ALERT) g = string_append_listele(g, ',', US"alert"); >++ if (where & SSL_CB_HANDSHAKE_START) g = string_append_listele(g, ',', US"hshake_start"); >++ if (where & SSL_CB_HANDSHAKE_DONE) g = string_append_listele(g, ',', US"hshake_done"); >+ >+ if (where & SSL_CB_LOOP) >+- debug_printf("%s: %s\n", str, SSL_state_string_long(s)); >++ debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); >+ else if (where & SSL_CB_ALERT) >+- debug_printf("SSL3 alert %s:%s:%s\n", >+- str = where & SSL_CB_READ ? US"read" : US"write", >++ debug_printf("SSL %s %s:%s\n", g->s, >+ SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); >+ else if (where & SSL_CB_EXIT) >+ { >+- if (ret == 0) >+- debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s)); >+- else if (ret < 0) >+- debug_printf("%s: error in %s\n", str, SSL_state_string_long(s)); >++ if (ret <= 0) >++ debug_printf("SSL %s: %s in %s\n", g->s, >++ ret == 0 ? "failed" : "error", SSL_state_string_long(s)); >+ } >+- else if (where & SSL_CB_HANDSHAKE_START) >+- debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s)); >+- else if (where & SSL_CB_HANDSHAKE_DONE) >+- debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s)); >++ else if (where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE)) >++ debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s)); >+ } >+ } >+ >+ #ifdef OPENSSL_HAVE_KEYLOG_CB >+ static void >diff --git a/mail/exim/files/debian/75_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch b/mail/exim/files/debian/75_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch >new file mode 100644 >index 000000000000..f261d621d67a >--- /dev/null >+++ b/mail/exim/files/debian/75_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch >@@ -0,0 +1,88 @@ >+From 1561c5d88b3a23a4348d8e3c1ce28554fcbcfe46 Mon Sep 17 00:00:00 2001 >+From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de> >+Date: Sat, 15 Oct 2022 19:30:58 +0200 >+Subject: [PATCH 1/2] Fix: Build with libopendmarc 1.4.x (fixes 2728) >+ >+--- >+ doc/ChangeLog | 3 +++ >+ src/EDITME | 7 +++++-- >+ src/config.h.defaults | 1 + >+ src/dmarc.c | 7 ++++++- >+ 4 files changed, 15 insertions(+), 3 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -13,10 +13,13 @@ >+ Debug help from Graeme Fowler. >+ >+ JH/10 GnuTLS: fix for (IOT?) clients offering no TLS extensions at all. >+ Find and fix by Jasen Betts. >+ >++HS/01 Bug 2728: Introduce EDITME option "DMARC_API" to work around incompatible >++ API changes in libopendmarc. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/EDITME >++++ b/src/EDITME >+@@ -600,18 +600,21 @@ >+ >+ # EXPERIMENTAL_DCC=yes >+ >+ # Uncomment the following line to add DMARC checking capability, implemented >+ # using libopendmarc libraries. You must have SPF and DKIM support enabled also. >+-# Library version libopendmarc-1.4.1-1.fc33.x86_64 (on Fedora 33) is known broken; >+-# 1.3.2-3 works. I seems that the OpenDMARC project broke their API. >+ # SUPPORT_DMARC=yes >+ # CFLAGS += -I/usr/local/include >+ # LDFLAGS += -lopendmarc >+ # Uncomment the following if you need to change the default. You can >+ # override it at runtime (main config option dmarc_tld_file) >+ # DMARC_TLD_FILE=/etc/exim/opendmarc.tlds >++# >++# Library version libopendmarc-1.4.1-1.fc33.x86_64 (on Fedora 33) is known broken; >++# 1.3.2-3 works. It seems that the OpenDMARC project broke their API. >++# Use this option if you need to build with an old library (1.3.x) >++# DMARC_API=100300 >+ >+ # Uncomment the following line to add ARC (Authenticated Received Chain) >+ # support. You must have SPF and DKIM support enabled also. >+ # EXPERIMENTAL_ARC=yes >+ >+--- a/src/config.h.defaults >++++ b/src/config.h.defaults >+@@ -148,10 +148,11 @@ >+ #define STRING_SPRINTF_BUFFER_SIZE (8192 * 4) >+ >+ #define SUPPORT_CRYPTEQ >+ #define SUPPORT_DANE >+ #define SUPPORT_DMARC >++#define DMARC_API 100400 >+ #define DMARC_TLD_FILE "/etc/exim/opendmarc.tlds" >+ #define SUPPORT_I18N >+ #define SUPPORT_I18N_2008 >+ #define SUPPORT_MAILDIR >+ #define SUPPORT_MAILSTORE >+--- a/src/dmarc.c >++++ b/src/dmarc.c >+@@ -457,11 +457,16 @@ >+ dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS : >+ vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL : >+ vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : >+ DMARC_POLICY_DKIM_OUTCOME_NONE; >+ libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain, >+- dkim_result, US""); >++/* The opendmarc project broke its API in a way we can't detect * easily. >++ * The EDITME provides a DMARC_API variable */ >++#if DMARC_API >= 100400 >++ sig->selector, >++#endif >++ dkim_result, US""); >+ DEBUG(D_receive) >+ debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain); >+ if (libdm_status != DMARC_PARSE_OKAY) >+ log_write(0, LOG_MAIN|LOG_PANIC, >+ "failure to store dkim (%s) for DMARC: %s", >diff --git a/mail/exim/files/debian/75_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch b/mail/exim/files/debian/75_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch >new file mode 100644 >index 000000000000..e8bda9e07b35 >--- /dev/null >+++ b/mail/exim/files/debian/75_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch >@@ -0,0 +1,39 @@ >+From 12fb3842f81bcbd4a4519d5728f2d7e0e3ca1445 Mon Sep 17 00:00:00 2001 >+From: Lorenz Brun <lorenz@brun.one> >+Date: Fri, 14 Oct 2022 21:02:51 +0200 >+Subject: [PATCH 2/2] DMARC: fix use-after-free in dmarc_dns_lookup >+ >+This fixes a use-after-free in dmarc_dns_lookup where the result >+of dns_lookup in dnsa is freed before the required data is copied out. >+ >+Fixes: 9258363 ("DNS: explicit alloc/free of workspace") >+--- >+ src/dmarc.c | 3 ++- >+ 1 file changed, 2 insertions(+), 1 deletion(-) >+ >+diff --git a/src/dmarc.c b/src/dmarc.c >+index ad0c26c91..53c2752ac 100644 >+--- a/src/dmarc.c >++++ b/src/dmarc.c >+@@ -226,16 +226,17 @@ dns_scan dnss; >+ int rc = dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL); >+ >+ if (rc == DNS_SUCCEED) >+ for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; >+ rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) >+ if (rr->type == T_TXT && rr->size > 3) >+ { >++ uschar *record = string_copyn_taint(US rr->data, rr->size, GET_TAINTED); >+ store_free_dns_answer(dnsa); >+- return string_copyn_taint(US rr->data, rr->size, GET_TAINTED); >++ return record; >+ } >+ store_free_dns_answer(dnsa); >+ return NULL; >+ } >+ >+ >+ static int >+-- >+2.35.1 >+ >diff --git a/mail/exim/files/debian/75_22-Fix-daemon-startup.-Bug-2930.patch b/mail/exim/files/debian/75_22-Fix-daemon-startup.-Bug-2930.patch >new file mode 100644 >index 000000000000..2a3434f8b0b1 >--- /dev/null >+++ b/mail/exim/files/debian/75_22-Fix-daemon-startup.-Bug-2930.patch >@@ -0,0 +1,68 @@ >+From 221321d2c51b83d1feced80ecd6c2fe33ec5456c Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Thu, 3 Nov 2022 20:08:25 +0000 >+Subject: [PATCH 1/2] Fix daemon startup. Bug 2930 >+ >+Broken-by: 7d5055276a >+--- >+ doc/ChangeLog | 4 ++++ >+ src/daemon.c | 8 ++++++-- >+ 2 files changed, 10 insertions(+), 2 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -16,10 +16,14 @@ >+ Find and fix by Jasen Betts. >+ >+ HS/01 Bug 2728: Introduce EDITME option "DMARC_API" to work around incompatible >+ API changes in libopendmarc. >+ >++JH/12 Bug 2930: Fix daemon startup. When started from any process apart from >++ pid 1, in the normal "background daemon" mode, having to drop process- >++ group leadership also lost track of needing to create listener sockets. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/daemon.c >++++ b/src/daemon.c >+@@ -1744,19 +1744,23 @@ >+ { >+ /* If the parent process of this one has pid == 1, we are re-initializing the >+ daemon as the result of a SIGHUP. In this case, there is no need to do >+ anything, because the controlling terminal has long gone. Otherwise, fork, in >+ case current process is a process group leader (see 'man setsid' for an >+- explanation) before calling setsid(). */ >++ explanation) before calling setsid(). >++ All other forks want daemon_listen cleared. Rather than blow a register, jsut >++ restore it here. */ >+ >+ if (getppid() != 1) >+ { >++ BOOL daemon_listen = f.daemon_listen; >+ pid_t pid = exim_fork(US"daemon"); >+ if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, >+ "fork() failed when starting daemon: %s", strerror(errno)); >+ if (pid > 0) exit(EXIT_SUCCESS); /* in parent process, just exit */ >+ (void)setsid(); /* release controlling terminal */ >++ f.daemon_listen = daemon_listen; >+ } >+ } >+ >+ /* We are now in the disconnected, daemon process (unless debugging). Set up >+ the listening sockets if required. */ >+@@ -2090,11 +2094,11 @@ >+ { /* found; append port to list */ >+ for (p = i2->log; *p; ) p++; /* end of existing string */ >+ if (*--p == '}') *p = '\0'; /* drop EOL */ >+ while (isdigit(*--p)) ; /* char before port */ >+ >+- i2->log = *p == ':' /* no list yet? */ >++ i2->log = *p == ':' /* no list yet? { */ >+ ? string_sprintf("%.*s{%s,%d}", >+ (int)(p - i2->log + 1), i2->log, p+1, ipa->port) >+ : string_sprintf("%s,%d}", i2->log, ipa->port); >+ ipa->log = NULL; >+ break; >diff --git a/mail/exim/files/debian/75_23-Fix-reccipients-after-run.-.-Bug-2929.patch b/mail/exim/files/debian/75_23-Fix-reccipients-after-run.-.-Bug-2929.patch >new file mode 100644 >index 000000000000..1c98ef26083b >--- /dev/null >+++ b/mail/exim/files/debian/75_23-Fix-reccipients-after-run.-.-Bug-2929.patch >@@ -0,0 +1,45 @@ >+From 6b331d5834d12bdda21857cd6fffac17038ce3c7 Mon Sep 17 00:00:00 2001 >+From: Ruben Jenster <r.jenster@drachenfels.de> >+Date: Thu, 3 Nov 2022 21:38:15 +0000 >+Subject: [PATCH 2/2] Fix $reccipients after ${run...}. Bug 2929 >+ >+Broken-by: cfe6acff2d >+--- >+ doc/ChangeLog | 3 +++ >+ src/transport.c | 3 ++- >+ 2 files changed, 5 insertions(+), 1 deletion(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -20,10 +20,13 @@ >+ >+ JH/12 Bug 2930: Fix daemon startup. When started from any process apart from >+ pid 1, in the normal "background daemon" mode, having to drop process- >+ group leadership also lost track of needing to create listener sockets. >+ >++JH/13 Bug 2929: Fix using $recipients after ${run...}. A change made for 4.96 >++ resulted in the variable appearing empty. Find and fix by Ruben Jenster. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/transport.c >++++ b/src/transport.c >+@@ -2342,13 +2342,14 @@ >+ /* Handle normal expansion string */ >+ >+ else >+ { >+ const uschar *expanded_arg; >++ BOOL enable_dollar_recipients_g = f.enable_dollar_recipients; >+ f.enable_dollar_recipients = allow_dollar_recipients; >+ expanded_arg = expand_cstring(argv[i]); >+- f.enable_dollar_recipients = FALSE; >++ f.enable_dollar_recipients = enable_dollar_recipients_g; >+ >+ if (!expanded_arg) >+ { >+ uschar *msg = string_sprintf("Expansion of \"%s\" " >+ "from command \"%s\" in %s failed: %s", >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 >deleted file mode 100644 >index ac72e532ebea..000000000000 >--- a/mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch >+++ /dev/null >@@ -1,616 +0,0 @@ >-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_31-Fix-regext-substring-capture-variables-for-null-matc.patch b/mail/exim/files/debian/75_31-Fix-regext-substring-capture-variables-for-null-matc.patch >new file mode 100644 >index 000000000000..bd250f2b7191 >--- /dev/null >+++ b/mail/exim/files/debian/75_31-Fix-regext-substring-capture-variables-for-null-matc.patch >@@ -0,0 +1,79 @@ >+From e63825824cc406c160ccbf2b154c5d81b168604a Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Fri, 11 Nov 2022 00:05:59 +0000 >+Subject: [PATCH 1/2] Fix regext substring capture variables for null matches. >+ Bug 2933 >+ >+broken-by: 59d66fdc13f0 >+--- >+ doc/ChangeLog | 5 +++++ >+ src/exim.c | 2 ++ >+ src/malware.c | 3 +++ >+ src/regex.c | 2 +- >+ 4 files changed, 11 insertions(+), 1 deletion(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -22,10 +22,15 @@ >+ pid 1, in the normal "background daemon" mode, having to drop process- >+ group leadership also lost track of needing to create listener sockets. >+ >+ JH/13 Bug 2929: Fix using $recipients after ${run...}. A change made for 4.96 >+ resulted in the variable appearing empty. Find and fix by Ruben Jenster. >++ >++JH/14 Bug 2933: Fix regex substring match variables for null matches. Since 4.96 >++ a capture group which obtained no text (eg. "(abc)*" matching zero >++ occurrences) could cause a segfault if the corresponding $<n> was >++ expanded. >+ >+ >+ >+ Exim version 4.96 >+ ----------------- >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -167,10 +167,12 @@ >+ for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++) >+ { >+ PCRE2_SIZE len; >+ pcre2_substring_get_bynumber(md, matchnum, >+ (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len); >++ if (!expand_nstring[expand_nmax]) >++ { expand_nstring[expand_nmax] = US""; len = 0; } >+ expand_nlength[expand_nmax++] = (int)len; >+ } >+ expand_nmax--; >+ } >+ else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any) >+--- a/src/malware.c >++++ b/src/malware.c >+@@ -323,11 +323,14 @@ >+ int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx); >+ PCRE2_UCHAR * substr = NULL; >+ PCRE2_SIZE slen; >+ >+ if (i >= 2) /* Got it */ >++ { >+ pcre2_substring_get_bynumber(md, 1, &substr, &slen); >++ if (!substr) substr = US""; >++ } >+ return US substr; >+ } >+ >+ static const pcre2_code * >+ m_pcre_nextinlist(const uschar ** list, int * sep, >+--- a/src/regex.c >++++ b/src/regex.c >+@@ -84,11 +84,11 @@ >+ for (int nn = 1; nn < n; nn++) >+ { >+ PCRE2_UCHAR * cstr; >+ PCRE2_SIZE cslen; >+ pcre2_substring_get_bynumber(md, nn, &cstr, &cslen); >+- regex_vars[nn-1] = CUS cstr; >++ regex_vars[nn-1] = cstr ? CUS cstr : CUS""; >+ } >+ >+ return OK; >+ } >+ } >diff --git a/mail/exim/files/debian/75_32-Fix-PAM-auth.-Bug-2813.patch b/mail/exim/files/debian/75_32-Fix-PAM-auth.-Bug-2813.patch >deleted file mode 100644 >index 537bfed558d7..000000000000 >--- a/mail/exim/files/debian/75_32-Fix-PAM-auth.-Bug-2813.patch >+++ /dev/null >@@ -1,25 +0,0 @@ >-From 51be321b27825c01829dffd90f11bfff256f7e42 Mon Sep 17 00:00:00 2001 >-From: Adam Lackorzynski <adam@l4re.org> >-Date: Sat, 16 Oct 2021 16:30:07 +0100 >-Subject: [PATCH] Fix PAM auth. Bug 2813 >- >---- >- src/auths/call_pam.c | 2 +- >- 1 file changed, 1 insertion(+), 1 deletion(-) >- >-diff --git a/src/auths/call_pam.c b/src/auths/call_pam.c >-index 80bb23ec3..03b9be1a8 100644 >---- a/src/auths/call_pam.c >-+++ b/src/auths/call_pam.c >-@@ -88,7 +88,7 @@ for (int i = 0; i < num_msg; i++) >- arg = US""; >- pam_arg_ended = TRUE; >- } >-- reply[i].resp = CS string_copy_malloc(arg); /* PAM frees resp */ >-+ reply[i].resp = strdup(CCS arg); /* Use libc malloc, PAM frees resp directly*/ >- reply[i].resp_retcode = PAM_SUCCESS; >- break; >- >--- >-2.34.1 >- >diff --git a/mail/exim/files/debian/75_32-Fix-regex-substring-capture-variables-for-null-match.patch b/mail/exim/files/debian/75_32-Fix-regex-substring-capture-variables-for-null-match.patch >new file mode 100644 >index 000000000000..7c2c14a385dc >--- /dev/null >+++ b/mail/exim/files/debian/75_32-Fix-regex-substring-capture-variables-for-null-match.patch >@@ -0,0 +1,94 @@ >+From 7ad1a2b2cc57b5f4bcb59186a9a8abcbed9f4f76 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Fri, 11 Nov 2022 18:22:00 +0000 >+Subject: [PATCH 2/2] Fix regex substring capture variables for null matches >+ (again). Bug 2933 >+ >+Broken-by: 59d66fdc13f0 >+--- >+ src/exim.c | 11 +++++------ >+ src/malware.c | 10 +++++----- >+ src/regex.c | 8 ++++---- >+ test/aux-var-src/0383.F | 4 ++-- >+ test/log/0383 | 4 ++-- >+ test/mail/0383.CALLER | 8 ++++---- >+ test/scripts/0000-Basic/0002 | 2 ++ >+ test/stdout/0002 | 2 ++ >+ 8 files changed, 26 insertions(+), 23 deletions(-) >+ >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -160,20 +160,19 @@ >+ PCRE_EOPT | options, md, pcre_mtc_ctx); >+ BOOL yield; >+ >+ if ((yield = (res >= 0))) >+ { >++ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); >+ res = pcre2_get_ovector_count(md); >+ expand_nmax = setup < 0 ? 0 : setup + 1; >+ for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++) >+ { >+- PCRE2_SIZE len; >+- pcre2_substring_get_bynumber(md, matchnum, >+- (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len); >+- if (!expand_nstring[expand_nmax]) >+- { expand_nstring[expand_nmax] = US""; len = 0; } >+- expand_nlength[expand_nmax++] = (int)len; >++ int off = matchnum * 2; >++ int len = ovec[off + 1] - ovec[off]; >++ expand_nstring[expand_nmax] = string_copyn(subject + ovec[off], len); >++ expand_nlength[expand_nmax++] = len; >+ } >+ expand_nmax--; >+ } >+ else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any) >+ { >+--- a/src/malware.c >++++ b/src/malware.c >+@@ -319,19 +319,19 @@ >+ uschar * >+ m_pcre_exec(const pcre2_code * cre, uschar * text) >+ { >+ pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx); >+ int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx); >+-PCRE2_UCHAR * substr = NULL; >+-PCRE2_SIZE slen; >++uschar * substr = NULL; >+ >+ if (i >= 2) /* Got it */ >+ { >+- pcre2_substring_get_bynumber(md, 1, &substr, &slen); >+- if (!substr) substr = US""; >++ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); >++ int len = ovec[3] - ovec[2]; >++ substr = string_copyn(text + ovec[2], len); >+ } >+-return US substr; >++return substr; >+ } >+ >+ static const pcre2_code * >+ m_pcre_nextinlist(const uschar ** list, int * sep, >+ char * listerr, uschar ** errstr) >+--- a/src/regex.c >++++ b/src/regex.c >+@@ -81,14 +81,14 @@ >+ sizeof(regex_match_string_buffer)-1); >+ regex_match_string = regex_match_string_buffer; >+ >+ for (int nn = 1; nn < n; nn++) >+ { >+- PCRE2_UCHAR * cstr; >+- PCRE2_SIZE cslen; >+- pcre2_substring_get_bynumber(md, nn, &cstr, &cslen); >+- regex_vars[nn-1] = cstr ? CUS cstr : CUS""; >++ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); >++ int off = nn * 2; >++ int len = ovec[off + 1] - ovec[off]; >++ regex_vars[nn-1] = string_copyn(linebuffer + ovec[off], len); >+ } >+ >+ return OK; >+ } >+ } >diff --git a/mail/exim/files/debian/75_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch b/mail/exim/files/debian/75_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch >new file mode 100644 >index 000000000000..61d4483e5f04 >--- /dev/null >+++ b/mail/exim/files/debian/75_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch >@@ -0,0 +1,48 @@ >+From 9ba47886c71d40edc99b026a99edee269d9c9c6f Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Sat, 12 Nov 2022 12:38:22 +0000 >+Subject: [PATCH] Fix regex substring capture - commentary. Bug 2933 >+ >+Broken-by (corrected): 22ed7a5295f1 >+--- >+ src/exim.c | 9 ++++++++- >+ 1 file changed, 8 insertions(+), 1 deletion(-) >+ >+diff --git a/src/exim.c b/src/exim.c >+index 16c0184e0..625494ce4 100644 >+--- a/src/exim.c >++++ b/src/exim.c >+@@ -102,11 +102,13 @@ pcre_gen_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx); >+ * Execute regular expression and set strings * >+ *************************************************/ >+ >+ /* This function runs a regular expression match, and sets up the pointers to >+ the matched substrings. The matched strings are copied so the lifetime of >+-the subject is not a problem. >++the subject is not a problem. Matched strings will have the same taint status >++as the subject string (this is not a de-taint method, and must not be made so >++given the support for wildcards in REs). >+ >+ Arguments: >+ re the compiled expression >+ subject the subject string >+ options additional PCRE options >+@@ -130,10 +132,15 @@ if ((yield = (res >= 0))) >+ PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md); >+ res = pcre2_get_ovector_count(md); >+ expand_nmax = setup < 0 ? 0 : setup + 1; >+ for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++) >+ { >++ /* Although PCRE2 has a pcre2_substring_get_bynumber() conveneience, it >++ seems to return a bad pointer when a capture group had no data, eg. (.*) >++ matching zero letters. So use the underlying ovec and hope (!) that the >++ offsets are sane (including that case). Should we go further and range- >++ check each one vs. the subject string length? */ >+ int off = matchnum * 2; >+ int len = ovec[off + 1] - ovec[off]; >+ expand_nstring[expand_nmax] = string_copyn(subject + ovec[off], len); >+ expand_nlength[expand_nmax++] = len; >+ } >+-- >+2.35.1 >+ >diff --git a/mail/exim/files/debian/75_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch b/mail/exim/files/debian/75_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch >deleted file mode 100644 >index c226354d5e8e..000000000000 >--- a/mail/exim/files/debian/75_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch >+++ /dev/null >@@ -1,42 +0,0 @@ >-From df618101a5ea15dc90c4a2968798ef2be9dba16f Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Mon, 18 Oct 2021 11:01:47 +0100 >-Subject: [PATCH] Exiqgrep: check arg parsing. Bug 2821 >- >---- >- src/exiqgrep.src | 2 +- >- 1 file changed, 1 insertion(+), 1 deletion(-) >- >-diff --git a/src/exiqgrep.src b/src/exiqgrep.src >-index c8762df47..04602da68 100644 >---- a/src/exiqgrep.src >-+++ b/src/exiqgrep.src >-@@ -53,12 +53,14 @@ if ($ARGV[0] eq '--version') { >- exit 0; >- } >- >--getopts('hf:r:y:o:s:C:zxlibRcaG:',\%opt); >--if ($ARGV[0]) { &help; exit;} >--if ($opt{h}) { &help; exit;} >-+if (!getopts('hf:r:y:o:s:C:zxlibRcaG:E:',\%opt)) { &help; exit; } >-+if ($opt{h}) { &help; exit; } >-+if ($ARGV[0] || !($opt{f} || $opt{r} || $opt{s} || $opt{y} || $opt{o} || $opt{z} || $opt{x} || $opt{c})) >-+ { &help; exit(1); } >- if ($opt{a}) { $eargs = '-bp'; } >- if ($opt{C} && -e $opt{C} && -f $opt{C} && -R $opt{C}) { $eargs .= ' -C '.$opt{C}; } >- if ($opt{G}) { $eargs .= ' -qG'.$opt{G}; } >-+if ($opt{E}) { $exim = $opt{E}; } >- >- # Read message queue output into hash >- &collect(); >-@@ -75,6 +77,7 @@ Exim message queue display utility. >- >- -h This help message. >- -C Specify which exim.conf to use. >-+ -E Specify exim binary to use. >- >- Selection criteria: >- -f <regexp> Match sender address sender (field is "< >" wrapped) >--- >-2.34.1 >- >diff --git a/mail/exim/files/debian/75_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch b/mail/exim/files/debian/75_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch >new file mode 100644 >index 000000000000..2e21065fb1d6 >--- /dev/null >+++ b/mail/exim/files/debian/75_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch >@@ -0,0 +1,232 @@ >+From 7f65a63b60c6ea86db683ac00e221939f3bb1d47 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Tue, 25 Oct 2022 21:26:30 +0100 >+Subject: [PATCH 1/2] OpenSSL: when preloading creds do the server certs before >+ the OCSP proofs so that the latter can ve verified before loading >+ >+--- >+ src/tls-openssl.c | 113 ++++++++++++++++++++++-------------------- >+ 1 file changed, 58 insertions(+), 55 deletions(-) >+ >+diff --git a/src/tls-openssl.c b/src/tls-openssl.c >+index 68ad6f15b..fdf0d92b2 100644 >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -441,14 +441,16 @@ exim_openssl_state_st state_server = {.is_server = TRUE}; >+ static int >+ setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, >+ uschar ** errstr ); >+ >+ /* Callbacks */ >+ #ifndef DISABLE_OCSP >+ static int tls_server_stapling_cb(SSL *s, void *arg); >++static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk); >++static void x509_store_dump_cert_s_names(X509_STORE * store); >+ #endif >+ >+ >+ >+ /* Daemon-called, before every connection, key create/rotate */ >+ #ifndef DISABLE_TLS_RESUME >+ static void tk_init(void); >+@@ -1307,15 +1309,14 @@ ocsp_load_response(exim_openssl_state_st * state, const uschar * filename, >+ { >+ BIO * bio; >+ OCSP_RESPONSE * resp; >+ OCSP_BASICRESP * basic_response; >+ OCSP_SINGLERESP * single_response; >+ ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd; >+ STACK_OF(X509) * sk; >+-unsigned long verify_flags; >+ int status, reason, i; >+ >+ DEBUG(D_tls) >+ debug_printf("tls_ocsp_file (%s) '%s'\n", is_pem ? "PEM" : "DER", filename); >+ >+ if (!filename || !*filename) return; >+ >+@@ -1372,28 +1373,28 @@ if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL) >+ if (!(basic_response = OCSP_response_get1_basic(resp))) >+ { >+ DEBUG(D_tls) >+ debug_printf("OCSP response parse error: unable to extract basic response.\n"); >+ goto bad; >+ } >+ >+-sk = state->verify_stack; >+-verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */ >++sk = state->verify_stack; /* set by setup_certs() / chain_from_pem_file() */ >+ >+ /* May need to expose ability to adjust those flags? >+ OCSP_NOSIGS OCSP_NOVERIFY OCSP_NOCHAIN OCSP_NOCHECKS OCSP_NOEXPLICIT >+ OCSP_TRUSTOTHER OCSP_NOINTERN */ >+ >+-/* This does a full verify on the OCSP proof before we load it for serving >+-up; possibly overkill - just date-checks might be nice enough. >++/* This does a partial verify (only the signer link, not the whole chain-to-CA) >++on the OCSP proof before we load it for serving up; possibly overkill - >++just date-checks might be nice enough. >+ >+ OCSP_basic_verify takes a "store" arg, but does not >+-use it for the chain verification, which is all we do >+-when OCSP_NOVERIFY is set. The content from the wire >+-"basic_response" and a cert-stack "sk" are all that is used. >++use it for the chain verification, when OCSP_NOVERIFY is set. >++The content from the wire "basic_response" and a cert-stack "sk" are all >++that is used. >+ >+ We have a stack, loaded in setup_certs() if tls_verify_certificates >+ was a file (not a directory, or "system"). It is unfortunate we >+ cannot used the connection context store, as that would neatly >+ handle the "system" case too, but there seems to be no library >+ function for getting a stack from a store. >+ [ In OpenSSL 1.1 - ? X509_STORE_CTX_get0_chain(ctx) ? ] >+@@ -1402,15 +1403,15 @@ SNI handling. >+ >+ Separately we might try to replace using OCSP_basic_verify() - which seems to not >+ be a public interface into the OpenSSL library (there's no manual entry) - >+ But what with? We also use OCSP_basic_verify in the client stapling callback. >+ And there we NEED it; we must verify that status... unless the >+ library does it for us anyway? */ >+ >+-if ((i = OCSP_basic_verify(basic_response, sk, NULL, verify_flags)) < 0) >++if ((i = OCSP_basic_verify(basic_response, sk, NULL, OCSP_NOVERIFY)) < 0) >+ { >+ DEBUG(D_tls) >+ { >+ ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring)); >+ debug_printf("OCSP response verify failure: %s\n", US ssl_errstring); >+ } >+ goto bad; >+@@ -1747,61 +1748,18 @@ if (opt_unset_or_noexpand(tls_eccurve)) >+ if (init_ecdh(ctx, &dummy_errstr)) >+ state_server.lib_state.ecdh = TRUE; >+ } >+ else >+ DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n"); >+ >+ #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT) >+-/* If we can, preload the server-side cert, key and ocsp */ >+- >+-if ( opt_set_and_noexpand(tls_certificate) >+-# ifndef DISABLE_OCSP >+- && opt_unset_or_noexpand(tls_ocsp_file) >+-#endif >+- && opt_unset_or_noexpand(tls_privatekey)) >+- { >+- /* Set watches on the filenames. The implementation does de-duplication >+- so we can just blindly do them all. */ >+- >+- if ( tls_set_watch(tls_certificate, TRUE) >+-# ifndef DISABLE_OCSP >+- && tls_set_watch(tls_ocsp_file, TRUE) >+-#endif >+- && tls_set_watch(tls_privatekey, TRUE)) >+- { >+- state_server.certificate = tls_certificate; >+- state_server.privatekey = tls_privatekey; >+-#ifndef DISABLE_OCSP >+- state_server.u_ocsp.server.file = tls_ocsp_file; >+-#endif >+- >+- DEBUG(D_tls) debug_printf("TLS: preloading server certs\n"); >+- if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK) >+- state_server.lib_state.conn_certs = TRUE; >+- } >+- } >+-else if ( !tls_certificate && !tls_privatekey >+-# ifndef DISABLE_OCSP >+- && !tls_ocsp_file >+-#endif >+- ) >+- { /* Generate & preload a selfsigned cert. No files to watch. */ >+- if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK) >+- { >+- state_server.lib_state.conn_certs = TRUE; >+- lifetime = f.running_in_test_harness ? 2 : 60 * 60; /* 1 hour */ >+- } >+- } >+-else >+- DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n"); >+- >+- >+ /* If we can, preload the Authorities for checking client certs against. >+ Actual choice to do verify is made (tls_{,try_}verify_hosts) >+-at TLS conn startup */ >++at TLS conn startup. >++Do this before the server ocsp so that its info can verify the ocsp. */ >+ >+ if ( opt_set_and_noexpand(tls_verify_certificates) >+ && opt_unset_or_noexpand(tls_crl)) >+ { >+ /* Watch the default dir also as they are always included */ >+ >+ if ( tls_set_watch(CUS X509_get_default_cert_file(), FALSE) >+@@ -1809,18 +1767,63 @@ if ( opt_set_and_noexpand(tls_verify_certificates) >+ && tls_set_watch(tls_crl, FALSE)) >+ { >+ DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n"); >+ >+ if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr) >+ == OK) >+ state_server.lib_state.cabundle = TRUE; >+- } >++ >++ /* If we can, preload the server-side cert, key and ocsp */ >++ >++ if ( opt_set_and_noexpand(tls_certificate) >++# ifndef DISABLE_OCSP >++ && opt_unset_or_noexpand(tls_ocsp_file) >++# endif >++ && opt_unset_or_noexpand(tls_privatekey)) >++ { >++ /* Set watches on the filenames. The implementation does de-duplication >++ so we can just blindly do them all. */ >++ >++ if ( tls_set_watch(tls_certificate, TRUE) >++# ifndef DISABLE_OCSP >++ && tls_set_watch(tls_ocsp_file, TRUE) >++# endif >++ && tls_set_watch(tls_privatekey, TRUE)) >++ { >++ state_server.certificate = tls_certificate; >++ state_server.privatekey = tls_privatekey; >++#ifndef DISABLE_OCSP >++ state_server.u_ocsp.server.file = tls_ocsp_file; >++# endif >++ >++ DEBUG(D_tls) debug_printf("TLS: preloading server certs\n"); >++ if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK) >++ state_server.lib_state.conn_certs = TRUE; >++ } >++ } >++ else if ( !tls_certificate && !tls_privatekey >++# ifndef DISABLE_OCSP >++ && !tls_ocsp_file >++# endif >++ ) >++ { /* Generate & preload a selfsigned cert. No files to watch. */ >++ if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK) >++ { >++ state_server.lib_state.conn_certs = TRUE; >++ lifetime = f.running_in_test_harness ? 2 : 60 * 60; /* 1 hour */ >++ } >++ } >++ else >++ DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n"); >++ } >+ } >+ else >+ DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n"); >++ >++ >+ #endif /* EXIM_HAVE_INOTIFY */ >+ >+ >+ /* If we can, preload the ciphers control string */ >+ >+ if (opt_set_and_noexpand(tls_require_ciphers)) >+ { >+-- >+2.35.1 >+ >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 >deleted file mode 100644 >index 93c99a4ef8f2..000000000000 >--- a/mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch >+++ /dev/null >@@ -1,931 +0,0 @@ >-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_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch b/mail/exim/files/debian/75_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch >new file mode 100644 >index 000000000000..09e4f11ef20e >--- /dev/null >+++ b/mail/exim/files/debian/75_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch >@@ -0,0 +1,217 @@ >+From 62b97c2ecf148ee86053d82e5509e4c3a5a20054 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Sat, 29 Oct 2022 22:33:43 +0100 >+Subject: [PATCH 2/2] OpenSSL: fix double-expansion of tls_verify_certificates >+ >+--- >+ src/tls-openssl.c | 66 +++++++++++++++++++++---------------------- >+ 1 file changed, 33 insertions(+), 33 deletions(-) >+ >+diff --git a/src/tls-openssl.c b/src/tls-openssl.c >+index fdf0d92b2..2e09882d2 100644 >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -435,15 +435,15 @@ typedef struct exim_openssl_state { >+ /* should figure out a cleanup of API to handle state preserved per >+ implementation, for various reasons, which can be void * in the APIs. >+ For now, we hack around it. */ >+ exim_openssl_state_st *client_static_state = NULL; /*XXX should not use static; multiple concurrent clients! */ >+ exim_openssl_state_st state_server = {.is_server = TRUE}; >+ >+ static int >+-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, >++setup_certs(SSL_CTX * sctx, uschar ** certs, uschar * crl, host_item * host, >+ uschar ** errstr ); >+ >+ /* Callbacks */ >+ #ifndef DISABLE_OCSP >+ static int tls_server_stapling_cb(SSL *s, void *arg); >+ static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk); >+ static void x509_store_dump_cert_s_names(X509_STORE * store); >+@@ -1762,18 +1762,18 @@ if ( opt_set_and_noexpand(tls_verify_certificates) >+ { >+ /* Watch the default dir also as they are always included */ >+ >+ if ( tls_set_watch(CUS X509_get_default_cert_file(), FALSE) >+ && tls_set_watch(tls_verify_certificates, FALSE) >+ && tls_set_watch(tls_crl, FALSE)) >+ { >++ uschar * v_certs = tls_verify_certificates; >+ DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n"); >+ >+- if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr) >+- == OK) >++ if (setup_certs(ctx, &v_certs, tls_crl, NULL, &dummy_errstr) == OK) >+ state_server.lib_state.cabundle = TRUE; >+ >+ /* If we can, preload the server-side cert, key and ocsp */ >+ >+ if ( opt_set_and_noexpand(tls_certificate) >+ # ifndef DISABLE_OCSP >+ && opt_unset_or_noexpand(tls_ocsp_file) >+@@ -1897,18 +1897,19 @@ if ( opt_set_and_noexpand(ob->tls_verify_certificates) >+ { >+ if ( !watch >+ || tls_set_watch(CUS X509_get_default_cert_file(), FALSE) >+ && tls_set_watch(ob->tls_verify_certificates, FALSE) >+ && tls_set_watch(ob->tls_crl, FALSE) >+ ) >+ { >++ uschar * v_certs = ob->tls_verify_certificates; >+ DEBUG(D_tls) >+ debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name); >+ >+- if (setup_certs(ctx, ob->tls_verify_certificates, >++ if (setup_certs(ctx, &v_certs, >+ ob->tls_crl, dummy_host, &dummy_errstr) == OK) >+ ob->tls_preload.cabundle = TRUE; >+ } >+ } >+ else >+ DEBUG(D_tls) >+ debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name); >+@@ -2238,22 +2239,20 @@ if (state->u_ocsp.server.file) >+ { >+ SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb); >+ SSL_CTX_set_tlsext_status_arg(server_sni, state); >+ } >+ #endif >+ >+ { >+- uschar * expcerts; >+- if ( !expand_check(tls_verify_certificates, US"tls_verify_certificates", >+- &expcerts, &dummy_errstr) >+- || (rc = setup_certs(server_sni, expcerts, tls_crl, NULL, >++ uschar * v_certs = tls_verify_certificates; >++ if ((rc = setup_certs(server_sni, &v_certs, tls_crl, NULL, >+ &dummy_errstr)) != OK) >+ goto bad; >+ >+- if (expcerts && *expcerts) >++ if (v_certs && *v_certs) >+ setup_cert_verify(server_sni, FALSE, verify_callback_server); >+ } >+ >+ /* do this after setup_certs, because this can require the certs for verifying >+ OCSP information. */ >+ if ((rc = tls_expand_session_files(server_sni, state, &dummy_errstr)) != OK) >+ goto bad; >+@@ -3017,32 +3016,33 @@ return TRUE; >+ >+ >+ /* Called by both client and server startup; on the server possibly >+ repeated after a Server Name Indication. >+ >+ Arguments: >+ sctx SSL_CTX* to initialise >+- certs certs file, expanded >++ certs certs file, returned expanded >+ crl CRL file or NULL >+ host NULL in a server; the remote host in a client >+ errstr error string pointer >+ >+ Returns: OK/DEFER/FAIL >+ */ >+ >+ static int >+-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, >++setup_certs(SSL_CTX * sctx, uschar ** certsp, uschar * crl, host_item * host, >+ uschar ** errstr) >+ { >+-uschar *expcerts, *expcrl; >++uschar * expcerts, * expcrl; >+ >+-if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr)) >++if (!expand_check(*certsp, US"tls_verify_certificates", &expcerts, errstr)) >+ return DEFER; >+ DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts); >+ >++*certsp = expcerts; >+ if (expcerts && *expcerts) >+ { >+ /* Tell the library to use its compiled-in location for the system default >+ CA bundle. Then add the ones specified in the config, if any. */ >+ >+ if (!SSL_CTX_set_default_verify_paths(sctx)) >+ return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr); >+@@ -3330,28 +3330,28 @@ if (verify_check_host(&tls_verify_hosts) == OK) >+ server_verify_optional = FALSE; >+ else if (verify_check_host(&tls_try_verify_hosts) == OK) >+ server_verify_optional = TRUE; >+ else >+ goto skip_certs; >+ >+ { >+- uschar * expcerts; >+- if (!expand_check(tls_verify_certificates, US"tls_verify_certificates", >+- &expcerts, errstr)) >+- return DEFER; >+- DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts); >++ uschar * v_certs = tls_verify_certificates; >+ >+ if (state_server.lib_state.cabundle) >+- { DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); } >++ { >++ DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); >++ setup_cert_verify(ctx, server_verify_optional, verify_callback_server); >++ } >+ else >+- if ((rc = setup_certs(ctx, expcerts, tls_crl, NULL, errstr)) != OK) >++ { >++ if ((rc = setup_certs(ctx, &v_certs, tls_crl, NULL, errstr)) != OK) >+ return rc; >+- >+- if (expcerts && *expcerts) >+- setup_cert_verify(ctx, server_verify_optional, verify_callback_server); >++ if (v_certs && *v_certs) >++ setup_cert_verify(ctx, server_verify_optional, verify_callback_server); >++ } >+ } >+ skip_certs: ; >+ >+ #ifndef DISABLE_TLS_RESUME >+ # if OPENSSL_VERSION_NUMBER < 0x30000000L >+ SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback); >+ /* despite working, appears to always return failure, so ignoring */ >+@@ -3606,28 +3606,28 @@ if ( ( ( !ob->tls_verify_hosts || !ob->tls_verify_hosts >+ client_verify_optional = FALSE; >+ else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK) >+ client_verify_optional = TRUE; >+ else >+ return OK; >+ >+ { >+- uschar * expcerts; >+- if (!expand_check(ob->tls_verify_certificates, US"tls_verify_certificates", >+- &expcerts, errstr)) >+- return DEFER; >+- DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts); >++ uschar * v_certs = ob->tls_verify_certificates; >+ >+ if (state->lib_state.cabundle) >+- { DEBUG(D_tls) debug_printf("TLS: CA bundle was preloaded\n"); } >++ { >++ DEBUG(D_tls) debug_printf("TLS: CA bundle for tpt was preloaded\n"); >++ setup_cert_verify(ctx, client_verify_optional, verify_callback_client); >++ } >+ else >+- if ((rc = setup_certs(ctx, expcerts, ob->tls_crl, host, errstr)) != OK) >++ { >++ if ((rc = setup_certs(ctx, &v_certs, ob->tls_crl, host, errstr)) != OK) >+ return rc; >+- >+- if (expcerts && *expcerts) >+- setup_cert_verify(ctx, client_verify_optional, verify_callback_client); >++ if (v_certs && *v_certs) >++ setup_cert_verify(ctx, client_verify_optional, verify_callback_client); >++ } >+ } >+ >+ if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK) >+ { >+ state->verify_cert_hostnames = >+ #ifdef SUPPORT_I18N >+ string_domain_utf8_to_alabel(host->certname, NULL); >+-- >+2.35.1 >+ >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 >deleted file mode 100644 >index b156611bd0e6..000000000000 >--- a/mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch >+++ /dev/null >@@ -1,140 +0,0 @@ >-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/debian/75_43-BSD-fix-resource-leak.patch b/mail/exim/files/debian/75_43-BSD-fix-resource-leak.patch >deleted file mode 100644 >index 0a624c30875c..000000000000 >--- a/mail/exim/files/debian/75_43-BSD-fix-resource-leak.patch >+++ /dev/null >@@ -1,61 +0,0 @@ >-From c57309a50444d858c0a2dc1581846a850d78a9ad Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Tue, 11 Jan 2022 11:21:45 +0000 >-Subject: [PATCH 077/151] BSD: fix resource leak >- >---- >- doc/ChangeLog | 4 ++++ >- src/tls.c | 9 +++++---- >- >-diff --git a/doc/ChangeLog b/doc/ChangeLog >-index e7c7085f8..567399483 100644 >---- a/doc/ChangeLog >-+++ b/doc/ChangeLog >-@@ -65,6 +65,10 @@ JH/13 Bug 2845: Fix handling of tls_require_ciphers for OpenSSL when a value >- >- JH/14 Bug 1895: TLS: Deprecate RFC 5114 Diffie-Hellman parameters. >- >-+JH/15 Fix a resource leak in *BSD. An off-by-one error resulted in the daemon >-+ failing to close the certificates directory, every hour or any time it >-+ was touched. >-+ >- >- Exim version 4.95 >- ----------------- >-diff --git a/src/tls.c b/src/tls.c >-index d5d11bcea..e6b1bf7a7 100644 >---- a/src/tls.c >-+++ b/src/tls.c >-@@ -185,8 +185,8 @@ for (;;) >- { >- if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0) >- { s = US"open file"; goto bad; } >-- DEBUG(D_tls) debug_printf("watch file '%s'\n", filename); >-- EV_SET(&kev[++kev_used], >-+ DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1); >-+ EV_SET(&kev[kev_used++], >- (uintptr_t)fd1, >- EVFILT_VNODE, >- EV_ADD | EV_ENABLE | EV_ONESHOT, >-@@ -196,8 +196,8 @@ for (;;) >- NULL); >- cnt++; >- } >-- DEBUG(D_tls) debug_printf("watch dir '%s'\n", s); >-- EV_SET(&kev[++kev_used], >-+ DEBUG(D_tls) debug_printf("watch dir '%s':\t%d\n", s, fd2); >-+ EV_SET(&kev[kev_used++], >- (uintptr_t)fd2, >- EVFILT_VNODE, >- EV_ADD | EV_ENABLE | EV_ONESHOT, >-@@ -320,6 +320,7 @@ if (tls_watch_fd < 0) return; >- /* Close the files we had open for kevent */ >- for (int i = 0; i < kev_used; i++) >- { >-+ DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident); >- (void) close((int) kev[i].ident); >- kev[i].ident = (uintptr_t)-1; >- } >--- >-2.35.1 >- >diff --git a/mail/exim/files/debian/75_45-Fix-bogus-error-message-copy.-Bug-2857.patch b/mail/exim/files/debian/75_45-Fix-bogus-error-message-copy.-Bug-2857.patch >deleted file mode 100644 >index 7a582781136d..000000000000 >--- a/mail/exim/files/debian/75_45-Fix-bogus-error-message-copy.-Bug-2857.patch >+++ /dev/null >@@ -1,38 +0,0 @@ >-From 7ad863f3819407559cd654639c25dcae427c190f Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Sun, 6 Feb 2022 19:00:26 +0000 >-Subject: [PATCH] Fix bogus error message copy. Bug 2857 >- >-Broken-by: bb43acbd98 >---- >- src/parse.c | 9 +++++---- >- 1 file changed, 5 insertions(+), 4 deletions(-) >- >-diff --git a/src/parse.c b/src/parse.c >-index 5bf97eab9..edbee2646 100644 >---- a/src/parse.c >-+++ b/src/parse.c >-@@ -1354,15 +1354,16 @@ for (;;) >- >- if (special) >- { >-- uschar *ss = Ustrchr(s+1, ':') + 1; >-+ uschar * ss = Ustrchr(s+1, ':') + 1; /* line after the special... */ >- if ((options & specopt) == specbit) >- { >- *error = string_sprintf("\"%.*s\" is not permitted", len, s); >- return FF_ERROR; >- } >-- while (*ss && isspace(*ss)) ss++; >-- while (s[len] && s[len] != '\n') len++; >-- *error = string_copyn(ss, s + len - ss); >-+ while (*ss && isspace(*ss)) ss++; /* skip leading whitespace */ >-+ if ((len = Ustrlen(ss)) > 0) /* ignore trailing newlines */ >-+ for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--; >-+ *error = string_copyn(ss, len); /* becomes the error */ >- return special; >- } >- >--- >-2.34.1 >- >diff --git a/mail/exim/files/debian/75_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch b/mail/exim/files/debian/75_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch >deleted file mode 100644 >index 0344630e70b3..000000000000 >--- a/mail/exim/files/debian/75_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch >+++ /dev/null >@@ -1,62 +0,0 @@ >-From 7f8394e7c983b1c199866fc6b1c14feb857b651d Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Sun, 13 Feb 2022 12:00:55 +0000 >-Subject: [PATCH] Fix include_directory in redirect routers. Bug 2715 >- >-Broken-by: 10c50704c1 >---- >- doc/ChangeLog | 5 +++++ >- src/parse.c | 9 ++++++--- >- test/confs/0313 | 4 +++- >- test/log/0313 | 2 ++ >- test/scripts/0000-Basic/0313 | 2 ++ >- 5 files changed, 18 insertions(+), 4 deletions(-) >- >---- a/doc/ChangeLog >-+++ b/doc/ChangeLog >-@@ -23,6 +23,11 @@ JH/15 Fix a resource leak in *BSD. An off-by-one erro >- failing to close the certificates directory, every hour or any time it >- was touched. >- >-+JH/18 Bug 2751: Fix include_directory in redirect routers. Previously a >-+ bad comparison between the option value and the name of the file to >-+ be included was done, and a mismatch was wrongly identified. >-+ 4.88 to 4.95 are affected. >-+ >- >- Exim version 4.95 >- ----------------- >---- a/src/parse.c >-+++ b/src/parse.c >-@@ -1422,11 +1422,13 @@ >- /* Check file name if required */ >- >- if (directory) >- { >- int len = Ustrlen(directory); >-- uschar *p = filename + len; >-+ uschar * p; >-+ while (len > 0 && directory[len-1] == '/') len--; /* ignore trailing '/' */ >-+ p = filename + len; >- >- if (Ustrncmp(filename, directory, len) != 0 || *p != '/') >- { >- *error = string_sprintf("included file %s is not in directory %s", >- filename, directory); >-@@ -1448,13 +1450,14 @@ >- } >- while (*p) >- { >- uschar temp; >- int fd2; >-- uschar * q = p; >-+ uschar * q = p + 1; /* skip dividing '/' */ >- >-- while (*++p && *p != '/') ; >-+ while (*q == '/') q++; /* skip extra '/' */ >-+ while (*++p && *p != '/') ; /* end of component */ >- temp = *p; >- *p = '\0'; >- >- fd2 = exim_openat(fd, CS q, O_RDONLY|O_NOFOLLOW); >- close(fd); >diff --git a/mail/exim/files/debian/75_50-Fix-logging-of-max-size-log-line.patch b/mail/exim/files/debian/75_50-Fix-logging-of-max-size-log-line.patch >new file mode 100644 >index 000000000000..5992faca6eac >--- /dev/null >+++ b/mail/exim/files/debian/75_50-Fix-logging-of-max-size-log-line.patch >@@ -0,0 +1,82 @@ >+From 1ed24e36e279c922d3366f6c3144570cc5f54d7a Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Mon, 19 Dec 2022 21:09:17 +0000 >+Subject: [PATCH] Fix logging of max-size log line >+ >+Broken-by: d12746bc15d8 >+--- >+ doc/ChangeLog | 5 +++++ >+ src/log.c | 7 ++++--- >+ test/confs/0633 | 21 ++++++++++++++++++++ >+ test/scripts/0000-Basic/0633 | 9 +++++++++ >+ test/stderr/0633 | 38 ++++++++++++++++++++++++++++++++++++ >+ test/stdout/0633 | 15 ++++++++++++++ >+ 6 files changed, 92 insertions(+), 3 deletions(-) >+ create mode 100644 test/confs/0633 >+ create mode 100644 test/scripts/0000-Basic/0633 >+ create mode 100644 test/stderr/0633 >+ create mode 100644 test/stdout/0633 >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -28,10 +28,15 @@ JH/13 Bug 2929: Fix using $recipients af >+ JH/14 Bug 2933: Fix regex substring match variables for null matches. Since 4.96 >+ a capture group which obtained no text (eg. "(abc)*" matching zero >+ occurrences) could cause a segfault if the corresponding $<n> was >+ expanded. >+ >++JH/18 Fix a fencepost error in logging. Previously (since 4.92) when a log line >++ was exactly sized compared to the log buffer, a crash occurred with the >++ misleading message "bad memory reference; pool not found". >++ Found and traced by Jasen Betts. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/log.c >++++ b/src/log.c >+@@ -803,11 +803,11 @@ Returns: nothing >+ void >+ log_write(unsigned int selector, int flags, const char *format, ...) >+ { >+ int paniclogfd; >+ ssize_t written_len; >+-gstring gs = { .size = LOG_BUFFER_SIZE-1, .ptr = 0, .s = log_buffer }; >++gstring gs = { .size = LOG_BUFFER_SIZE-2, .ptr = 0, .s = log_buffer }; >+ gstring * g; >+ va_list ap; >+ >+ /* If panic_recurseflag is set, we have failed to open the panic log. This is >+ the ultimate disaster. First try to write the message to a debug file and/or >+@@ -949,15 +949,14 @@ DEBUG(D_any|D_v) >+ g->ptr = i; >+ g = string_cat(g, US"**** log string overflowed log buffer ****"); >+ } >+ va_end(ap); >+ >+- g->size = LOG_BUFFER_SIZE; >+ g = string_catn(g, US"\n", 1); >+ debug_printf("%s", string_from_gstring(g)); >+ >+- gs.size = LOG_BUFFER_SIZE-1; /* Having used the buffer for debug output, */ >++ gs.size = LOG_BUFFER_SIZE-2; /* Having used the buffer for debug output, */ >+ gs.ptr = 0; /* reset it for the real use. */ >+ gs.s = log_buffer; >+ } >+ /* If no log file is specified, we are in a mess. */ >+ >+@@ -1035,10 +1034,12 @@ if ( flags & LOG_RECIPIENTS >+ if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break; >+ g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s); >+ } >+ } >+ >++/* actual size, now we are placing the newline (and space for NUL) */ >++gs.size = LOG_BUFFER_SIZE; >+ g = string_catn(g, US"\n", 1); >+ string_from_gstring(g); >+ >+ /* Handle loggable errors when running a utility, or when address testing. >+ Write to log_stderr unless debugging (when it will already have been written), >diff --git a/mail/exim/files/debian/75_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch b/mail/exim/files/debian/75_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch >new file mode 100644 >index 000000000000..bbbfbe9ef1e7 >--- /dev/null >+++ b/mail/exim/files/debian/75_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch >@@ -0,0 +1,76 @@ >+From 1d38781da934809e6ce0b8c3718c4b3bccdfe1d2 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Wed, 28 Dec 2022 19:39:06 +0000 >+Subject: [PATCH] Fix recursion on dns_again_means_nonexist. Bug 2911 >+ >+--- >+ doc/ChangeLog | 8 +++++ >+ src/dns.c | 12 ++++++++ >+ test/confs/2202 | 18 +++++++++-- >+ test/scripts/2200-dnsdb/2202 | 8 +++++ >+ test/stderr/2202 | 58 +++++++++++++++++++++++++++++++++++- >+ test/stdout/2202 | 8 +++++ >+ 6 files changed, 108 insertions(+), 4 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -33,10 +33,18 @@ JH/14 Bug 2933: Fix regex substring matc >+ JH/18 Fix a fencepost error in logging. Previously (since 4.92) when a log line >+ was exactly sized compared to the log buffer, a crash occurred with the >+ misleading message "bad memory reference; pool not found". >+ Found and traced by Jasen Betts. >+ >++JH/19 Bug 2911: Fix a recursion in DNS lookups. Previously, if the main option >++ dns_again_means_nonexist included an element causing a DNS lookup which >++ iteslf returned DNS_AGAIN, unbounded recursion occurred. Possible results >++ included (though probably not limited to) a process crash from stack >++ memory limit, or from excessive open files. Replace this with a paniclog >++ whine (as this is likely a configuration error), and returning >++ DNS_NOMATCH. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/dns.c >++++ b/src/dns.c >+@@ -799,10 +799,11 @@ int >+ dns_basic_lookup(dns_answer * dnsa, const uschar * name, int type) >+ { >+ int rc; >+ #ifndef STAND_ALONE >+ const uschar * save_domain; >++static BOOL try_again_recursion = FALSE; >+ #endif >+ >+ /* DNS lookup failures of any kind are cached in a tree. This is mainly so that >+ a timeout on one domain doesn't happen time and time again for messages that >+ have many addresses in the same domain. We rely on the resolver and name server >+@@ -903,15 +904,26 @@ if (dnsa->answerlen < 0) switch (h_errno >+ DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n", >+ name, dns_text_type(type)); >+ >+ /* Cut this out for various test programs */ >+ #ifndef STAND_ALONE >++ if (try_again_recursion) >++ { >++ log_write(0, LOG_MAIN|LOG_PANIC, >++ "dns_again_means_nonexist recursion seen for %s (assuming nonexist)", >++ name); >++ return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); >++ } >++ >++ try_again_recursion = TRUE; >+ save_domain = deliver_domain; >+ deliver_domain = string_copy(name); /* set $domain */ >+ rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0, >+ &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); >+ deliver_domain = save_domain; >++ try_again_recursion = FALSE; >++ >+ if (rc != OK) >+ { >+ DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n"); >+ return dns_fail_return(name, type, 0, DNS_AGAIN); >+ } >diff --git a/mail/exim/files/debian/75_55-Specific-check-for-null-pointer.patch b/mail/exim/files/debian/75_55-Specific-check-for-null-pointer.patch >deleted file mode 100644 >index 0d52bf5091a0..000000000000 >--- a/mail/exim/files/debian/75_55-Specific-check-for-null-pointer.patch >+++ /dev/null >@@ -1,67 +0,0 @@ >-From b249717db8ced250a586385f06e61cf7107d5222 Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Fri, 18 Feb 2022 15:45:37 +0000 >-Subject: [PATCH] Specific check for null pointer >- >---- >- src/smtp_out.c | 18 +++++++++++++----- >- 1 file changed, 13 insertions(+), 5 deletions(-) >- >-diff --git a/src/smtp_out.c b/src/smtp_out.c >-index 608a781eb..fc1e6cecd 100644 >---- a/src/smtp_out.c >-+++ b/src/smtp_out.c >-@@ -524,13 +524,21 @@ flush_buffer(smtp_outblock * outblock, int mode) >- int rc; >- int n = outblock->ptr - outblock->buffer; >- BOOL more = mode == SCMD_MORE; >-+client_conn_ctx * cctx; >- >- HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n, >- more ? " (more expected)" : ""); >- >-+if (!(cctx = outblock->cctx)) >-+ { >-+ log_write(0, LOG_MAIN|LOG_PANIC, "null conn-context pointer"); >-+ errno = 0; >-+ return FALSE; >-+ } >-+ >- #ifndef DISABLE_TLS >--if (outblock->cctx->tls_ctx) >-- rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more); >-+if (cctx->tls_ctx) /*XXX have seen a null cctx here, rvfy sending QUIT, hence check above */ >-+ rc = tls_write(cctx->tls_ctx, outblock->buffer, n, more); >- else >- #endif >- >-@@ -544,7 +552,7 @@ else >- requirement: TFO with data can, in rare cases, replay the data to the >- receiver. */ >- >-- if ( (outblock->cctx->sock = smtp_connect(outblock->conn_args, &early_data)) >-+ if ( (cctx->sock = smtp_connect(outblock->conn_args, &early_data)) >- < 0) >- return FALSE; >- outblock->conn_args = NULL; >-@@ -552,7 +560,7 @@ else >- } >- else >- { >-- rc = send(outblock->cctx->sock, outblock->buffer, n, >-+ rc = send(cctx->sock, outblock->buffer, n, >- #ifdef MSG_MORE >- more ? MSG_MORE : 0 >- #else >-@@ -567,7 +575,7 @@ else >- https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */ >- >- if (!more) >-- setsockopt(outblock->cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off)); >-+ setsockopt(cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off)); >- #endif >- } >- } >--- >-2.34.1 >- >diff --git a/mail/exim/files/debian/75_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch b/mail/exim/files/debian/75_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch >new file mode 100644 >index 000000000000..ddf54fa02af2 >--- /dev/null >+++ b/mail/exim/files/debian/75_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch >@@ -0,0 +1,50 @@ >+From 57d70161718e02927a22d6a3481803b72035ac46 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Sat, 31 Dec 2022 13:37:17 +0000 >+Subject: [PATCH] Close server smtp socket explicitly on connect ACL "drop" >+ >+--- >+ src/smtp_in.c | 13 ++++++++ >+ test/confs/0022 | 2 ++ >+ test/log/0022 | 2 ++ >+ test/rejectlog/0022 | 3 ++ >+ test/scripts/0000-Basic/0022 | 13 ++++++++ >+ test/stderr/0022 | 60 ++++++++++++++++++------------------ >+ test/stdout/0022 | 6 ++++ >+ 7 files changed, 69 insertions(+), 30 deletions(-) >+ create mode 100644 test/rejectlog/0022 >+ >+diff --git a/src/smtp_in.c b/src/smtp_in.c >+index 1cfcc0404..6880e3c09 100644 >+--- a/src/smtp_in.c >++++ b/src/smtp_in.c >+@@ -3563,10 +3563,23 @@ log_write(L_smtp_connection, LOG_MAIN, "%s closed by DROP in ACL", >+ /* Run the not-quit ACL, but without any custom messages. This should not be a >+ problem, because we get here only if some other ACL has issued "drop", and >+ in that case, *its* custom messages will have been used above. */ >+ >+ smtp_notquit_exit(US"acl-drop", NULL, NULL); >++ >++/* An overenthusiastic fail2ban/iptables implimentation has been seen to result >++in the TCP conn staying open, and retrying, despite this process exiting. A >++malicious client could possibly do the same, tying up server netowrking >++resources. Close the socket explicitly to try to avoid that (there's a note in >++the Linux socket(7) manpage, SO_LINGER para, to the effect that exim() without >++close() results in the socket always lingering). */ >++ >++(void) poll_one_fd(fileno(smtp_in), POLLIN, 200); >++DEBUG(D_any) debug_printf_indent("SMTP(close)>>\n"); >++(void) fclose(smtp_in); >++(void) fclose(smtp_out); >++ >+ return 2; >+ } >+ >+ >+ >+diff --git a/test/rejectlog/0022 b/test/rejectlog/0022 >+new file mode 100644 >+index 000000000..68e21fff3 >+-- >+2.39.0 >+ >diff --git a/mail/exim/files/debian/75_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch b/mail/exim/files/debian/75_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch >new file mode 100644 >index 000000000000..da05ba9476a8 >--- /dev/null >+++ b/mail/exim/files/debian/75_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch >@@ -0,0 +1,184 @@ >+From ca4014de81e6aa367aa0a54c49b4c3d4b137814c Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Sun, 1 Jan 2023 12:18:38 +0000 >+Subject: [PATCH] OpenSSL: fix tls_eccurve setting explicit curve/group. Bug >+ 2954 >+ >+--- >+ doc/ChangeLog | 4 +++ >+ src/tls-openssl.c | 39 ++++++++++++++---------- >+ test/confs/2148 | 54 ++++++++++++++++++++++++++++++++++ >+ test/confs/2149 | 39 +++++++++++++----------- >+ test/log/2148 | 48 ++++++++++++++++++++++++++++++ >+ test/log/2149 | 39 ++++++++++++------------ >+ test/paniclog/{2149 => 2148} | 0 >+ test/scripts/2100-OpenSSL/2148 | 50 +++++++++++++++++++++++++++++++ >+ test/scripts/2100-OpenSSL/2149 | 50 ++++++++++++++++--------------- >+ test/stderr/2148 | 5 ++++ >+ test/stderr/2149 | 3 -- >+ 11 files changed, 250 insertions(+), 81 deletions(-) >+ create mode 100644 test/confs/2148 >+ create mode 100644 test/log/2148 >+ rename test/paniclog/{2149 => 2148} (100%) >+ create mode 100644 test/scripts/2100-OpenSSL/2148 >+ create mode 100644 test/stderr/2148 >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -41,10 +41,14 @@ JH/19 Bug 2911: Fix a recursion in DNS l >+ included (though probably not limited to) a process crash from stack >+ memory limit, or from excessive open files. Replace this with a paniclog >+ whine (as this is likely a configuration error), and returning >+ DNS_NOMATCH. >+ >++JH/20 Bug 2954: (OpenSSL) Fix setting of explicit EC curve/group. Previously >++ this always failed, probably leading to the usual downgrade to in-clear >++ connections. >++ >+ >+ >+ Exim version 4.96 >+ ----------------- >+ >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -657,16 +657,16 @@ if (dh_bitsize <= tls_dh_max_bits) >+ /* EVP_PKEY_free(pkey); crashes */ >+ #endif >+ } >+ else >+ DEBUG(D_tls) >+- debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n", >++ debug_printf(" Diffie-Hellman initialized from %s with %d-bit prime\n", >+ dhexpanded ? dhexpanded : US"default", dh_bitsize); >+ } >+ else >+ DEBUG(D_tls) >+- debug_printf("dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n", >++ debug_printf(" dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n", >+ dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits); >+ >+ #if OPENSSL_VERSION_NUMBER < 0x30000000L >+ DH_free(dh); >+ #endif >+@@ -712,23 +712,31 @@ init_ecdh(SSL_CTX * sctx, uschar ** errs >+ #ifdef OPENSSL_NO_ECDH >+ return TRUE; >+ #else >+ >+ uschar * exp_curve; >+-int nid; >+-BOOL rv; >++int nid, rc; >+ >+ # ifndef EXIM_HAVE_ECDH >+ DEBUG(D_tls) >+- debug_printf("No OpenSSL API to define ECDH parameters, skipping\n"); >++ debug_printf(" No OpenSSL API to define ECDH parameters, skipping\n"); >+ return TRUE; >+ # else >+ >+ if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr)) >+ return FALSE; >++ >++/* Is the option deliberately empty? */ >++ >+ if (!exp_curve || !*exp_curve) >++ { >++#if OPENSSL_VERSION_NUMBER >= 0x10002000L >++ DEBUG(D_tls) debug_printf( " ECDH OpenSSL 1.0.2+: clearing curves list\n"); >++ (void) SSL_CTX_set1_curves(sctx, &nid, 0); >++#endif >+ return TRUE; >++ } >+ >+ /* "auto" needs to be handled carefully. >+ * OpenSSL < 1.0.2: we do not select anything, but fallback to prime256v1 >+ * OpenSSL < 1.1.0: we have to call SSL_CTX_set_ecdh_auto >+ * (openssl/ssl.h defines SSL_CTRL_SET_ECDH_AUTO) >+@@ -737,27 +745,26 @@ if (!exp_curve || !*exp_curve) >+ */ >+ if (Ustrcmp(exp_curve, "auto") == 0) >+ { >+ #if OPENSSL_VERSION_NUMBER < 0x10002000L >+ DEBUG(D_tls) debug_printf( >+- "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n"); >++ " ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n"); >+ exp_curve = US"prime256v1"; >+ #else >+ # if defined SSL_CTRL_SET_ECDH_AUTO >+ DEBUG(D_tls) debug_printf( >+- "ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n"); >++ " ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n"); >+ SSL_CTX_set_ecdh_auto(sctx, 1); >+ return TRUE; >+ # else >+ DEBUG(D_tls) debug_printf( >+- "ECDH OpenSSL 1.1.0+: temp key parameter settings: default selection\n"); >++ " ECDH OpenSSL 1.1.0+: temp key parameter settings: library default selection\n"); >+ return TRUE; >+ # endif >+ #endif >+ } >+ >+-DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve); >+ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef >+ # ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID >+ && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef >+ # endif >+ ) >+@@ -777,27 +784,27 @@ if ( (nid = OBJ_sn2nid (CCS exp_c >+ } >+ >+ /* The "tmp" in the name here refers to setting a temporary key >+ not to the stability of the interface. */ >+ >+- if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0)) >++ if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0)) >+ tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr); >+ else >+- DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve); >++ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve); >+ EC_KEY_free(ecdh); >+ } >+ >+ #else /* v 3.0.0 + */ >+ >+-if ((rv = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0) >++if ((rc = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0) >+ tls_error(string_sprintf("Error enabling '%s' group", exp_curve), NULL, NULL, errstr); >+ else >+- DEBUG(D_tls) debug_printf("ECDH: enabled '%s' group\n", exp_curve); >++ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' group\n", exp_curve); >+ >+ #endif >+ >+-return !rv; >++return !!rc; >+ >+ # endif /*EXIM_HAVE_ECDH*/ >+ #endif /*OPENSSL_NO_ECDH*/ >+ } >+ >+@@ -1719,19 +1726,19 @@ state_server.lib_state.lib_ctx = ctx; >+ >+ /* Preload DH params and EC curve */ >+ >+ if (opt_unset_or_noexpand(tls_dhparam)) >+ { >+- DEBUG(D_tls) debug_printf("TLS: preloading DH params for server\n"); >++ DEBUG(D_tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam); >+ if (init_dh(ctx, tls_dhparam, &dummy_errstr)) >+ state_server.lib_state.dh = TRUE; >+ } >+ else >+ DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n"); >+ if (opt_unset_or_noexpand(tls_eccurve)) >+ { >+- DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n"); >++ DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve); >+ if (init_ecdh(ctx, &dummy_errstr)) >+ state_server.lib_state.ecdh = TRUE; >+ } >+ else >+ DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n"); >diff --git a/mail/exim/files/debian/75_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch b/mail/exim/files/debian/75_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch >new file mode 100644 >index 000000000000..e346df17abdb >--- /dev/null >+++ b/mail/exim/files/debian/75_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch >@@ -0,0 +1,42 @@ >+From 7fa5764c203f2f4a900898a79ed02d674075313f Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Mon, 2 Jan 2023 15:04:14 +0000 >+Subject: [PATCH 1/3] OpenSSL: Fix tls_eccurve on earlier versions than 3.0.0. >+ Bug 2954 >+ >+Broken-by: ca4014de81e6 >+--- >+ src/tls-openssl.c | 7 ++++--- >+ test/log/2149 | 28 ++++++++++++++-------------- >+ test/runtest | 3 +++ >+ test/scripts/2100-OpenSSL/2149 | 22 ++++++++++++---------- >+ 4 files changed, 33 insertions(+), 27 deletions(-) >+ >+diff --git a/src/tls-openssl.c b/src/tls-openssl.c >+index 4d0f99ea9..e063d29bd 100644 >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -786,8 +786,9 @@ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef >+ # endif >+ ) >+ { >+- tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve), >+- NULL, NULL, errstr); >++ uschar * s = string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve); >++ DEBUG(D_tls) debug_printf("TLS error '%s'\n", s); >++ if (errstr) *errstr = s; >+ return FALSE; >+ } >+ >+@@ -803,7 +804,7 @@ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef >+ /* The "tmp" in the name here refers to setting a temporary key >+ not to the stability of the interface. */ >+ >+- if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0)) >++ if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh)) == 0) >+ tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr); >+ else >+ DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve); >+-- >+2.39.0 >+ >diff --git a/mail/exim/files/debian/75_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch b/mail/exim/files/debian/75_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch >new file mode 100644 >index 000000000000..15b1b8a8ff8d >--- /dev/null >+++ b/mail/exim/files/debian/75_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch >@@ -0,0 +1,99 @@ >+From e1aca33756f73c22b00a98d40ce2be8ed94464b1 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Thu, 5 Jan 2023 13:03:37 +0000 >+Subject: [PATCH 2/3] OpenSSL: log conns rejected for bad ALPN, with the >+ offered value >+ >+Unfortunately, no way to do this under GnuTLS >+--- >+ src/match.c | 1 + >+ src/tls-gnu.c | 9 ++++++++- >+ src/tls-openssl.c | 13 +++++++++++-- >+ test/log/1190 | 2 ++ >+ test/runtest | 3 +++ >+ 5 files changed, 25 insertions(+), 3 deletions(-) >+ >+diff --git a/src/match.c b/src/match.c >+index 91a49c0f0..07070362d 100644 >+--- a/src/match.c >++++ b/src/match.c >+@@ -968,6 +968,7 @@ Arguments: >+ s string to search for >+ listptr ptr to ptr to colon separated list of patterns, or NULL >+ sep a separator value for the list (see string_nextinlist()) >++ or zero for auto >+ anchorptr ptr to tree for named items, or NULL if no named items >+ cache_bits ptr to cache_bits for ditto, or NULL if not caching >+ type MCL_DOMAIN when matching a domain list >+diff --git a/src/tls-gnu.c b/src/tls-gnu.c >+index 729fb5879..b47fabf1d 100644 >+--- a/src/tls-gnu.c >++++ b/src/tls-gnu.c >+@@ -1119,21 +1119,28 @@ switch (tls_id) >+ /* The format of "data" here doesn't seem to be documented, but appears >+ to be a 2-byte field with a (redundant, given the "size" arg) total length >+ then a sequence of one-byte size then string (not nul-term) names. The >+- latter is as described in OpenSSL documentation. */ >++ latter is as described in OpenSSL documentation. >++ Note that we do not get called for a match_fail, making it hard to log >++ a single bad ALPN being offered (the common case). */ >++ { >++ gstring * g = NULL; >+ >+ DEBUG(D_tls) debug_printf("Seen ALPN extension from client (s=%u):", size); >+ for (const uschar * s = data+2; s-data < size-1; s += *s + 1) >+ { >+ server_seen_alpn++; >++ g = string_append_listele_n(g, ':', s+1, *s); >+ DEBUG(D_tls) debug_printf(" '%.*s'", (int)*s, s+1); >+ } >+ DEBUG(D_tls) debug_printf("\n"); >+ if (server_seen_alpn > 1) >+ { >++ log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g)); >+ DEBUG(D_tls) debug_printf("TLS: too many ALPNs presented in handshake\n"); >+ return GNUTLS_E_NO_APPLICATION_PROTOCOL; >+ } >+ break; >++ } >+ #endif >+ } >+ return 0; >+diff --git a/src/tls-openssl.c b/src/tls-openssl.c >+index e063d29bd..513ba0d3a 100644 >+--- a/src/tls-openssl.c >++++ b/src/tls-openssl.c >+@@ -2324,6 +2324,8 @@ static int >+ tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen, >+ const uschar * in, unsigned int inlen, void * arg) >+ { >++gstring * g = NULL; >++ >+ server_seen_alpn = TRUE; >+ DEBUG(D_tls) >+ { >+@@ -2354,12 +2356,19 @@ if ( inlen > 1 /* at least one name */ >+ } >+ } >+ >+-/* More than one name from clilent, or name did not match our list. */ >++/* More than one name from client, or name did not match our list. */ >+ >+ /* This will be fatal to the TLS conn; would be nice to kill TCP also. >+ Maybe as an option in future; for now leave control to the config (must-tls). */ >+ >+-DEBUG(D_tls) debug_printf("TLS ALPN rejected\n"); >++for (int pos = 0, siz; pos < inlen; pos += siz+1) >++ { >++ siz = in[pos]; >++ if (pos + 1 + siz > inlen) siz = inlen - pos - 1; >++ g = string_append_listele_n(g, ':', in + pos + 1, siz); >++ } >++log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g)); >++gstring_release_unused(g); >+ return SSL_TLSEXT_ERR_ALERT_FATAL; >+ } >+ #endif /* EXIM_HAVE_ALPN */ >+-- >+2.39.0 >+ >diff --git a/mail/exim/files/debian/75_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch b/mail/exim/files/debian/75_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch >new file mode 100644 >index 000000000000..417ffa4eed8c >--- /dev/null >+++ b/mail/exim/files/debian/75_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch >@@ -0,0 +1,96 @@ >+From 30520c8f87fcf660ed99a2344cae7f9787f7bc89 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Thu, 5 Jan 2023 18:39:51 +0000 >+Subject: [PATCH 3/3] DANE: do not check dns_again_means_nonexist for TLSA >+ results of TRY_AGAIN >+ >+--- >+ doc/doc-docbook/spec.xfpt | 7 ++++++- >+ doc/ChangeLog | 4 ++++ >+ src/dns.c | 35 ++++++++++++++++++++++------------- >+ 3 files changed, 32 insertions(+), 14 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -46,10 +46,14 @@ JH/19 Bug 2911: Fix a recursion in DNS l >+ JH/20 Bug 2954: (OpenSSL) Fix setting of explicit EC curve/group. Previously >+ this always failed, probably leading to the usual downgrade to in-clear >+ connections. >+ >+ >++JH/20 Fix TLSA lookups. Previously dns_again_means_nonexist would affect >++ SERVFAIL results, which breaks the downgrade resistance of DANE. Change >++ to not checking that list for these looks. >++ >+ >+ Exim version 4.96 >+ ----------------- >+ >+ JH/01 Move the wait-for-next-tick (needed for unique message IDs) from >+--- a/src/dns.c >++++ b/src/dns.c >+@@ -904,25 +904,34 @@ if (dnsa->answerlen < 0) switch (h_errno >+ DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n", >+ name, dns_text_type(type)); >+ >+ /* Cut this out for various test programs */ >+ #ifndef STAND_ALONE >+- if (try_again_recursion) >++ /* Permitting dns_again_means nonexist for TLSA lookups breaks the >++ doewngrade resistance of dane, so avoid for those. */ >++ >++ if (type == T_TLSA) >++ rc = FAIL; >++ else >+ { >+- log_write(0, LOG_MAIN|LOG_PANIC, >+- "dns_again_means_nonexist recursion seen for %s (assuming nonexist)", >+- name); >+- return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH); >+- } >++ if (try_again_recursion) >++ { >++ log_write(0, LOG_MAIN|LOG_PANIC, >++ "dns_again_means_nonexist recursion seen for %s" >++ " (assuming nonexist)", name); >++ return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), >++ DNS_NOMATCH); >++ } >+ >+- try_again_recursion = TRUE; >+- save_domain = deliver_domain; >+- deliver_domain = string_copy(name); /* set $domain */ >+- rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0, >+- &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); >+- deliver_domain = save_domain; >+- try_again_recursion = FALSE; >++ try_again_recursion = TRUE; >++ save_domain = deliver_domain; >++ deliver_domain = string_copy(name); /* set $domain */ >++ rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0, >++ &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); >++ deliver_domain = save_domain; >++ try_again_recursion = FALSE; >++ } >+ >+ if (rc != OK) >+ { >+ DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n"); >+ return dns_fail_return(name, type, 0, DNS_AGAIN); >+--- a/doc/spec.txt >++++ b/doc/spec.txt >+@@ -14246,11 +14246,13 @@ dns_again_means_nonexist, it is treated >+ should be used with care. You can make it apply to reverse lookups by a setting >+ such as this: >+ >+ dns_again_means_nonexist = *.in-addr.arpa >+ >+-This option applies to all DNS lookups that Exim does. It also applies when the >++This option applies to all DNS lookups that Exim does, except for TLSA lookups >++(where knowing about such failures +is security-relevant). It also applies >++when the >+ gethostbyname() or getipnodebyname() functions give temporary errors, since >+ these are most likely to be caused by DNS lookup problems. The dnslookup router >+ has some options of its own for controlling what happens when lookups for MX or >+ SRV records give temporary errors. These more specific options are applied >+ after this global option. >diff --git a/mail/exim/files/debian/75_66-Fix-crash-in-expansions.patch b/mail/exim/files/debian/75_66-Fix-crash-in-expansions.patch >new file mode 100644 >index 000000000000..d776c8edf393 >--- /dev/null >+++ b/mail/exim/files/debian/75_66-Fix-crash-in-expansions.patch >@@ -0,0 +1,84 @@ >+From 70069b65a39a7ba73a36fbd95371ff03cde1eb23 Mon Sep 17 00:00:00 2001 >+From: Jeremy Harris <jgh146exb@wizmail.org> >+Date: Thu, 2 Feb 2023 20:00:35 +0000 >+Subject: [PATCH] Fix crash in expansions >+ >+Broken-by: 1058096b8c53 >+--- >+ doc/ChangeLog | 4 ++++ >+ src/expand.c | 9 +++++---- >+ test/stderr/0630 | 1 + >+ 3 files changed, 10 insertions(+), 4 deletions(-) >+ >+--- a/doc/ChangeLog >++++ b/doc/ChangeLog >+@@ -50,10 +50,14 @@ JH/20 Bug 2954: (OpenSSL) Fix setting of >+ >+ JH/20 Fix TLSA lookups. Previously dns_again_means_nonexist would affect >+ SERVFAIL results, which breaks the downgrade resistance of DANE. Change >+ to not checking that list for these looks. >+ >++JH/23 Fix crash in string expansions. Previously, if an empty variable was >++ immediately followed by an expansion operator, a null-indirection read >++ was done, killing the process. >++ >+ >+ Exim version 4.96 >+ ----------------- >+ >+ JH/01 Move the wait-for-next-tick (needed for unique message IDs) from >+--- a/src/expand.c >++++ b/src/expand.c >+@@ -4652,11 +4652,11 @@ while (*s) >+ yield = string_catn(yield, value, len); >+ >+ continue; >+ } >+ >+- if (isdigit(*s)) >++ if (isdigit(*s)) /* A $<n> variable */ >+ { >+ int n; >+ s = read_cnumber(&n, s); >+ if (n >= 0 && n <= expand_nmax) >+ yield = string_catn(yield, expand_nstring[n], expand_nlength[n]); >+@@ -7060,10 +7060,11 @@ NOT_ITEM: ; >+ if (arg) *arg++ = '_'; /* Put back for error messages */ >+ } >+ >+ /* Deal specially with operators that might take a certificate variable >+ as we do not want to do the usual expansion. For most, expand the string.*/ >++ >+ switch(c) >+ { >+ #ifndef DISABLE_TLS >+ case EOP_MD5: >+ case EOP_SHA1: >+@@ -7107,11 +7108,11 @@ NOT_ITEM: ; >+ >+ /* Otherwise, switch on the operator type. After handling go back >+ to the main loop top. */ >+ >+ { >+- int start = yield->ptr; >++ unsigned expansion_start = gstring_length(yield); >+ switch(c) >+ { >+ case EOP_BASE32: >+ { >+ uschar *t; >+@@ -8168,12 +8169,12 @@ NOT_ITEM: ; >+ goto EXPAND_FAILED; >+ } /* EOP_* switch */ >+ >+ DEBUG(D_expand) >+ { >+- const uschar * s = yield->s + start; >+- int i = yield->ptr - start; >++ const uschar * s = yield->s + expansion_start; >++ int i = gstring_length(yield) - expansion_start; >+ BOOL tainted = is_tainted(s); >+ >+ DEBUG(D_noutf8) >+ { >+ debug_printf_indent("|-----op-res: %.*s\n", i, s); >diff --git a/mail/exim/files/patch-OS__Makefile-Default b/mail/exim/files/patch-OS__Makefile-Default >deleted file mode 100644 >index 1e639c95419a..000000000000 >--- a/mail/exim/files/patch-OS__Makefile-Default >+++ /dev/null >@@ -1,10 +0,0 @@ >---- OS/Makefile-Default.orig 2019-01-30 14:59:52.000000000 +0100 >-+++ OS/Makefile-Default 2019-02-13 00:34:40.753182000 +0100 >-@@ -242,6 +242,7 @@ >- # The default setting points to a template function that doesn't actually do >- # any scanning, but just accepts the message. >- >-+# HAVE_LOCAL_SCAN=no >- LOCAL_SCAN_SOURCE=src/local_scan.c >- >- # If you want to specify options for your local_scan() that can be set from >diff --git a/mail/exim/files/patch-OS__Makefile-FreeBSD b/mail/exim/files/patch-OS__Makefile-FreeBSD >index 239f5bca9637..a2608a0dcf32 100644 >--- a/mail/exim/files/patch-OS__Makefile-FreeBSD >+++ b/mail/exim/files/patch-OS__Makefile-FreeBSD >@@ -1,11 +1,13 @@ >---- OS/Makefile-FreeBSD.orig 2009-11-14 21:13:45.000000000 +0300 >-+++ OS/Makefile-FreeBSD 2009-11-14 21:15:39.000000000 +0300 >-@@ -7,7 +7,7 @@ >- PORTOBJFORMAT!= test -x /usr/bin/objformat && /usr/bin/objformat || echo aout >+--- OS/Makefile-FreeBSD.orig 2023-04-09 09:45:04.226201000 +0200 >++++ OS/Makefile-FreeBSD 2023-04-09 09:48:01.819463000 +0200 >+@@ -18,8 +18,8 @@ >+ # Dynamically loaded modules need to be built with -fPIC >+ CFLAGS_DYNAMIC=-shared -rdynamic -fPIC > >- CHOWN_COMMAND=/usr/sbin/chown >--STRIP_COMMAND=/usr/bin/strip >-+STRIP_COMMAND=XX_STRIPCMD_XX >- CHMOD_COMMAND=/bin/chmod >+-# FreeBSD always ships with Berkeley DB >+-USE_DB=yes >++# FreeBSD ships with Berkeley DB until 13.1, but ndbm is always included >++USE_NDBM=yes > >- HAVE_SA_LEN=YES >+ # This code for building outside ports suggested by Richard Clayton >+ .ifdef X11BASE >diff --git a/mail/exim/files/patch-OS_os.c-FreeBSD b/mail/exim/files/patch-OS_os.c-FreeBSD >deleted file mode 100644 >index 99e89850ed0c..000000000000 >--- a/mail/exim/files/patch-OS_os.c-FreeBSD >+++ /dev/null >@@ -1,15 +0,0 @@ >---- 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-src-dmarc.c b/mail/exim/files/patch-src-dmarc.c >deleted file mode 100644 >index c0054446458c..000000000000 >--- a/mail/exim/files/patch-src-dmarc.c >+++ /dev/null >@@ -1,19 +0,0 @@ >---- src/dmarc.c.orig 2021-04-30 12:08:21 UTC >-+++ src/dmarc.c >-@@ -37,6 +37,7 @@ uschar *spf_human_readable = NULL; >- u_char *header_from_sender = NULL; >- int history_file_status = DMARC_HIST_OK; >- uschar *dkim_history_buffer= NULL; >-+uschar *dkim_selector = NULL; >- >- typedef struct dmarc_exim_p { >- uschar *name; >-@@ -446,7 +447,7 @@ if (!dmarc_abort && !sender_host_authenticated) >- vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL : >- DMARC_POLICY_DKIM_OUTCOME_NONE; >- libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain, >-- dkim_result, US""); >-+ dkim_selector, dkim_result, US""); >- DEBUG(D_receive) >- debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain); >- if (libdm_status != DMARC_PARSE_OKAY) >diff --git a/mail/exim/files/tls/patch-tls1 b/mail/exim/files/tls/patch-tls1 >deleted file mode 100644 >index d76d5589b2bb..000000000000 >--- a/mail/exim/files/tls/patch-tls1 >+++ /dev/null >@@ -1,43 +0,0 @@ >-From fc624b8cb4c3312d7450dfa86adfa3fe8dd9cbeb Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Tue, 11 Jan 2022 14:50:09 +0000 >-Subject: [PATCH] Ensure server tls close alert not delayed >- >---- >- src/src/tls-gnu.c | 5 +++++ >- src/src/tls-openssl.c | 3 +++ >- 2 files changed, 8 insertions(+) >- >-diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c >-index 53635ac..3adadb8 100644 >---- a/src/tls-gnu.c >-+++ b/src/tls-gnu.c >-@@ -3731,6 +3731,11 @@ if (do_shutdown) >- >- tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ >- >-+#ifdef EXIM_TCP_CORK >-+ if (do_shutdown > 1) >-+ (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off)); >-+#endif >-+ >- ALARM(2); >- gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); >- ALARM_CLR(0); >-diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c >-index 5130455..576f62b 100644 >---- a/src/tls-openssl.c >-+++ b/src/tls-openssl.c >-@@ -4516,6 +4516,9 @@ if (do_shutdown) >- if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ >- && do_shutdown > 1) >- { >-+#ifdef EXIM_TCP_CORK >-+ (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off)); >-+#endif >- ALARM(2); >- rc = SSL_shutdown(*sslp); /* wait for response */ >- ALARM_CLR(0); >--- >-1.9.1 >- >diff --git a/mail/exim/files/tls/patch-tls2 b/mail/exim/files/tls/patch-tls2 >deleted file mode 100644 >index e88c127fd374..000000000000 >--- a/mail/exim/files/tls/patch-tls2 >+++ /dev/null >@@ -1,174 +0,0 @@ >-From 2ead369f8435918f3f15408b9394e580bcaf0910 Mon Sep 17 00:00:00 2001 >-From: Jeremy Harris <jgh146exb@wizmail.org> >-Date: Thu, 10 Mar 2022 15:23:26 +0000 >-Subject: [PATCH] OpenSSL: track shutdown calls. Bug 2864 >- >---- >- doc/doc-txt/ChangeLog | 5 +++++ >- src/src/macros.h | 7 ++++--- >- src/src/tls-gnu.c | 10 +++++++--- >- src/src/tls-openssl.c | 13 ++++++++----- >- src/src/transports/smtp.c | 19 +++++++++++++------ >- 5 files changed, 37 insertions(+), 17 deletions(-) >- >-diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog >-index 5ba587b..1c799b6 100644 >---- a/doc/ChangeLog >-+++ b/doc/ChangeLog >-@@ -95,6 +95,11 @@ JH/21 Remove the "allow_insecure_tainted_data" main config option and the >- JH/22 Fix static address-list lookups to properly return the matched item. >- Previously only the domain part was returned. >- >-+JH/23 Bug 2864: FreeBSD: fix transport hang after 4xx/5xx response. Previously >-+ the call into OpenSSL to send a TLS Close was being repeated; this >-+ resulted in the library waiting for the peer's Close. If that was never >-+ sent we waited forever. Fix by tracking send calls. >-+ >- >- Exim version 4.95 >- ----------------- >-diff --git a/src/src/macros.h b/src/src/macros.h >-index 92f2cc0..659a70f 100644 >---- a/src/macros.h >-+++ b/src/macros.h >-@@ -1051,9 +1051,10 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE }; >- >- >- /* Options on tls_close */ >--#define TLS_NO_SHUTDOWN 0 >--#define TLS_SHUTDOWN_NOWAIT 1 >--#define TLS_SHUTDOWN_WAIT 2 >-+#define TLS_NO_SHUTDOWN 0 /* Just forget the context */ >-+#define TLS_SHUTDOWN_NOWAIT 1 /* Send alert; do not wait */ >-+#define TLS_SHUTDOWN_WAIT 2 /* Send alert & wait for peer's alert */ >-+#define TLS_SHUTDOWN_WONLY 3 /* only wait for peer's alert */ >- >- >- #ifdef COMPILE_UTILITY >-diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c >-index 1215f85..6227823 100644 >---- a/src/tls-gnu.c >-+++ b/src/tls-gnu.c >-@@ -3744,17 +3744,21 @@ if (!tlsp || tlsp->active.sock < 0) return; /* TLS was not active */ >- if (do_shutdown) >- { >- DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", >-- do_shutdown > 1 ? " (with response-wait)" : ""); >-+ do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : ""); >- >- tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ >- >- #ifdef EXIM_TCP_CORK >-- if (do_shutdown > 1) >-+ if (do_shutdown == TLS_SHUTDOWN_WAIT) >- (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off)); >- #endif >- >-+ /* The library seems to have no way to only wait for a peer's >-+ shutdown, so handle the same as TLS_SHUTDOWN_WAIT */ >-+ >- ALARM(2); >-- gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); >-+ gnutls_bye(state->session, >-+ do_shutdown > TLS_SHUTDOWN_NOWAIT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR); >- ALARM_CLR(0); >- } >- >-diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c >-index d5c5778..7bf62f5 100644 >---- a/src/tls-openssl.c >-+++ b/src/tls-openssl.c >-@@ -4519,22 +4519,25 @@ int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock; >- >- if (*fdp < 0) return; /* TLS was not active */ >- >--if (do_shutdown) >-+if (do_shutdown > TLS_NO_SHUTDOWN) >- { >- int rc; >- DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n", >-- do_shutdown > 1 ? " (with response-wait)" : ""); >-+ do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : ""); >- >- tls_write(ct_ctx, NULL, 0, FALSE); /* flush write buffer */ >- >-- if ( (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ >-- && do_shutdown > 1) >-+ if ( ( do_shutdown >= TLS_SHUTDOWN_WONLY >-+ || (rc = SSL_shutdown(*sslp)) == 0 /* send "close notify" alert */ >-+ ) >-+ && do_shutdown > TLS_SHUTDOWN_NOWAIT >-+ ) >- { >- #ifdef EXIM_TCP_CORK >- (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off)); >- #endif >- ALARM(2); >-- rc = SSL_shutdown(*sslp); /* wait for response */ >-+ rc = SSL_shutdown(*sslp); /* wait for response */ >- ALARM_CLR(0); >- } >- >-diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c >-index e2c2680..524f186 100644 >---- a/src/transports/smtp.c >-+++ b/src/transports/smtp.c >-@@ -4085,7 +4085,7 @@ else >- sx->send_quit = FALSE; /* avoid sending it later */ >- >- #ifndef DISABLE_TLS >-- if (sx->cctx.tls_ctx) /* need to send TLS Close Notify */ >-+ if (sx->cctx.tls_ctx && sx->send_tlsclose) /* need to send TLS Close Notify */ >- { >- # ifdef EXIM_TCP_CORK /* Use _CORK to get Close Notify in FIN segment */ >- (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); >-@@ -4429,7 +4429,8 @@ if (!sx->ok) >- # ifndef DISABLE_TLS >- if (sx->cctx.tls_ctx) >- { >-- tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT); >-+ tls_close(sx->cctx.tls_ctx, >-+ sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY); >- sx->cctx.tls_ctx = NULL; >- } >- # endif >-@@ -4640,7 +4641,8 @@ if (sx->completed_addr && sx->ok && sx->send_quit) >- a new EHLO. If we don't get a good response, we don't attempt to pass >- the socket on. */ >- >-- tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT); >-+ tls_close(sx->cctx.tls_ctx, >-+ sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY); >- sx->send_tlsclose = FALSE; >- sx->cctx.tls_ctx = NULL; >- tls_out.active.sock = -1; >-@@ -4742,7 +4744,7 @@ if (sx->send_quit) >- { /* Use _MORE to get QUIT in FIN segment */ >- (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n"); >- #ifndef DISABLE_TLS >-- if (sx->cctx.tls_ctx) >-+ if (sx->cctx.tls_ctx && sx->send_tlsclose) >- { >- # ifdef EXIM_TCP_CORK /* Use _CORK to get TLS Close Notify in FIN segment */ >- (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); >-@@ -4797,10 +4799,15 @@ if (sx->send_quit || tcw_done && !tcw) >- while (!sigalrm_seen && n > 0); >- ALARM_CLR(0); >- >-+ if (sx->send_tlsclose) >-+ { >- # ifdef EXIM_TCP_CORK >-- (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); >-+ (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on)); >- # endif >-- tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT); >-+ tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT); >-+ } >-+ else >-+ tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WONLY); >- sx->cctx.tls_ctx = NULL; >- } >- #endif >--- >-1.9.1 >-
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 265098
:
241365
|
241368
| 241399