1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-10-18 19:49:40 +00:00

mail/exim: fix update to 4.96 by adding missing patches

PR:		265098
Reported by:	David Siebuerger <drs-freebsd@sieborger.nom.za>
This commit is contained in:
Kurt Jaeger 2023-05-26 20:33:29 +02:00
parent fe2317c01a
commit 0034826752
24 changed files with 2250 additions and 0 deletions

View File

@ -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,

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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;

View File

@ -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",

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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);
}

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);