View | Details | Raw Unified | Return to bug 265098 | Differences between
and this patch

Collapse All | Expand All

(-)b/UPDATING (+9 lines)
Lines 5-10 they are unavoidable. Link Here
5
You should get into the habit of checking this file for changes each time
5
You should get into the habit of checking this file for changes each time
6
you update your ports collection, before attempting any port upgrades.
6
you update your ports collection, before attempting any port upgrades.
7
7
8
2023xxxx:
9
  AFFECTS: users of mail/exim
10
  AUTHOR: pi@FreeBSD.org
11
12
  The port changes from USE_DB to USE_NDBM. Any existing configuration like
13
  ${lookup{$needle}dbm{haystack.db}}
14
  will need to change to
15
  ${lookup{$needle}dbm{haystack}}.
16
8
20230407:
17
20230407:
9
  AFFECTS: users of devel/sonarqube-community
18
  AFFECTS: users of devel/sonarqube-community
10
  AUTHOR: netchild@FreeBSD.org
19
  AUTHOR: netchild@FreeBSD.org
(-)b/mail/exim/Makefile (-19 / +27 lines)
Lines 1-6 Link Here
1
PORTNAME=	exim
1
PORTNAME=	exim
2
PORTVERSION?=	${EXIM_VERSION}
2
PORTVERSION?=	${EXIM_VERSION}
3
PORTREVISION?=	6
3
PORTREVISION?=	0
4
CATEGORIES=	mail
4
CATEGORIES=	mail
5
MASTER_SITES=	EXIM:exim
5
MASTER_SITES=	EXIM:exim
6
MASTER_SITE_SUBDIR=	/exim4/:exim \
6
MASTER_SITE_SUBDIR=	/exim4/:exim \
Lines 66-85 SQLITE_USES= pkgconfig sqlite Link Here
66
66
67
DEBIAN_PATCHES_PREFIX=	${FILESDIR}/debian/75
67
DEBIAN_PATCHES_PREFIX=	${FILESDIR}/debian/75
68
EXTRA_PATCHES= \
68
EXTRA_PATCHES= \
69
		${DEBIAN_PATCHES_PREFIX}_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch:-p1 \
69
		${DEBIAN_PATCHES_PREFIX}_01-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch:-p1 \
70
		${DEBIAN_PATCHES_PREFIX}_32-Fix-PAM-auth.-Bug-2813.patch:-p1 \
70
		${DEBIAN_PATCHES_PREFIX}_05-SPF-fix-memory-accounting-for-error-case.patch:-p1 \
71
		${DEBIAN_PATCHES_PREFIX}_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch:-p1 \
71
		${DEBIAN_PATCHES_PREFIX}_08-Fix-regex-n-use-after-free.-Bug-2915.patch:-p1 \
72
		${DEBIAN_PATCHES_PREFIX}_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch:-p1 \
72
		${DEBIAN_PATCHES_PREFIX}_09-Fix-non-WITH_CONTENT_SCAN-build.patch:-p1 \
73
		${DEBIAN_PATCHES_PREFIX}_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch:-p1 \
73
		${DEBIAN_PATCHES_PREFIX}_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch:-p1 \
74
		${DEBIAN_PATCHES_PREFIX}_43-BSD-fix-resource-leak.patch:-p1 \
74
		${DEBIAN_PATCHES_PREFIX}_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch:-p1 \
75
		${DEBIAN_PATCHES_PREFIX}_45-Fix-bogus-error-message-copy.-Bug-2857.patch:-p1 \
75
		${DEBIAN_PATCHES_PREFIX}_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch:-p1 \
76
		${DEBIAN_PATCHES_PREFIX}_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch:-p1 \
76
		${DEBIAN_PATCHES_PREFIX}_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch:-p1 \
77
		${DEBIAN_PATCHES_PREFIX}_55-Specific-check-for-null-pointer.patch:-p1
77
		${DEBIAN_PATCHES_PREFIX}_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch:-p1 \
78
78
		${DEBIAN_PATCHES_PREFIX}_22-Fix-daemon-startup.-Bug-2930.patch:-p1 \
79
TLS_PATCHES_PREFIX=	${FILESDIR}/tls/
79
		${DEBIAN_PATCHES_PREFIX}_23-Fix-reccipients-after-run.-.-Bug-2929.patch:-p1 \
80
EXTRA_PATCHES+= \
80
		${DEBIAN_PATCHES_PREFIX}_31-Fix-regext-substring-capture-variables-for-null-matc.patch:-p1 \
81
		${TLS_PATCHES_PREFIX}patch-tls1:-p1 \
81
		${DEBIAN_PATCHES_PREFIX}_32-Fix-regex-substring-capture-variables-for-null-match.patch:-p1 \
82
		${TLS_PATCHES_PREFIX}patch-tls2:-p1
82
		${DEBIAN_PATCHES_PREFIX}_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch:-p1 \
83
		${DEBIAN_PATCHES_PREFIX}_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch:-p1 \
84
		${DEBIAN_PATCHES_PREFIX}_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch:-p1 \
85
		${DEBIAN_PATCHES_PREFIX}_50-Fix-logging-of-max-size-log-line.patch:-p1 \
86
		${DEBIAN_PATCHES_PREFIX}_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch:-p1 \
87
		${DEBIAN_PATCHES_PREFIX}_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch:-p1 \
88
		${DEBIAN_PATCHES_PREFIX}_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch:-p1 \
89
		${DEBIAN_PATCHES_PREFIX}_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch:-p1 \
90
		${DEBIAN_PATCHES_PREFIX}_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch:-p1 \
91
		${DEBIAN_PATCHES_PREFIX}_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch:-p1 \
92
		${DEBIAN_PATCHES_PREFIX}_66-Fix-crash-in-expansions.patch:-p1
83
93
84
.include <bsd.port.options.mk>
94
.include <bsd.port.options.mk>
85
95
Lines 120-126 EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.c Link Here
120
EXTRA_PATCHES+=	${FILESDIR}/extra-patch-Local-sa-exim.conf
130
EXTRA_PATCHES+=	${FILESDIR}/extra-patch-Local-sa-exim.conf
121
.endif
131
.endif
122
132
123
EXIM_VERSION=	4.95
133
EXIM_VERSION=	4.96
124
SA_EXIM_VERSION=4.2.1
134
SA_EXIM_VERSION=4.2.1
125
EXIM_INSTALL_ARG+=	"-no_chown" "-no_symlink"
135
EXIM_INSTALL_ARG+=	"-no_chown" "-no_symlink"
126
EXTRA_PATCHES+=	`${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`
136
EXTRA_PATCHES+=	`${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`
Lines 210-216 WITH_DEFAULT_CHARSET?= ISO-8859-1 Link Here
210
220
211
# You should not need to fiddle with anything below this point.
221
# You should not need to fiddle with anything below this point.
212
222
213
LIB_DEPENDS+=	libpcre.so:devel/pcre
223
LIB_DEPENDS+=	libpcre2-posix.so:devel/pcre2
214
224
215
.if ! ${PORT_OPTIONS:MDKIM}
225
.if ! ${PORT_OPTIONS:MDKIM}
216
SEDLIST+=	-e 's,^\# (DISABLE_DKIM=),\1,'
226
SEDLIST+=	-e 's,^\# (DISABLE_DKIM=),\1,'
Lines 599-606 do-configure: Link Here
599
	@${REINPLACE_CMD} -e 's,/usr/bin/spamc,${LOCALBASE}/bin/spamc,' \
609
	@${REINPLACE_CMD} -e 's,/usr/bin/spamc,${LOCALBASE}/bin/spamc,' \
600
	    ${WRKSRC}/Local/sa-exim.conf
610
	    ${WRKSRC}/Local/sa-exim.conf
601
.endif
611
.endif
602
	@${REINPLACE_CMD} -E -e 's/XX_STRIPCMD_XX/${STRIP_CMD:S,/,\/,g}/' \
603
		${WRKSRC}/OS/Makefile-FreeBSD
604
	@(cd ${WRKSRC}; ${SETENV} ${MAKE_ENV} ${MAKE} ${MAKE_FLAGS} ${MAKEFILE} ${MAKE_ARGS} configure)
612
	@(cd ${WRKSRC}; ${SETENV} ${MAKE_ENV} ${MAKE} ${MAKE_FLAGS} ${MAKEFILE} ${MAKE_ARGS} configure)
605
613
606
post-build:
614
post-build:
(-)b/mail/exim/distinfo (-3 / +3 lines)
Lines 1-5 Link Here
1
TIMESTAMP = 1632918983
1
TIMESTAMP = 1681024359
2
SHA256 (exim/exim-4.95.tar.bz2) = 7f4716cc1b3fee66930d83b249f1c7b119fa1957f6f46e3f4372805cbc97ea63
2
SHA256 (exim/exim-4.96.tar.bz2) = c7a413fec601cc44a8f5fe9e5b64cb24a7d133f3a4a976f33741d98ff0ec6b91
3
SIZE (exim/exim-4.95.tar.bz2) = 2035738
3
SIZE (exim/exim-4.96.tar.bz2) = 2047632
4
SHA256 (exim/sa-exim-4.2.1.tar.gz) = 24d4bf7b0fdddaea11f132981cebb6a86a4ab20ef54111a8ebd481b421c6e2c1
4
SHA256 (exim/sa-exim-4.2.1.tar.gz) = 24d4bf7b0fdddaea11f132981cebb6a86a4ab20ef54111a8ebd481b421c6e2c1
5
SIZE (exim/sa-exim-4.2.1.tar.gz) = 68933
5
SIZE (exim/sa-exim-4.2.1.tar.gz) = 68933
(-)b/mail/exim/files/debian/75_01-Fix-exit-on-attempt-to-rewrite-a-malformed-address.-.patch (+57 lines)
Added Link Here
1
From e7ec503729970a03d4509921342bc81313976126 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Tue, 12 Jul 2022 22:14:04 +0100
4
Subject: [PATCH] Fix exit on attempt to rewrite a malformed address.  Bug 2903
5
6
---
7
 doc/ChangeLog        |   5 +
8
 src/rewrite.c            |   9 +-
9
 test/confs/0471              |   7 +
10
 test/log/0471                |   5 +
11
 test/scripts/0000-Basic/0471 |   4 +-
12
 test/stderr/0471             | 245 ++++++++++++++++++++++++++++++++++-
13
 6 files changed, 267 insertions(+), 8 deletions(-)
14
15
--- a/doc/ChangeLog
16
+++ b/doc/ChangeLog
17
@@ -1,9 +1,14 @@
18
 This document describes *changes* to previous versions, that might
19
 affect Exim's operation, with an unchanged configuration file.  For new
20
 options, and new features, see the NewStuff file next to this ChangeLog.
21
 
22
+JH/04 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
23
+      Make the rewrite never match and keep the logging.  Trust the
24
+      admin to be using verify=header-syntax (to actually reject the message).
25
+
26
+
27
 Exim version 4.96
28
 -----------------
29
 
30
 JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from
31
       after reception to before a subsequent reception.  This should
32
--- a/src/rewrite.c
33
+++ b/src/rewrite.c
34
@@ -493,19 +493,18 @@
35
   empty address, overlong addres. Sometimes the result matters, sometimes not.
36
   It seems this function is called for *any* header we see. */
37
 
38
   if (!recipient)
39
     {
40
-    /* Handle unparesable addresses in the header. Slightly ugly because a
41
+    /* Log unparesable addresses in the header. Slightly ugly because a
42
     null output from the extract can also result from a header without an
43
-    address, "To: undisclosed recpients:;" being the classic case. */
44
+    address, "To: undisclosed recpients:;" being the classic case. Ignore
45
+    this one and carry on. */
46
 
47
     if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0)
48
-      {
49
       log_write(0, LOG_MAIN, "rewrite: %s", errmess);
50
-      exim_exit(EXIT_FAILURE);
51
-      }
52
+
53
     loop_reset_point = store_reset(loop_reset_point);
54
     continue;
55
     }
56
 
57
   /* If routed_old is not NULL, this is a rewrite caused by a router,
(-)b/mail/exim/files/debian/75_05-SPF-fix-memory-accounting-for-error-case.patch (+25 lines)
Added Link Here
1
From 93c722ce0549360af68269f088f4e59ed8fc130e Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sun, 7 Aug 2022 17:00:27 +0100
4
Subject: [PATCH] SPF: fix memory accounting for error case
5
6
---
7
 src/spf.c | 2 +-
8
 1 file changed, 1 insertion(+), 1 deletion(-)
9
10
diff --git a/src/spf.c b/src/spf.c
11
index db6eea3a8..a8c0f75c4 100644
12
--- a/src/spf.c
13
+++ b/src/spf.c
14
@@ -204,7 +204,7 @@ spf_nxdomain = SPF_dns_rr_new_init(spf_dns_server,
15
   "", ns_t_any, 24 * 60 * 60, HOST_NOT_FOUND);
16
 if (!spf_nxdomain)
17
   {
18
-  free(spf_dns_server);
19
+  store_free(spf_dns_server);
20
   return NULL;
21
   }
22
 
23
-- 
24
2.35.1
25
(-)b/mail/exim/files/debian/75_08-Fix-regex-n-use-after-free.-Bug-2915.patch (+193 lines)
Added Link Here
1
From 4e9ed49f8f12eb331b29bd5b6dc3693c520fddc2 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Wed, 31 Aug 2022 15:37:40 +0100
4
Subject: [PATCH] Fix $regex<n> use-after-free.  Bug 2915
5
6
---
7
 doc/ChangeLog           |  8 +++++++-
8
 src/exim.c                  |  4 +---
9
 src/expand.c                |  2 +-
10
 src/functions.h             |  1 +
11
 src/globals.c               |  2 +-
12
 src/regex.c                 | 29 ++++++++++++++++++-----------
13
 src/smtp_in.c               |  2 ++
14
 7 files changed, 55 insertions(+), 17 deletions(-)
15
16
--- a/doc/ChangeLog
17
+++ b/doc/ChangeLog
18
@@ -4,15 +4,21 @@
19
 
20
 JH/04 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
21
       Make the rewrite never match and keep the logging.  Trust the
22
       admin to be using verify=header-syntax (to actually reject the message).
23
 
24
+JH/08 Bug 2915: Fix use-after-free for $regex<n> variables. Previously when
25
+      more than one message arrived in a single connection a reference from
26
+      the earlier message could be re-used.  Often a sigsegv resulted.
27
+      These variables were introduced in Exim 4.87.
28
+      Debug help from Graeme Fowler.
29
+
30
 
31
 Exim version 4.96
32
 -----------------
33
 
34
-JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from
35
+JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
36
       after reception to before a subsequent reception.  This should
37
       mean slightly faster delivery, and also confirmation of reception
38
       to senders.
39
 
40
 JH/02 Move from using the pcre library to pcre2.  The former is no longer
41
--- a/src/exim.c
42
+++ b/src/exim.c
43
@@ -1999,12 +1999,10 @@
44
 
45
 regex_whitelisted_macro =
46
   regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
47
 #endif
48
 
49
-for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
50
-
51
 /* If the program is called as "mailq" treat it as equivalent to "exim -bp";
52
 this seems to be a generally accepted convention, since one finds symbolic
53
 links called "mailq" in standard OS configurations. */
54
 
55
 if ((namelen == 5 && Ustrcmp(argv[0], "mailq") == 0) ||
56
@@ -6082,11 +6080,11 @@
57
   callout_address = NULL;
58
   sending_ip_address = NULL;
59
   deliver_localpart_data = deliver_domain_data =
60
   recipient_data = sender_data = NULL;
61
   acl_var_m = NULL;
62
-  for(int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
63
+  regex_vars_clear();
64
 
65
   store_reset(reset_point);
66
   }
67
 
68
 exim_exit(EXIT_SUCCESS);   /* Never returns */
69
--- a/src/expand.c
70
+++ b/src/expand.c
71
@@ -1871,11 +1871,11 @@
72
   {
73
   tree_node * node = tree_search(router_var, name + 2);
74
   return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
75
   }
76
 
77
-/* Handle $auth<n> variables. */
78
+/* Handle $auth<n>, $regex<n> variables. */
79
 
80
 if (Ustrncmp(name, "auth", 4) == 0)
81
   {
82
   uschar *endptr;
83
   int n = Ustrtoul(name + 4, &endptr, 10);
84
--- a/src/functions.h
85
+++ b/src/functions.h
86
@@ -436,10 +436,11 @@
87
 extern int     regex(const uschar **);
88
 #endif
89
 extern BOOL    regex_match(const pcre2_code *, const uschar *, int, uschar **);
90
 extern BOOL    regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
91
 extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
92
+extern void    regex_vars_clear(void);
93
 extern void    retry_add_item(address_item *, uschar *, int);
94
 extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
95
                  uschar **, uschar **);
96
 extern retry_config *retry_find_config(const uschar *, const uschar *, int, int);
97
 extern BOOL    retry_ultimate_address_timeout(uschar *, const uschar *,
98
--- a/src/globals.c
99
+++ b/src/globals.c
100
@@ -1313,11 +1313,11 @@
101
 #ifndef DISABLE_PIPE_CONNECT
102
 const pcre2_code *regex_EARLY_PIPE   = NULL;
103
 #endif
104
 const pcre2_code *regex_ismsgid      = NULL;
105
 const pcre2_code *regex_smtp_code    = NULL;
106
-const uschar *regex_vars[REGEX_VARS];
107
+const uschar *regex_vars[REGEX_VARS] = { 0 };;
108
 #ifdef WHITELIST_D_MACROS
109
 const pcre2_code *regex_whitelisted_macro = NULL;
110
 #endif
111
 #ifdef WITH_CONTENT_SCAN
112
 uschar *regex_match_string     = NULL;
113
--- a/src/regex.c
114
+++ b/src/regex.c
115
@@ -94,22 +94,32 @@
116
   }
117
 pcre2_match_data_free(md);
118
 return FAIL;
119
 }
120
 
121
+
122
+/* reset expansion variables */
123
+void
124
+regex_vars_clear(void)
125
+{
126
+regex_match_string = NULL;
127
+for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
128
+}
129
+
130
+
131
+
132
 int
133
-regex(const uschar **listptr)
134
+regex(const uschar ** listptr)
135
 {
136
 unsigned long mbox_size;
137
-FILE *mbox_file;
138
-pcre_list *re_list_head;
139
-uschar *linebuffer;
140
+FILE * mbox_file;
141
+pcre_list * re_list_head;
142
+uschar * linebuffer;
143
 long f_pos = 0;
144
 int ret = FAIL;
145
 
146
-/* reset expansion variable */
147
-regex_match_string = NULL;
148
+regex_vars_clear();
149
 
150
 if (!mime_stream)				/* We are in the DATA ACL */
151
   {
152
   if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
153
     {						/* error while spooling */
154
@@ -167,18 +177,17 @@
155
 
156
 
157
 int
158
 mime_regex(const uschar **listptr)
159
 {
160
-pcre_list *re_list_head = NULL;
161
-FILE *f;
162
-uschar *mime_subject = NULL;
163
+pcre_list * re_list_head = NULL;
164
+FILE * f;
165
+uschar * mime_subject = NULL;
166
 int mime_subject_len = 0;
167
 int ret;
168
 
169
-/* reset expansion variable */
170
-regex_match_string = NULL;
171
+regex_vars_clear();
172
 
173
 /* precompile our regexes */
174
 if (!(re_list_head = compile(*listptr)))
175
   return FAIL;			/* no regexes -> nothing to do */
176
 
177
--- a/src/smtp_in.c
178
+++ b/src/smtp_in.c
179
@@ -2155,12 +2155,14 @@
180
 prdr_requested = FALSE;
181
 #endif
182
 #ifdef SUPPORT_I18N
183
 message_smtputf8 = FALSE;
184
 #endif
185
+regex_vars_clear();
186
 body_linecount = body_zerocount = 0;
187
 
188
+lookup_value = NULL;				/* Can be set by ACL */
189
 sender_rate = sender_rate_limit = sender_rate_period = NULL;
190
 ratelimiters_mail = NULL;           /* Updated by ratelimit ACL condition */
191
                    /* Note that ratelimiters_conn persists across resets. */
192
 
193
 /* Reset message ACL variables */
(-)b/mail/exim/files/debian/75_09-Fix-non-WITH_CONTENT_SCAN-build.patch (+58 lines)
Added Link Here
1
From d8ecc7bf97934a1e2244788c610c958cacd740bd Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Wed, 31 Aug 2022 17:03:37 +0100
4
Subject: [PATCH 1/3] Fix non-WITH_CONTENT_SCAN build.
5
6
Broken-by: 4e9ed49f8f
7
---
8
 src/exim.c  | 11 +++++++++++
9
 src/regex.c | 10 ----------
10
 2 files changed, 11 insertions(+), 10 deletions(-)
11
12
--- a/src/exim.c
13
+++ b/src/exim.c
14
@@ -1677,10 +1677,21 @@
15
   if ((s = expand_string(big_buffer))) printf("%s\n", CS s);
16
   else printf("Failed: %s\n", expand_string_message);
17
 }
18
 
19
 
20
+/* reset regex expansion variables */
21
+void
22
+regex_vars_clear(void)
23
+{
24
+regex_match_string = NULL;
25
+for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
26
+}
27
+
28
+
29
+
30
+
31
 
32
 /*************************************************
33
 *          Entry point and high-level code       *
34
 *************************************************/
35
 
36
--- a/src/regex.c
37
+++ b/src/regex.c
38
@@ -95,20 +95,10 @@
39
 pcre2_match_data_free(md);
40
 return FAIL;
41
 }
42
 
43
 
44
-/* reset expansion variables */
45
-void
46
-regex_vars_clear(void)
47
-{
48
-regex_match_string = NULL;
49
-for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
50
-}
51
-
52
-
53
-
54
 int
55
 regex(const uschar ** listptr)
56
 {
57
 unsigned long mbox_size;
58
 FILE * mbox_file;
(-)b/mail/exim/files/debian/75_10-Fix-non-WITH_CONTENT_SCAN-build-2.patch (+135 lines)
Added Link Here
1
From 158dff9936e36a2d31d037d3988b9353458d6471 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Wed, 31 Aug 2022 17:17:59 +0100
4
Subject: [PATCH 2/3] Fix non-WITH_CONTENT_SCAN build (2)
5
6
Broken-by: d8ecc7bf97
7
---
8
 src/exim.c      | 13 +------------
9
 src/functions.h |  2 +-
10
 src/globals.h   |  2 +-
11
 src/regex.c     | 10 ++++++++++
12
 src/smtp_in.c   |  2 ++
13
 5 files changed, 15 insertions(+), 14 deletions(-)
14
15
--- a/src/exim.c
16
+++ b/src/exim.c
17
@@ -1677,21 +1677,10 @@
18
   if ((s = expand_string(big_buffer))) printf("%s\n", CS s);
19
   else printf("Failed: %s\n", expand_string_message);
20
 }
21
 
22
 
23
-/* reset regex expansion variables */
24
-void
25
-regex_vars_clear(void)
26
-{
27
-regex_match_string = NULL;
28
-for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
29
-}
30
-
31
-
32
-
33
-
34
 
35
 /*************************************************
36
 *          Entry point and high-level code       *
37
 *************************************************/
38
 
39
@@ -6085,17 +6074,17 @@
40
   deliver_domain_orig = NULL;
41
   deliver_host = deliver_host_address = NULL;
42
   dnslist_domain = dnslist_matched = NULL;
43
 #ifdef WITH_CONTENT_SCAN
44
   malware_name = NULL;
45
+  regex_vars_clear();
46
 #endif
47
   callout_address = NULL;
48
   sending_ip_address = NULL;
49
   deliver_localpart_data = deliver_domain_data =
50
   recipient_data = sender_data = NULL;
51
   acl_var_m = NULL;
52
-  regex_vars_clear();
53
 
54
   store_reset(reset_point);
55
   }
56
 
57
 exim_exit(EXIT_SUCCESS);   /* Never returns */
58
--- a/src/functions.h
59
+++ b/src/functions.h
60
@@ -432,15 +432,15 @@
61
 extern BOOL    receive_msg(BOOL);
62
 extern int_eximarith_t receive_statvfs(BOOL, int *);
63
 extern void    receive_swallow_smtp(void);
64
 #ifdef WITH_CONTENT_SCAN
65
 extern int     regex(const uschar **);
66
+extern void    regex_vars_clear(void);
67
 #endif
68
 extern BOOL    regex_match(const pcre2_code *, const uschar *, int, uschar **);
69
 extern BOOL    regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
70
 extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
71
-extern void    regex_vars_clear(void);
72
 extern void    retry_add_item(address_item *, uschar *, int);
73
 extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
74
                  uschar **, uschar **);
75
 extern retry_config *retry_find_config(const uschar *, const uschar *, int, int);
76
 extern BOOL    retry_ultimate_address_timeout(uschar *, const uschar *,
77
--- a/src/globals.h
78
+++ b/src/globals.h
79
@@ -895,16 +895,16 @@
80
 #ifndef DISABLE_PIPE_CONNECT
81
 extern const pcre2_code  *regex_EARLY_PIPE;  /* For recognizing PIPE_CONNCT */
82
 #endif
83
 extern const pcre2_code  *regex_ismsgid;     /* Compiled r.e. for message ID */
84
 extern const pcre2_code  *regex_smtp_code;   /* For recognizing SMTP codes */
85
-extern const uschar *regex_vars[];           /* $regexN variables */
86
 #ifdef WHITELIST_D_MACROS
87
 extern const pcre2_code  *regex_whitelisted_macro; /* For -D macro values */
88
 #endif
89
 #ifdef WITH_CONTENT_SCAN
90
 extern uschar *regex_match_string;     /* regex that matched a line (regex ACL condition) */
91
+extern const uschar *regex_vars[];
92
 #endif
93
 extern int     remote_delivery_count;  /* Number of remote addresses */
94
 extern int     remote_max_parallel;    /* Maximum parallel delivery */
95
 extern uschar *remote_sort_domains;    /* Remote domain sorting order */
96
 extern retry_config *retries;          /* Chain of retry config information */
97
--- a/src/regex.c
98
+++ b/src/regex.c
99
@@ -95,10 +95,20 @@
100
 pcre2_match_data_free(md);
101
 return FAIL;
102
 }
103
 
104
 
105
+/* reset expansion variables */
106
+void
107
+regex_vars_clear(void)
108
+{
109
+regex_match_string = NULL;
110
+for (int i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
111
+}
112
+
113
+
114
+
115
 int
116
 regex(const uschar ** listptr)
117
 {
118
 unsigned long mbox_size;
119
 FILE * mbox_file;
120
--- a/src/smtp_in.c
121
+++ b/src/smtp_in.c
122
@@ -2155,11 +2155,13 @@
123
 prdr_requested = FALSE;
124
 #endif
125
 #ifdef SUPPORT_I18N
126
 message_smtputf8 = FALSE;
127
 #endif
128
+#ifdef WITH_CONTENT_SCAN
129
 regex_vars_clear();
130
+#endif
131
 body_linecount = body_zerocount = 0;
132
 
133
 lookup_value = NULL;				/* Can be set by ACL */
134
 sender_rate = sender_rate_limit = sender_rate_period = NULL;
135
 ratelimiters_mail = NULL;           /* Updated by ratelimit ACL condition */
(-)b/mail/exim/files/debian/75_11-Fix-non-WITH_CONTENT_SCAN-build-3.patch (+45 lines)
Added Link Here
1
From 32da6327e434e986a18b75a84f2d8c687ba14619 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 1 Sep 2022 15:54:35 +0100
4
Subject: [PATCH 3/3] Fix non-WITH_CONTENT_SCAN build (3)
5
6
Broken-by: d8ecc7bf97
7
---
8
 src/expand.c | 4 ++++
9
 1 file changed, 4 insertions(+)
10
11
diff --git a/src/expand.c b/src/expand.c
12
index 89de56255..831ca2b75 100644
13
--- a/src/expand.c
14
+++ b/src/expand.c
15
@@ -1869,6 +1869,7 @@ if (Ustrncmp(name, "auth", 4) == 0)
16
   if (!*endptr && n != 0 && n <= AUTH_VARS)
17
     return auth_vars[n-1] ? auth_vars[n-1] : US"";
18
   }
19
+#ifdef WITH_CONTENT_SCAN
20
 else if (Ustrncmp(name, "regex", 5) == 0)
21
   {
22
   uschar *endptr;
23
@@ -1876,6 +1877,7 @@ else if (Ustrncmp(name, "regex", 5) == 0)
24
   if (!*endptr && n != 0 && n <= REGEX_VARS)
25
     return regex_vars[n-1] ? regex_vars[n-1] : US"";
26
   }
27
+#endif
28
 
29
 /* For all other variables, search the table */
30
 
31
@@ -8715,9 +8717,11 @@ assert_variable_notin() treats as const, so deconst is safe. */
32
 for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i])
33
   assert_variable_notin(US"auth<n>", US auth_vars[i], &e);
34
 
35
+#ifdef WITH_CONTENT_SCAN
36
 /* check regex<n> variables. assert_variable_notin() treats as const. */
37
 for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i])
38
   assert_variable_notin(US"regex<n>", US regex_vars[i], &e);
39
+#endif
40
 
41
 /* check known-name variables */
42
 for (var_entry * v = var_table; v < var_table + var_table_size; v++)
43
-- 
44
2.35.1
45
(-)b/mail/exim/files/debian/75_16-GnuTLS-fix-for-clients-offering-no-TLS-extensions.patch (+114 lines)
Added Link Here
1
From ece23f05d6a430a461a75639197271c23f6858ec Mon Sep 17 00:00:00 2001
2
From: Jasen Betts <jasen@xnet.co.nz>
3
Date: Fri, 30 Sep 2022 13:49:41 +0100
4
Subject: [PATCH] GnuTLS: fix for clients offering no TLS extensions
5
6
---
7
 doc/ChangeLog              |  3 +++
8
 src/tls-gnu.c                  |  3 ++-
9
 src/tls-openssl.c              | 39 +++++++++++++++---------------
10
 test/confs/2091                    |  1 +
11
 test/log/2091                      |  3 +++
12
 test/scripts/2090-GnuTLS-ALPN/2091 | 19 +++++++++++++++
13
 test/stdout/2091                   | 21 ++++++++++++++++
14
 7 files changed, 68 insertions(+), 21 deletions(-)
15
 create mode 120000 test/confs/2091
16
 create mode 100644 test/log/2091
17
 create mode 100644 test/scripts/2090-GnuTLS-ALPN/2091
18
 create mode 100644 test/stdout/2091
19
20
--- a/doc/ChangeLog
21
+++ b/doc/ChangeLog
22
@@ -10,10 +10,14 @@
23
       more than one message arrived in a single connection a reference from
24
       the earlier message could be re-used.  Often a sigsegv resulted.
25
       These variables were introduced in Exim 4.87.
26
       Debug help from Graeme Fowler.
27
 
28
+JH/10 GnuTLS: fix for (IOT?) clients offering no TLS extensions at all.
29
+      Find and fix by Jasen Betts.
30
+
31
+
32
 
33
 Exim version 4.96
34
 -----------------
35
 
36
 JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
37
--- a/src/tls-gnu.c
38
+++ b/src/tls-gnu.c
39
@@ -1130,12 +1130,13 @@
40
 static int
41
 tls_server_clienthello_cb(gnutls_session_t session, unsigned int htype,
42
   unsigned when, unsigned int incoming, const gnutls_datum_t * msg)
43
 {
44
 /* Call fn for each extension seen.  3.6.3 onwards */
45
-return gnutls_ext_raw_parse(NULL, tls_server_clienthello_ext, msg,
46
+int rc = gnutls_ext_raw_parse(NULL, tls_server_clienthello_ext, msg,
47
 			   GNUTLS_EXT_RAW_FLAG_TLS_CLIENT_HELLO);
48
+return rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE ? 0 : rc;
49
 }
50
 
51
 
52
 # ifdef notdef_crashes
53
 /* Make a note that we saw a status-response */
54
--- a/src/tls-openssl.c
55
+++ b/src/tls-openssl.c
56
@@ -940,40 +940,39 @@
57
 
58
 Returns:    nothing
59
 */
60
 
61
 static void
62
-info_callback(SSL *s, int where, int ret)
63
+info_callback(SSL * s, int where, int ret)
64
 {
65
 DEBUG(D_tls)
66
   {
67
-  const uschar * str;
68
+  gstring * g = NULL;
69
 
70
-  if (where & SSL_ST_CONNECT)
71
-     str = US"SSL_connect";
72
-  else if (where & SSL_ST_ACCEPT)
73
-     str = US"SSL_accept";
74
-  else
75
-     str = US"SSL info (undefined)";
76
+  if (where & SSL_ST_CONNECT) g = string_append_listele(g, ',', US"SSL_connect");
77
+  if (where & SSL_ST_ACCEPT)  g = string_append_listele(g, ',', US"SSL_accept");
78
+  if (where & SSL_CB_LOOP)    g = string_append_listele(g, ',', US"state_chg");
79
+  if (where & SSL_CB_EXIT)    g = string_append_listele(g, ',', US"hshake_exit");
80
+  if (where & SSL_CB_READ)    g = string_append_listele(g, ',', US"read");
81
+  if (where & SSL_CB_WRITE)   g = string_append_listele(g, ',', US"write");
82
+  if (where & SSL_CB_ALERT)   g = string_append_listele(g, ',', US"alert");
83
+  if (where & SSL_CB_HANDSHAKE_START) g = string_append_listele(g, ',', US"hshake_start");
84
+  if (where & SSL_CB_HANDSHAKE_DONE)  g = string_append_listele(g, ',', US"hshake_done");
85
 
86
   if (where & SSL_CB_LOOP)
87
-     debug_printf("%s: %s\n", str, SSL_state_string_long(s));
88
+     debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s));
89
   else if (where & SSL_CB_ALERT)
90
-    debug_printf("SSL3 alert %s:%s:%s\n",
91
-	  str = where & SSL_CB_READ ? US"read" : US"write",
92
+    debug_printf("SSL %s %s:%s\n", g->s,
93
 	  SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
94
   else if (where & SSL_CB_EXIT)
95
     {
96
-    if (ret == 0)
97
-      debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s));
98
-    else if (ret < 0)
99
-      debug_printf("%s: error in %s\n", str, SSL_state_string_long(s));
100
+    if (ret <= 0)
101
+      debug_printf("SSL %s: %s in %s\n", g->s,
102
+	ret == 0 ? "failed" : "error", SSL_state_string_long(s));
103
     }
104
-  else if (where & SSL_CB_HANDSHAKE_START)
105
-     debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s));
106
-  else if (where & SSL_CB_HANDSHAKE_DONE)
107
-     debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s));
108
+  else if (where & (SSL_CB_HANDSHAKE_START | SSL_CB_HANDSHAKE_DONE))
109
+     debug_printf("SSL %s: %s\n", g->s, SSL_state_string_long(s));
110
   }
111
 }
112
 
113
 #ifdef OPENSSL_HAVE_KEYLOG_CB
114
 static void
(-)b/mail/exim/files/debian/75_18-Fix-Build-with-libopendmarc-1.4.x-fixes-2728.patch (+88 lines)
Added Link Here
1
From 1561c5d88b3a23a4348d8e3c1ce28554fcbcfe46 Mon Sep 17 00:00:00 2001
2
From: "Heiko Schlittermann (HS12-RIPE)" <hs@schlittermann.de>
3
Date: Sat, 15 Oct 2022 19:30:58 +0200
4
Subject: [PATCH 1/2] Fix: Build with libopendmarc 1.4.x (fixes 2728)
5
6
---
7
 doc/ChangeLog     | 3 +++
8
 src/EDITME            | 7 +++++--
9
 src/config.h.defaults | 1 +
10
 src/dmarc.c           | 7 ++++++-
11
 4 files changed, 15 insertions(+), 3 deletions(-)
12
13
--- a/doc/ChangeLog
14
+++ b/doc/ChangeLog
15
@@ -13,10 +13,13 @@
16
       Debug help from Graeme Fowler.
17
 
18
 JH/10 GnuTLS: fix for (IOT?) clients offering no TLS extensions at all.
19
       Find and fix by Jasen Betts.
20
 
21
+HS/01 Bug 2728: Introduce EDITME option "DMARC_API" to work around incompatible
22
+      API changes in libopendmarc.
23
+
24
 
25
 
26
 Exim version 4.96
27
 -----------------
28
 
29
--- a/src/EDITME
30
+++ b/src/EDITME
31
@@ -600,18 +600,21 @@
32
 
33
 # EXPERIMENTAL_DCC=yes
34
 
35
 # Uncomment the following line to add DMARC checking capability, implemented
36
 # using libopendmarc libraries. You must have SPF and DKIM support enabled also.
37
-# Library version libopendmarc-1.4.1-1.fc33.x86_64  (on Fedora 33) is known broken;
38
-# 1.3.2-3 works.  I seems that the OpenDMARC project broke their API.
39
 # SUPPORT_DMARC=yes
40
 # CFLAGS += -I/usr/local/include
41
 # LDFLAGS += -lopendmarc
42
 # Uncomment the following if you need to change the default. You can
43
 # override it at runtime (main config option dmarc_tld_file)
44
 # DMARC_TLD_FILE=/etc/exim/opendmarc.tlds
45
+#
46
+# Library version libopendmarc-1.4.1-1.fc33.x86_64  (on Fedora 33) is known broken;
47
+# 1.3.2-3 works.  It seems that the OpenDMARC project broke their API.
48
+# Use this option if you need to build with an old library (1.3.x)
49
+# DMARC_API=100300
50
 
51
 # Uncomment the following line to add ARC (Authenticated Received Chain)
52
 # support.  You must have SPF and DKIM support enabled also.
53
 # EXPERIMENTAL_ARC=yes
54
 
55
--- a/src/config.h.defaults
56
+++ b/src/config.h.defaults
57
@@ -148,10 +148,11 @@
58
 #define STRING_SPRINTF_BUFFER_SIZE (8192 * 4)
59
 
60
 #define SUPPORT_CRYPTEQ
61
 #define SUPPORT_DANE
62
 #define SUPPORT_DMARC
63
+#define DMARC_API 100400
64
 #define DMARC_TLD_FILE "/etc/exim/opendmarc.tlds"
65
 #define SUPPORT_I18N
66
 #define SUPPORT_I18N_2008
67
 #define SUPPORT_MAILDIR
68
 #define SUPPORT_MAILSTORE
69
--- a/src/dmarc.c
70
+++ b/src/dmarc.c
71
@@ -457,11 +457,16 @@
72
     dkim_result = vs == PDKIM_VERIFY_PASS ? DMARC_POLICY_DKIM_OUTCOME_PASS :
73
 		  vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
74
 		  vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
75
 		  DMARC_POLICY_DKIM_OUTCOME_NONE;
76
     libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain,
77
-					       dkim_result, US"");
78
+/* The opendmarc project broke its API in a way we can't detect * easily.
79
+ * The EDITME provides a DMARC_API variable */
80
+#if DMARC_API >= 100400
81
+                                               sig->selector,
82
+#endif
83
+                                               dkim_result, US"");
84
     DEBUG(D_receive)
85
       debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
86
     if (libdm_status != DMARC_PARSE_OKAY)
87
       log_write(0, LOG_MAIN|LOG_PANIC,
88
 		"failure to store dkim (%s) for DMARC: %s",
(-)b/mail/exim/files/debian/75_19-DMARC-fix-use-after-free-in-dmarc_dns_lookup.patch (+39 lines)
Added Link Here
1
From 12fb3842f81bcbd4a4519d5728f2d7e0e3ca1445 Mon Sep 17 00:00:00 2001
2
From: Lorenz Brun <lorenz@brun.one>
3
Date: Fri, 14 Oct 2022 21:02:51 +0200
4
Subject: [PATCH 2/2] DMARC: fix use-after-free in dmarc_dns_lookup
5
6
This fixes a use-after-free in dmarc_dns_lookup where the result
7
of dns_lookup in dnsa is freed before the required data is copied out.
8
9
Fixes: 9258363 ("DNS: explicit alloc/free of workspace")
10
---
11
 src/dmarc.c | 3 ++-
12
 1 file changed, 2 insertions(+), 1 deletion(-)
13
14
diff --git a/src/dmarc.c b/src/dmarc.c
15
index ad0c26c91..53c2752ac 100644
16
--- a/src/dmarc.c
17
+++ b/src/dmarc.c
18
@@ -226,16 +226,17 @@ dns_scan dnss;
19
 int rc = dns_lookup(dnsa, string_sprintf("_dmarc.%s", dom), T_TXT, NULL);
20
 
21
 if (rc == DNS_SUCCEED)
22
   for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
23
        rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
24
     if (rr->type == T_TXT && rr->size > 3)
25
       {
26
+      uschar *record = string_copyn_taint(US rr->data, rr->size, GET_TAINTED);
27
       store_free_dns_answer(dnsa);
28
-      return string_copyn_taint(US rr->data, rr->size, GET_TAINTED);
29
+      return record;
30
       }
31
 store_free_dns_answer(dnsa);
32
 return NULL;
33
 }
34
 
35
 
36
 static int
37
-- 
38
2.35.1
39
(-)b/mail/exim/files/debian/75_22-Fix-daemon-startup.-Bug-2930.patch (+68 lines)
Added Link Here
1
From 221321d2c51b83d1feced80ecd6c2fe33ec5456c Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 3 Nov 2022 20:08:25 +0000
4
Subject: [PATCH 1/2] Fix daemon startup.  Bug 2930
5
6
Broken-by: 7d5055276a
7
---
8
 doc/ChangeLog | 4 ++++
9
 src/daemon.c      | 8 ++++++--
10
 2 files changed, 10 insertions(+), 2 deletions(-)
11
12
--- a/doc/ChangeLog
13
+++ b/doc/ChangeLog
14
@@ -16,10 +16,14 @@
15
       Find and fix by Jasen Betts.
16
 
17
 HS/01 Bug 2728: Introduce EDITME option "DMARC_API" to work around incompatible
18
       API changes in libopendmarc.
19
 
20
+JH/12 Bug 2930: Fix daemon startup.  When started from any process apart from
21
+      pid 1, in the normal "background daemon" mode, having to drop process-
22
+      group leadership also lost track of needing to create listener sockets.
23
+
24
 
25
 
26
 Exim version 4.96
27
 -----------------
28
 
29
--- a/src/daemon.c
30
+++ b/src/daemon.c
31
@@ -1744,19 +1744,23 @@
32
   {
33
   /* If the parent process of this one has pid == 1, we are re-initializing the
34
   daemon as the result of a SIGHUP. In this case, there is no need to do
35
   anything, because the controlling terminal has long gone. Otherwise, fork, in
36
   case current process is a process group leader (see 'man setsid' for an
37
-  explanation) before calling setsid(). */
38
+  explanation) before calling setsid().
39
+  All other forks want daemon_listen cleared. Rather than blow a register, jsut
40
+  restore it here. */
41
 
42
   if (getppid() != 1)
43
     {
44
+    BOOL daemon_listen = f.daemon_listen;
45
     pid_t pid = exim_fork(US"daemon");
46
     if (pid < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
47
       "fork() failed when starting daemon: %s", strerror(errno));
48
     if (pid > 0) exit(EXIT_SUCCESS);      /* in parent process, just exit */
49
     (void)setsid();                       /* release controlling terminal */
50
+    f.daemon_listen = daemon_listen;
51
     }
52
   }
53
 
54
 /* We are now in the disconnected, daemon process (unless debugging). Set up
55
 the listening sockets if required. */
56
@@ -2090,11 +2094,11 @@
57
 	      {				/* found; append port to list */
58
 	      for (p = i2->log; *p; ) p++;	/* end of existing string */
59
 	      if (*--p == '}') *p = '\0';	/* drop EOL */
60
 	      while (isdigit(*--p)) ;		/* char before port */
61
 
62
-	      i2->log = *p == ':'		/* no list yet? */
63
+	      i2->log = *p == ':'		/* no list yet?     { */
64
 		? string_sprintf("%.*s{%s,%d}",
65
 		  (int)(p - i2->log + 1), i2->log, p+1, ipa->port)
66
 		: string_sprintf("%s,%d}", i2->log, ipa->port);
67
 	      ipa->log = NULL;
68
 	      break;
(-)b/mail/exim/files/debian/75_23-Fix-reccipients-after-run.-.-Bug-2929.patch (+45 lines)
Added Link Here
1
From 6b331d5834d12bdda21857cd6fffac17038ce3c7 Mon Sep 17 00:00:00 2001
2
From: Ruben Jenster <r.jenster@drachenfels.de>
3
Date: Thu, 3 Nov 2022 21:38:15 +0000
4
Subject: [PATCH 2/2] Fix $reccipients after ${run...}.  Bug 2929
5
6
Broken-by: cfe6acff2d
7
---
8
 doc/ChangeLog | 3 +++
9
 src/transport.c   | 3 ++-
10
 2 files changed, 5 insertions(+), 1 deletion(-)
11
12
--- a/doc/ChangeLog
13
+++ b/doc/ChangeLog
14
@@ -20,10 +20,13 @@
15
 
16
 JH/12 Bug 2930: Fix daemon startup.  When started from any process apart from
17
       pid 1, in the normal "background daemon" mode, having to drop process-
18
       group leadership also lost track of needing to create listener sockets.
19
 
20
+JH/13 Bug 2929: Fix using $recipients after ${run...}.  A change made for 4.96
21
+      resulted in the variable appearing empty.  Find and fix by Ruben Jenster.
22
+
23
 
24
 
25
 Exim version 4.96
26
 -----------------
27
 
28
--- a/src/transport.c
29
+++ b/src/transport.c
30
@@ -2342,13 +2342,14 @@
31
     /* Handle normal expansion string */
32
 
33
     else
34
       {
35
       const uschar *expanded_arg;
36
+      BOOL enable_dollar_recipients_g = f.enable_dollar_recipients;
37
       f.enable_dollar_recipients = allow_dollar_recipients;
38
       expanded_arg = expand_cstring(argv[i]);
39
-      f.enable_dollar_recipients = FALSE;
40
+      f.enable_dollar_recipients = enable_dollar_recipients_g;
41
 
42
       if (!expanded_arg)
43
         {
44
         uschar *msg = string_sprintf("Expansion of \"%s\" "
45
           "from command \"%s\" in %s failed: %s",
(-)a/mail/exim/files/debian/75_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch (-616 lines)
Removed Link Here
1
From 1843f70b733127fcba3321d9d69359e05905f8cc Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sat, 16 Oct 2021 00:12:16 +0100
4
Subject: [PATCH] Avoid calling gettimeofday(), select() per char for cmdline
5
 message submission.  Bug 2819
6
7
Broken-by: 3c55eef240
8
---
9
 doc/ChangeLog          |  4 ++
10
 src/exim.c                 |  7 ++-
11
 src/filtertest.c           | 16 +++----
12
 src/functions.h            |  4 ++
13
 src/globals.c              | 21 +++++----
14
 src/globals.h              |  3 ++
15
 src/receive.c              | 78 ++++++++++++++++++++++------------
16
 src/smtp_in.c              | 24 ++++++++++-
17
 src/tls-gnu.c              |  9 ++++
18
 src/tls-openssl.c          |  8 ++++
19
 src/transports/autoreply.c | 13 +++---
20
 11 files changed, 133 insertions(+), 54 deletions(-)
21
22
--- a/doc/ChangeLog
23
+++ b/doc/ChangeLog
24
@@ -1,9 +1,13 @@
25
 This document describes *changes* to previous versions, that might
26
 affect Exim's operation, with an unchanged configuration file.  For new
27
 options, and new features, see the NewStuff file next to this ChangeLog.
28
 
29
+JH/05 Bug 2819: speed up command-line messages being read in.  Previously a
30
+      time check was being done for every character; replace that with one
31
+      per buffer.
32
+
33
 
34
 Exim version 4.95
35
 -----------------
36
 
37
 JH/01 Bug 1329: Fix format of Maildir-format filenames to match other mail-
38
--- a/src/exim.c
39
+++ b/src/exim.c
40
@@ -5382,11 +5382,11 @@
41
 
42
 if (smtp_input)
43
   {
44
   if (!f.is_inetd) set_process_info("accepting a local %sSMTP message from <%s>",
45
     smtp_batched_input? "batched " : "",
46
-    (sender_address!= NULL)? sender_address : originator_login);
47
+    sender_address ? sender_address : originator_login);
48
   }
49
 else
50
   {
51
   int old_pool = store_pool;
52
   store_pool = POOL_PERM;
53
@@ -5432,11 +5432,12 @@
54
     mac_smtp_fflush();
55
     exim_exit(EXIT_SUCCESS);
56
     }
57
   }
58
 
59
-/* Otherwise, set up the input size limit here. */
60
+/* Otherwise, set up the input size limit here and set no stdin stdio buffer
61
+(we handle buferring so as to have visibility of fill level). */
62
 
63
 else
64
   {
65
   thismessage_size_limit = expand_string_integer(message_size_limit, TRUE);
66
   if (expand_string_message)
67
@@ -5444,10 +5445,12 @@
68
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand "
69
         "message_size_limit: %s", expand_string_message);
70
     else
71
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
72
         "message_size_limit: %s", expand_string_message);
73
+
74
+  setvbuf(stdin, NULL, _IONBF, 0);
75
   }
76
 
77
 /* Loop for several messages when reading SMTP input. If we fork any child
78
 processes, we don't want to wait for them unless synchronous delivery is
79
 requested, so set SIGCHLD to SIG_IGN in that case. This is not necessarily the
80
--- a/src/filtertest.c
81
+++ b/src/filtertest.c
82
@@ -43,15 +43,15 @@
83
 s = message_body_end;
84
 body_len = 0;
85
 body_linecount = 0;
86
 header_size = message_size;
87
 
88
-if (!dot_ended && !feof(stdin))
89
+if (!dot_ended && !stdin_feof())
90
   {
91
   if (!f.dot_ends)
92
     {
93
-    while ((ch = getc(stdin)) != EOF)
94
+    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
95
       {
96
       if (ch == 0) body_zerocount++;
97
       if (ch == '\n') body_linecount++;
98
       if (body_len < message_body_visible) message_body[body_len++] = ch;
99
       *s++ = ch;
100
@@ -60,11 +60,11 @@
101
       }
102
     }
103
   else
104
     {
105
     int ch_state = 1;
106
-    while ((ch = getc(stdin)) != EOF)
107
+    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
108
       {
109
       if (ch == 0) body_zerocount++;
110
       switch (ch_state)
111
         {
112
         case 0:                         /* Normal state */
113
@@ -97,10 +97,11 @@
114
       }
115
     READ_END: ;
116
     }
117
   if (s == message_body_end || s[-1] != '\n') body_linecount++;
118
   }
119
+debug_printf("%s %d\n", __FUNCTION__, __LINE__);
120
 
121
 message_body[body_len] = 0;
122
 message_body_size = message_size - header_size;
123
 
124
 /* body_len stops at message_body_visible; it if got there, we may have
125
@@ -248,11 +249,11 @@
126
   }
127
 
128
 /* For a filter, set up the message_body variables and the message size if this
129
 is the first time this function has been called. */
130
 
131
-if (message_body == NULL) read_message_body(dot_ended);
132
+if (!message_body) read_message_body(dot_ended);
133
 
134
 /* Now pass the filter file to the function that interprets it. Because
135
 filter_test is not FILTER_NONE, the interpreter will output comments about what
136
 it is doing. No need to clean up store. Indeed, we must not, because we may be
137
 testing a system filter that is going to be followed by a user filter test. */
138
@@ -267,14 +268,13 @@
139
   f.enable_dollar_recipients = FALSE;
140
   f.system_filtering = FALSE;
141
   }
142
 else
143
   {
144
-  yield = (filter_type == FILTER_SIEVE)?
145
-    sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
146
-    :
147
-    filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
148
+  yield = filter_type == FILTER_SIEVE
149
+    ? sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
150
+    : filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
151
   }
152
 
153
 return yield != FF_ERROR;
154
 }
155
 
156
--- a/src/functions.h
157
+++ b/src/functions.h
158
@@ -66,10 +66,11 @@
159
 extern uschar *tls_field_from_dn(uschar *, const uschar *);
160
 extern void    tls_free_cert(void **);
161
 extern int     tls_getc(unsigned);
162
 extern uschar *tls_getbuf(unsigned *);
163
 extern void    tls_get_cache(unsigned);
164
+extern BOOL    tls_hasc(void);
165
 extern BOOL    tls_import_cert(const uschar *, void **);
166
 extern BOOL    tls_is_name_for_cert(const uschar *, void *);
167
 # ifdef USE_OPENSSL
168
 extern BOOL    tls_openssl_options_parse(uschar *, long *);
169
 # endif
170
@@ -148,10 +149,11 @@
171
 extern uschar *b64encode(const uschar *, int);
172
 extern uschar *b64encode_taint(const uschar *, int, BOOL);
173
 extern int     b64decode(const uschar *, uschar **);
174
 extern int     bdat_getc(unsigned);
175
 extern uschar *bdat_getbuf(unsigned *);
176
+extern BOOL    bdat_hasc(void);
177
 extern int     bdat_ungetc(int);
178
 extern void    bdat_flush_data(void);
179
 
180
 extern void    bits_clear(unsigned int *, size_t, int *);
181
 extern void    bits_set(unsigned int *, size_t, int *);
182
@@ -492,10 +494,11 @@
183
                  uschar **, uschar *);
184
 extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
185
 extern int     smtp_getc(unsigned);
186
 extern uschar *smtp_getbuf(unsigned *);
187
 extern void    smtp_get_cache(unsigned);
188
+extern BOOL    smtp_hasc(void);
189
 extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
190
 extern void    smtp_log_no_mail(void);
191
 extern void    smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
192
 extern void    smtp_proxy_tls(void *, uschar *, size_t, int *, int) NORETURN;
193
 extern BOOL    smtp_read_response(void *, uschar *, int, int, int);
194
@@ -521,10 +524,11 @@
195
 extern uschar *spool_sender_from_msgid(const uschar *);
196
 extern int     spool_write_header(uschar *, int, uschar **);
197
 extern int     stdin_getc(unsigned);
198
 extern int     stdin_feof(void);
199
 extern int     stdin_ferror(void);
200
+extern BOOL    stdin_hasc(void);
201
 extern int     stdin_ungetc(int);
202
 
203
 extern void    store_exit(void);
204
 extern void    store_init(void);
205
 extern void    store_writeprotect(int);
206
--- a/src/globals.c
207
+++ b/src/globals.c
208
@@ -169,20 +169,23 @@
209
 /* Input-reading functions for messages, so we can use special ones for
210
 incoming TCP/IP. The defaults use stdin. We never need these for any
211
 stand-alone tests. */
212
 
213
 #if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
214
-int (*lwr_receive_getc)(unsigned) = stdin_getc;
215
+int	(*lwr_receive_getc)(unsigned)	= stdin_getc;
216
 uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
217
-int (*lwr_receive_ungetc)(int) = stdin_ungetc;
218
-int (*receive_getc)(unsigned)  = stdin_getc;
219
-uschar * (*receive_getbuf)(unsigned *)  = NULL;
220
-void (*receive_get_cache)(unsigned)    = NULL;
221
-int (*receive_ungetc)(int)     = stdin_ungetc;
222
-int (*receive_feof)(void)      = stdin_feof;
223
-int (*receive_ferror)(void)    = stdin_ferror;
224
-BOOL (*receive_smtp_buffered)(void) = NULL;   /* Only used for SMTP */
225
+int	(*lwr_receive_ungetc)(int)	= stdin_ungetc;
226
+BOOL	(*lwr_receive_hasc)(void)	= stdin_hasc;
227
+
228
+int	(*receive_getc)(unsigned) 	= stdin_getc;
229
+uschar * (*receive_getbuf)(unsigned *) 	= NULL;
230
+void	(*receive_get_cache)(unsigned)	= NULL;
231
+BOOL	(*receive_hasc)(void)		= stdin_hasc;
232
+int	(*receive_ungetc)(int)    	= stdin_ungetc;
233
+int	(*receive_feof)(void)     	= stdin_feof;
234
+int	(*receive_ferror)(void)   	= stdin_ferror;
235
+BOOL	(*receive_smtp_buffered)(void)	= NULL;   /* Only used for SMTP */
236
 #endif
237
 
238
 
239
 /* List of per-address expansion variables for clearing and saving/restoring
240
 when verifying one address while routing/verifying another. We have to have
241
--- a/src/globals.h
242
+++ b/src/globals.h
243
@@ -159,13 +159,16 @@
244
 /* Input-reading functions for messages, so we can use special ones for
245
 incoming TCP/IP. */
246
 
247
 extern int (*lwr_receive_getc)(unsigned);
248
 extern uschar * (*lwr_receive_getbuf)(unsigned *);
249
+extern BOOL (*lwr_receive_hasc)(void);
250
 extern int (*lwr_receive_ungetc)(int);
251
+
252
 extern int (*receive_getc)(unsigned);
253
 extern uschar * (*receive_getbuf)(unsigned *);
254
+extern BOOL (*receive_hasc)(void);
255
 extern void (*receive_get_cache)(unsigned);
256
 extern int (*receive_ungetc)(int);
257
 extern int (*receive_feof)(void);
258
 extern int (*receive_ferror)(void);
259
 extern BOOL (*receive_smtp_buffered)(void);
260
--- a/src/receive.c
261
+++ b/src/receive.c
262
@@ -42,46 +42,75 @@
263
 /* These are the default functions that are set up in the variables such as
264
 receive_getc initially. They just call the standard functions, passing stdin as
265
 the file. (When SMTP input is occurring, different functions are used by
266
 changing the pointer variables.) */
267
 
268
+uschar stdin_buf[4096];
269
+uschar * stdin_inptr = stdin_buf;
270
+uschar * stdin_inend = stdin_buf;
271
+
272
+static BOOL
273
+stdin_refill(void)
274
+{
275
+size_t rc = fread(stdin_buf, 1, sizeof(stdin_buf), stdin);
276
+if (rc <= 0)
277
+  {
278
+  if (had_data_timeout)
279
+    {
280
+    fprintf(stderr, "exim: timed out while reading - message abandoned\n");
281
+    log_write(L_lost_incoming_connection,
282
+	      LOG_MAIN, "timed out while reading local message");
283
+    receive_bomb_out(US"data-timeout", NULL);   /* Does not return */
284
+    }
285
+  if (had_data_sigint)
286
+    {
287
+    if (filter_test == FTEST_NONE)
288
+      {
289
+      fprintf(stderr, "\nexim: %s received - message abandoned\n",
290
+	had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
291
+      log_write(0, LOG_MAIN, "%s received while reading local message",
292
+	had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
293
+      }
294
+    receive_bomb_out(US"signal-exit", NULL);    /* Does not return */
295
+    }
296
+  return FALSE;
297
+  }
298
+stdin_inend = stdin_buf + rc;
299
+stdin_inptr = stdin_buf;
300
+return TRUE;
301
+}
302
+
303
 int
304
 stdin_getc(unsigned lim)
305
 {
306
-int c = getc(stdin);
307
+if (stdin_inptr >= stdin_inend)
308
+  if (!stdin_refill())
309
+      return EOF;
310
+return *stdin_inptr++;
311
+}
312
 
313
-if (had_data_timeout)
314
-  {
315
-  fprintf(stderr, "exim: timed out while reading - message abandoned\n");
316
-  log_write(L_lost_incoming_connection,
317
-            LOG_MAIN, "timed out while reading local message");
318
-  receive_bomb_out(US"data-timeout", NULL);   /* Does not return */
319
-  }
320
-if (had_data_sigint)
321
-  {
322
-  if (filter_test == FTEST_NONE)
323
-    {
324
-    fprintf(stderr, "\nexim: %s received - message abandoned\n",
325
-      had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
326
-    log_write(0, LOG_MAIN, "%s received while reading local message",
327
-      had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
328
-    }
329
-  receive_bomb_out(US"signal-exit", NULL);    /* Does not return */
330
-  }
331
-return c;
332
+
333
+BOOL
334
+stdin_hasc(void)
335
+{
336
+return stdin_inptr < stdin_inend;
337
 }
338
 
339
 int
340
 stdin_ungetc(int c)
341
 {
342
-return ungetc(c, stdin);
343
+if (stdin_inptr <= stdin_buf)
344
+  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in stdin_ungetc");
345
+
346
+*--stdin_inptr = c;
347
+return c;
348
 }
349
 
350
 int
351
 stdin_feof(void)
352
 {
353
-return feof(stdin);
354
+return stdin_hasc() ? FALSE : feof(stdin);
355
 }
356
 
357
 int
358
 stdin_ferror(void)
359
 {
360
@@ -586,11 +615,11 @@
361
 the file copy. */
362
 
363
 static void
364
 log_close_chk(void)
365
 {
366
-if (!receive_timeout)
367
+if (!receive_timeout && !receive_hasc())
368
   {
369
   struct timeval t;
370
   timesince(&t, &received_time);
371
   if (t.tv_sec > 30*60)
372
     mainlog_close();
373
@@ -652,15 +681,10 @@
374
 
375
 if (!f.dot_ends)
376
   {
377
   int last_ch = '\n';
378
 
379
-/*XXX we do a gettimeofday before checking for every received char,
380
-which is hardly clever.  The function-indirection doesn't help, but
381
-an additional function to check for nonempty read buffer would help.
382
-See stdin_getc() / smtp_getc() / tls_getc() / bdat_getc(). */
383
-
384
   for ( ;
385
        log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF;
386
        last_ch = ch)
387
     {
388
     if (ch == 0) body_zerocount++;
389
--- a/src/smtp_in.c
390
+++ b/src/smtp_in.c
391
@@ -561,10 +561,16 @@
392
   if (!smtp_refill(lim))
393
     return EOF;
394
 return *smtp_inptr++;
395
 }
396
 
397
+BOOL
398
+smtp_hasc(void)
399
+{
400
+return smtp_inptr < smtp_inend;
401
+}
402
+
403
 uschar *
404
 smtp_getbuf(unsigned * len)
405
 {
406
 unsigned size;
407
 uschar * buf;
408
@@ -743,10 +749,18 @@
409
       }
410
     }
411
   }
412
 }
413
 
414
+BOOL
415
+bdat_hasc(void)
416
+{
417
+if (chunking_data_left > 0)
418
+  return lwr_receive_hasc();
419
+return TRUE;
420
+}
421
+
422
 uschar *
423
 bdat_getbuf(unsigned * len)
424
 {
425
 uschar * buf;
426
 
427
@@ -782,40 +796,44 @@
428
 bdat_push_receive_functions(void)
429
 {
430
 /* push the current receive_* function on the "stack", and
431
 replace them by bdat_getc(), which in turn will use the lwr_receive_*
432
 functions to do the dirty work. */
433
-if (lwr_receive_getc == NULL)
434
+if (!lwr_receive_getc)
435
   {
436
   lwr_receive_getc = receive_getc;
437
   lwr_receive_getbuf = receive_getbuf;
438
+  lwr_receive_hasc = receive_hasc;
439
   lwr_receive_ungetc = receive_ungetc;
440
   }
441
 else
442
   {
443
   DEBUG(D_receive) debug_printf("chunking double-push receive functions\n");
444
   }
445
 
446
 receive_getc = bdat_getc;
447
 receive_getbuf = bdat_getbuf;
448
+receive_hasc = bdat_hasc;
449
 receive_ungetc = bdat_ungetc;
450
 }
451
 
452
 static inline void
453
 bdat_pop_receive_functions(void)
454
 {
455
-if (lwr_receive_getc == NULL)
456
+if (!lwr_receive_getc)
457
   {
458
   DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
459
   return;
460
   }
461
 receive_getc = lwr_receive_getc;
462
 receive_getbuf = lwr_receive_getbuf;
463
+receive_hasc = lwr_receive_hasc;
464
 receive_ungetc = lwr_receive_ungetc;
465
 
466
 lwr_receive_getc = NULL;
467
 lwr_receive_getbuf = NULL;
468
+lwr_receive_hasc = NULL;
469
 lwr_receive_ungetc = NULL;
470
 }
471
 
472
 /*************************************************
473
 *          SMTP version of ungetc()              *
474
@@ -2574,16 +2592,18 @@
475
 smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0';
476
 
477
 receive_getc = smtp_getc;
478
 receive_getbuf = smtp_getbuf;
479
 receive_get_cache = smtp_get_cache;
480
+receive_hasc = smtp_hasc;
481
 receive_ungetc = smtp_ungetc;
482
 receive_feof = smtp_feof;
483
 receive_ferror = smtp_ferror;
484
 receive_smtp_buffered = smtp_buffered;
485
 lwr_receive_getc = NULL;
486
 lwr_receive_getbuf = NULL;
487
+lwr_receive_hasc = NULL;
488
 lwr_receive_ungetc = NULL;
489
 smtp_inptr = smtp_inend = smtp_inbuffer;
490
 smtp_had_eof = smtp_had_error = 0;
491
 
492
 /* Set up the message size limit; this may be host-specific */
493
--- a/src/tls-gnu.c
494
+++ b/src/tls-gnu.c
495
@@ -3136,10 +3136,11 @@
496
 state->xfer_buffer = store_malloc(ssl_xfer_buffer_size);
497
 
498
 receive_getc = tls_getc;
499
 receive_getbuf = tls_getbuf;
500
 receive_get_cache = tls_get_cache;
501
+receive_hasc = tls_hasc;
502
 receive_ungetc = tls_ungetc;
503
 receive_feof = tls_feof;
504
 receive_ferror = tls_ferror;
505
 receive_smtp_buffered = tls_smtp_buffered;
506
 
507
@@ -3738,10 +3739,11 @@
508
 if (!ct_ctx)	/* server */
509
   {
510
   receive_getc =	smtp_getc;
511
   receive_getbuf =	smtp_getbuf;
512
   receive_get_cache =	smtp_get_cache;
513
+  receive_hasc =	smtp_hasc;
514
   receive_ungetc =	smtp_ungetc;
515
   receive_feof =	smtp_feof;
516
   receive_ferror =	smtp_ferror;
517
   receive_smtp_buffered = smtp_buffered;
518
   }
519
@@ -3852,10 +3854,17 @@
520
 /* Something in the buffer; return next uschar */
521
 
522
 return state->xfer_buffer[state->xfer_buffer_lwm++];
523
 }
524
 
525
+BOOL
526
+tls_hasc(void)
527
+{
528
+exim_gnutls_state_st * state = &state_server;
529
+return state->xfer_buffer_lwm < state->xfer_buffer_hwm;
530
+}
531
+
532
 uschar *
533
 tls_getbuf(unsigned * len)
534
 {
535
 exim_gnutls_state_st * state = &state_server;
536
 unsigned size;
537
--- a/src/tls-openssl.c
538
+++ b/src/tls-openssl.c
539
@@ -3348,10 +3348,11 @@
540
 ssl_xfer_eof = ssl_xfer_error = FALSE;
541
 
542
 receive_getc = tls_getc;
543
 receive_getbuf = tls_getbuf;
544
 receive_get_cache = tls_get_cache;
545
+receive_hasc = tls_hasc;
546
 receive_ungetc = tls_ungetc;
547
 receive_feof = tls_feof;
548
 receive_ferror = tls_ferror;
549
 receive_smtp_buffered = tls_smtp_buffered;
550
 
551
@@ -4124,10 +4125,16 @@
552
 /* Something in the buffer; return next uschar */
553
 
554
 return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
555
 }
556
 
557
+BOOL
558
+tls_hasc(void)
559
+{
560
+return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm;
561
+}
562
+
563
 uschar *
564
 tls_getbuf(unsigned * len)
565
 {
566
 unsigned size;
567
 uschar * buf;
568
@@ -4413,10 +4420,11 @@
569
 #endif
570
 
571
   receive_getc =	smtp_getc;
572
   receive_getbuf =	smtp_getbuf;
573
   receive_get_cache =	smtp_get_cache;
574
+  receive_hasc =	smtp_hasc;
575
   receive_ungetc =	smtp_ungetc;
576
   receive_feof =	smtp_feof;
577
   receive_ferror =	smtp_ferror;
578
   receive_smtp_buffered = smtp_buffered;
579
   tls_in.active.tls_ctx = NULL;
580
--- a/src/transports/autoreply.c
581
+++ b/src/transports/autoreply.c
582
@@ -644,10 +644,11 @@
583
   if (text[Ustrlen(text)-1] != '\n') fprintf(fp, "\n");
584
   }
585
 
586
 if (ff)
587
   {
588
+debug_printf("%s %d: ff\n", __FUNCTION__, __LINE__);
589
   while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
590
     {
591
     if (file_expand)
592
       {
593
       uschar *s = expand_string(big_buffer);
594
@@ -667,16 +668,16 @@
595
 /* Copy the original message if required, observing the return size
596
 limit if we are returning the body. */
597
 
598
 if (return_message)
599
   {
600
-  uschar *rubric = (tblock->headers_only)?
601
-    US"------ This is a copy of the message's header lines.\n"
602
-    : (tblock->body_only)?
603
-    US"------ This is a copy of the body of the message, without the headers.\n"
604
-    :
605
-    US"------ This is a copy of the message, including all the headers.\n";
606
+debug_printf("%s %d: ret msg\n", __FUNCTION__, __LINE__);
607
+  uschar *rubric = tblock->headers_only
608
+    ? US"------ This is a copy of the message's header lines.\n"
609
+    : tblock->body_only
610
+    ? US"------ This is a copy of the body of the message, without the headers.\n"
611
+    : US"------ This is a copy of the message, including all the headers.\n";
612
   transport_ctx tctx = {
613
     .u = {.fd = fileno(fp)},
614
     .tblock = tblock,
615
     .addr = addr,
616
     .check_string = NULL,
(-)b/mail/exim/files/debian/75_31-Fix-regext-substring-capture-variables-for-null-matc.patch (+79 lines)
Added Link Here
1
From e63825824cc406c160ccbf2b154c5d81b168604a Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Fri, 11 Nov 2022 00:05:59 +0000
4
Subject: [PATCH 1/2] Fix regext substring capture variables for null matches. 
5
 Bug 2933
6
7
broken-by: 59d66fdc13f0
8
---
9
 doc/ChangeLog | 5 +++++
10
 src/exim.c        | 2 ++
11
 src/malware.c     | 3 +++
12
 src/regex.c       | 2 +-
13
 4 files changed, 11 insertions(+), 1 deletion(-)
14
15
--- a/doc/ChangeLog
16
+++ b/doc/ChangeLog
17
@@ -22,10 +22,15 @@
18
       pid 1, in the normal "background daemon" mode, having to drop process-
19
       group leadership also lost track of needing to create listener sockets.
20
 
21
 JH/13 Bug 2929: Fix using $recipients after ${run...}.  A change made for 4.96
22
       resulted in the variable appearing empty.  Find and fix by Ruben Jenster.
23
+ 
24
+JH/14 Bug 2933: Fix regex substring match variables for null matches. Since 4.96
25
+      a capture group which obtained no text (eg. "(abc)*" matching zero
26
+      occurrences) could cause a segfault if the corresponding $<n> was
27
+      expanded.
28
 
29
 
30
 
31
 Exim version 4.96
32
 -----------------
33
--- a/src/exim.c
34
+++ b/src/exim.c
35
@@ -167,10 +167,12 @@
36
   for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++)
37
     {
38
     PCRE2_SIZE len;
39
     pcre2_substring_get_bynumber(md, matchnum,
40
       (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len);
41
+    if (!expand_nstring[expand_nmax])
42
+      { expand_nstring[expand_nmax] = US""; len = 0; }
43
     expand_nlength[expand_nmax++] = (int)len;
44
     }
45
   expand_nmax--;
46
   }
47
 else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any)
48
--- a/src/malware.c
49
+++ b/src/malware.c
50
@@ -323,11 +323,14 @@
51
 int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx);
52
 PCRE2_UCHAR * substr = NULL;
53
 PCRE2_SIZE slen;
54
 
55
 if (i >= 2)				/* Got it */
56
+  {
57
   pcre2_substring_get_bynumber(md, 1, &substr, &slen);
58
+  if (!substr) substr = US"";
59
+  }
60
 return US substr;
61
 }
62
 
63
 static const pcre2_code *
64
 m_pcre_nextinlist(const uschar ** list, int * sep,
65
--- a/src/regex.c
66
+++ b/src/regex.c
67
@@ -84,11 +84,11 @@
68
     for (int nn = 1; nn < n; nn++)
69
       {
70
       PCRE2_UCHAR * cstr;
71
       PCRE2_SIZE cslen;
72
       pcre2_substring_get_bynumber(md, nn, &cstr, &cslen);
73
-      regex_vars[nn-1] = CUS cstr;
74
+      regex_vars[nn-1] = cstr ? CUS cstr : CUS"";
75
       }
76
 
77
     return OK;
78
     }
79
   }
(-)a/mail/exim/files/debian/75_32-Fix-PAM-auth.-Bug-2813.patch (-25 lines)
Removed Link Here
1
From 51be321b27825c01829dffd90f11bfff256f7e42 Mon Sep 17 00:00:00 2001
2
From: Adam Lackorzynski <adam@l4re.org>
3
Date: Sat, 16 Oct 2021 16:30:07 +0100
4
Subject: [PATCH] Fix PAM auth.  Bug 2813
5
6
---
7
 src/auths/call_pam.c | 2 +-
8
 1 file changed, 1 insertion(+), 1 deletion(-)
9
10
diff --git a/src/auths/call_pam.c b/src/auths/call_pam.c
11
index 80bb23ec3..03b9be1a8 100644
12
--- a/src/auths/call_pam.c
13
+++ b/src/auths/call_pam.c
14
@@ -88,7 +88,7 @@ for (int i = 0; i < num_msg; i++)
15
 	arg = US"";
16
 	pam_arg_ended = TRUE;
17
 	}
18
-      reply[i].resp = CS string_copy_malloc(arg); /* PAM frees resp */
19
+      reply[i].resp = strdup(CCS arg); /* Use libc malloc, PAM frees resp directly*/
20
       reply[i].resp_retcode = PAM_SUCCESS;
21
       break;
22
 
23
-- 
24
2.34.1
25
(-)b/mail/exim/files/debian/75_32-Fix-regex-substring-capture-variables-for-null-match.patch (+94 lines)
Added Link Here
1
From 7ad1a2b2cc57b5f4bcb59186a9a8abcbed9f4f76 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Fri, 11 Nov 2022 18:22:00 +0000
4
Subject: [PATCH 2/2] Fix regex substring capture variables for null matches
5
 (again).  Bug 2933
6
7
Broken-by: 59d66fdc13f0
8
---
9
 src/exim.c               | 11 +++++------
10
 src/malware.c            | 10 +++++-----
11
 src/regex.c              |  8 ++++----
12
 test/aux-var-src/0383.F      |  4 ++--
13
 test/log/0383                |  4 ++--
14
 test/mail/0383.CALLER        |  8 ++++----
15
 test/scripts/0000-Basic/0002 |  2 ++
16
 test/stdout/0002             |  2 ++
17
 8 files changed, 26 insertions(+), 23 deletions(-)
18
19
--- a/src/exim.c
20
+++ b/src/exim.c
21
@@ -160,20 +160,19 @@
22
 			PCRE_EOPT | options, md, pcre_mtc_ctx);
23
 BOOL yield;
24
 
25
 if ((yield = (res >= 0)))
26
   {
27
+  PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
28
   res = pcre2_get_ovector_count(md);
29
   expand_nmax = setup < 0 ? 0 : setup + 1;
30
   for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++)
31
     {
32
-    PCRE2_SIZE len;
33
-    pcre2_substring_get_bynumber(md, matchnum,
34
-      (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len);
35
-    if (!expand_nstring[expand_nmax])
36
-      { expand_nstring[expand_nmax] = US""; len = 0; }
37
-    expand_nlength[expand_nmax++] = (int)len;
38
+    int off = matchnum * 2;
39
+    int len = ovec[off + 1] - ovec[off];
40
+    expand_nstring[expand_nmax] = string_copyn(subject + ovec[off], len);
41
+    expand_nlength[expand_nmax++] = len;
42
     }
43
   expand_nmax--;
44
   }
45
 else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any)
46
   {
47
--- a/src/malware.c
48
+++ b/src/malware.c
49
@@ -319,19 +319,19 @@
50
 uschar *
51
 m_pcre_exec(const pcre2_code * cre, uschar * text)
52
 {
53
 pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
54
 int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx);
55
-PCRE2_UCHAR * substr = NULL;
56
-PCRE2_SIZE slen;
57
+uschar * substr = NULL;
58
 
59
 if (i >= 2)				/* Got it */
60
   {
61
-  pcre2_substring_get_bynumber(md, 1, &substr, &slen);
62
-  if (!substr) substr = US"";
63
+  PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
64
+  int len = ovec[3] - ovec[2];
65
+  substr = string_copyn(text + ovec[2], len);
66
   }
67
-return US substr;
68
+return substr;
69
 }
70
 
71
 static const pcre2_code *
72
 m_pcre_nextinlist(const uschar ** list, int * sep,
73
  char * listerr, uschar ** errstr)
74
--- a/src/regex.c
75
+++ b/src/regex.c
76
@@ -81,14 +81,14 @@
77
 	      sizeof(regex_match_string_buffer)-1);
78
     regex_match_string = regex_match_string_buffer;
79
 
80
     for (int nn = 1; nn < n; nn++)
81
       {
82
-      PCRE2_UCHAR * cstr;
83
-      PCRE2_SIZE cslen;
84
-      pcre2_substring_get_bynumber(md, nn, &cstr, &cslen);
85
-      regex_vars[nn-1] = cstr ? CUS cstr : CUS"";
86
+      PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
87
+      int off = nn * 2;
88
+      int len = ovec[off + 1] - ovec[off];
89
+      regex_vars[nn-1] = string_copyn(linebuffer + ovec[off], len);
90
       }
91
 
92
     return OK;
93
     }
94
   }
(-)b/mail/exim/files/debian/75_34-Fix-regex-substring-capture-commentary.-Bug-2933.patch (+48 lines)
Added Link Here
1
From 9ba47886c71d40edc99b026a99edee269d9c9c6f Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sat, 12 Nov 2022 12:38:22 +0000
4
Subject: [PATCH] Fix regex substring capture - commentary.  Bug 2933
5
6
Broken-by (corrected): 22ed7a5295f1
7
---
8
 src/exim.c | 9 ++++++++-
9
 1 file changed, 8 insertions(+), 1 deletion(-)
10
11
diff --git a/src/exim.c b/src/exim.c
12
index 16c0184e0..625494ce4 100644
13
--- a/src/exim.c
14
+++ b/src/exim.c
15
@@ -102,11 +102,13 @@ pcre_gen_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
16
 *   Execute regular expression and set strings   *
17
 *************************************************/
18
 
19
 /* This function runs a regular expression match, and sets up the pointers to
20
 the matched substrings.  The matched strings are copied so the lifetime of
21
-the subject is not a problem.
22
+the subject is not a problem.  Matched strings will have the same taint status
23
+as the subject string (this is not a de-taint method, and must not be made so
24
+given the support for wildcards in REs).
25
 
26
 Arguments:
27
   re          the compiled expression
28
   subject     the subject string
29
   options     additional PCRE options
30
@@ -130,10 +132,15 @@ if ((yield = (res >= 0)))
31
   PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
32
   res = pcre2_get_ovector_count(md);
33
   expand_nmax = setup < 0 ? 0 : setup + 1;
34
   for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++)
35
     {
36
+    /* Although PCRE2 has a pcre2_substring_get_bynumber() conveneience, it
37
+    seems to return a bad pointer when a capture group had no data, eg. (.*)
38
+    matching zero letters.  So use the underlying ovec and hope (!) that the
39
+    offsets are sane (including that case).  Should we go further and range-
40
+    check each one vs. the subject string length? */
41
     int off = matchnum * 2;
42
     int len = ovec[off + 1] - ovec[off];
43
     expand_nstring[expand_nmax] = string_copyn(subject + ovec[off], len);
44
     expand_nlength[expand_nmax++] = len;
45
     }
46
-- 
47
2.35.1
48
(-)a/mail/exim/files/debian/75_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch (-42 lines)
Removed Link Here
1
From df618101a5ea15dc90c4a2968798ef2be9dba16f Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Mon, 18 Oct 2021 11:01:47 +0100
4
Subject: [PATCH] Exiqgrep: check arg parsing.  Bug 2821
5
6
---
7
 src/exiqgrep.src | 2 +-
8
 1 file changed, 1 insertion(+), 1 deletion(-)
9
10
diff --git a/src/exiqgrep.src b/src/exiqgrep.src
11
index c8762df47..04602da68 100644
12
--- a/src/exiqgrep.src
13
+++ b/src/exiqgrep.src
14
@@ -53,12 +53,14 @@ if ($ARGV[0] eq '--version') {
15
         exit 0;
16
 }
17
 
18
-getopts('hf:r:y:o:s:C:zxlibRcaG:',\%opt);
19
-if ($ARGV[0]) { &help; exit;}
20
-if ($opt{h}) { &help; exit;}
21
+if (!getopts('hf:r:y:o:s:C:zxlibRcaG:E:',\%opt)) { &help; exit; }
22
+if ($opt{h}) { &help; exit; }
23
+if ($ARGV[0] || !($opt{f} || $opt{r} || $opt{s} || $opt{y} || $opt{o} || $opt{z} || $opt{x} || $opt{c}))
24
+   { &help; exit(1); }
25
 if ($opt{a}) { $eargs = '-bp'; }
26
 if ($opt{C} && -e $opt{C} && -f $opt{C} && -R $opt{C}) { $eargs .= ' -C '.$opt{C}; }
27
 if ($opt{G}) { $eargs .= ' -qG'.$opt{G}; }
28
+if ($opt{E}) { $exim = $opt{E}; }
29
 
30
 # Read message queue output into hash
31
 &collect();
32
@@ -75,6 +77,7 @@ Exim message queue display utility.
33
 
34
 	-h		This help message.
35
 	-C		Specify which exim.conf to use.
36
+	-E		Specify exim binary to use.
37
 
38
 Selection criteria:
39
 	-f <regexp>	Match sender address sender (field is "< >" wrapped)
40
-- 
41
2.34.1
42
(-)b/mail/exim/files/debian/75_37-OpenSSL-when-preloading-creds-do-the-server-certs-be.patch (+232 lines)
Added Link Here
1
From 7f65a63b60c6ea86db683ac00e221939f3bb1d47 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Tue, 25 Oct 2022 21:26:30 +0100
4
Subject: [PATCH 1/2] OpenSSL: when preloading creds do the server certs before
5
 the OCSP proofs so that the latter can ve verified before loading
6
7
---
8
 src/tls-openssl.c | 113 ++++++++++++++++++++++--------------------
9
 1 file changed, 58 insertions(+), 55 deletions(-)
10
11
diff --git a/src/tls-openssl.c b/src/tls-openssl.c
12
index 68ad6f15b..fdf0d92b2 100644
13
--- a/src/tls-openssl.c
14
+++ b/src/tls-openssl.c
15
@@ -441,14 +441,16 @@ exim_openssl_state_st state_server = {.is_server = TRUE};
16
 static int
17
 setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
18
     uschar ** errstr );
19
 
20
 /* Callbacks */
21
 #ifndef DISABLE_OCSP
22
 static int tls_server_stapling_cb(SSL *s, void *arg);
23
+static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk);
24
+static void x509_store_dump_cert_s_names(X509_STORE * store);
25
 #endif
26
 
27
 
28
 
29
 /* Daemon-called, before every connection, key create/rotate */
30
 #ifndef DISABLE_TLS_RESUME
31
 static void tk_init(void);
32
@@ -1307,15 +1309,14 @@ ocsp_load_response(exim_openssl_state_st * state, const uschar * filename,
33
 {
34
 BIO * bio;
35
 OCSP_RESPONSE * resp;
36
 OCSP_BASICRESP * basic_response;
37
 OCSP_SINGLERESP * single_response;
38
 ASN1_GENERALIZEDTIME * rev, * thisupd, * nextupd;
39
 STACK_OF(X509) * sk;
40
-unsigned long verify_flags;
41
 int status, reason, i;
42
 
43
 DEBUG(D_tls)
44
   debug_printf("tls_ocsp_file (%s)  '%s'\n", is_pem ? "PEM" : "DER", filename);
45
 
46
 if (!filename || !*filename) return;
47
 
48
@@ -1372,28 +1373,28 @@ if ((status = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL)
49
 if (!(basic_response = OCSP_response_get1_basic(resp)))
50
   {
51
   DEBUG(D_tls)
52
     debug_printf("OCSP response parse error: unable to extract basic response.\n");
53
   goto bad;
54
   }
55
 
56
-sk = state->verify_stack;
57
-verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
58
+sk = state->verify_stack;	/* set by setup_certs() / chain_from_pem_file() */
59
 
60
 /* May need to expose ability to adjust those flags?
61
 OCSP_NOSIGS OCSP_NOVERIFY OCSP_NOCHAIN OCSP_NOCHECKS OCSP_NOEXPLICIT
62
 OCSP_TRUSTOTHER OCSP_NOINTERN */
63
 
64
-/* This does a full verify on the OCSP proof before we load it for serving
65
-up; possibly overkill - just date-checks might be nice enough.
66
+/* This does a partial verify (only the signer link, not the whole chain-to-CA)
67
+on the OCSP proof before we load it for serving up; possibly overkill -
68
+just date-checks might be nice enough.
69
 
70
 OCSP_basic_verify takes a "store" arg, but does not
71
-use it for the chain verification, which is all we do
72
-when OCSP_NOVERIFY is set.  The content from the wire
73
-"basic_response" and a cert-stack "sk" are all that is used.
74
+use it for the chain verification, when OCSP_NOVERIFY is set.
75
+The content from the wire "basic_response" and a cert-stack "sk" are all
76
+that is used.
77
 
78
 We have a stack, loaded in setup_certs() if tls_verify_certificates
79
 was a file (not a directory, or "system").  It is unfortunate we
80
 cannot used the connection context store, as that would neatly
81
 handle the "system" case too, but there seems to be no library
82
 function for getting a stack from a store.
83
 [ In OpenSSL 1.1 - ?  X509_STORE_CTX_get0_chain(ctx) ? ]
84
@@ -1402,15 +1403,15 @@ SNI handling.
85
 
86
 Separately we might try to replace using OCSP_basic_verify() - which seems to not
87
 be a public interface into the OpenSSL library (there's no manual entry) -
88
 But what with?  We also use OCSP_basic_verify in the client stapling callback.
89
 And there we NEED it; we must verify that status... unless the
90
 library does it for us anyway?  */
91
 
92
-if ((i = OCSP_basic_verify(basic_response, sk, NULL, verify_flags)) < 0)
93
+if ((i = OCSP_basic_verify(basic_response, sk, NULL, OCSP_NOVERIFY)) < 0)
94
   {
95
   DEBUG(D_tls)
96
     {
97
     ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
98
     debug_printf("OCSP response verify failure: %s\n", US ssl_errstring);
99
     }
100
   goto bad;
101
@@ -1747,61 +1748,18 @@ if (opt_unset_or_noexpand(tls_eccurve))
102
   if (init_ecdh(ctx, &dummy_errstr))
103
     state_server.lib_state.ecdh = TRUE;
104
   }
105
 else
106
   DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n");
107
 
108
 #if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
109
-/* If we can, preload the server-side cert, key and ocsp */
110
-
111
-if (  opt_set_and_noexpand(tls_certificate)
112
-# ifndef DISABLE_OCSP
113
-   && opt_unset_or_noexpand(tls_ocsp_file)
114
-#endif
115
-   && opt_unset_or_noexpand(tls_privatekey))
116
-  {
117
-  /* Set watches on the filenames.  The implementation does de-duplication
118
-  so we can just blindly do them all.  */
119
-
120
-  if (  tls_set_watch(tls_certificate, TRUE)
121
-# ifndef DISABLE_OCSP
122
-     && tls_set_watch(tls_ocsp_file, TRUE)
123
-#endif
124
-     && tls_set_watch(tls_privatekey, TRUE))
125
-    {
126
-    state_server.certificate = tls_certificate;
127
-    state_server.privatekey = tls_privatekey;
128
-#ifndef DISABLE_OCSP
129
-    state_server.u_ocsp.server.file = tls_ocsp_file;
130
-#endif
131
-
132
-    DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
133
-    if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
134
-      state_server.lib_state.conn_certs = TRUE;
135
-    }
136
-  }
137
-else if (  !tls_certificate && !tls_privatekey
138
-# ifndef DISABLE_OCSP
139
-	&& !tls_ocsp_file
140
-#endif
141
-   )
142
-  {		/* Generate & preload a selfsigned cert. No files to watch. */
143
-  if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
144
-    {
145
-    state_server.lib_state.conn_certs = TRUE;
146
-    lifetime = f.running_in_test_harness ? 2 : 60 * 60;		/* 1 hour */
147
-    }
148
-  }
149
-else
150
-  DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
151
-
152
-
153
 /* If we can, preload the Authorities for checking client certs against.
154
 Actual choice to do verify is made (tls_{,try_}verify_hosts)
155
-at TLS conn startup */
156
+at TLS conn startup.
157
+Do this before the server ocsp so that its info can verify the ocsp. */
158
 
159
 if (  opt_set_and_noexpand(tls_verify_certificates)
160
    && opt_unset_or_noexpand(tls_crl))
161
   {
162
   /* Watch the default dir also as they are always included */
163
 
164
   if (  tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
165
@@ -1809,18 +1767,63 @@ if (  opt_set_and_noexpand(tls_verify_certificates)
166
      && tls_set_watch(tls_crl, FALSE))
167
     {
168
     DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
169
 
170
     if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr)
171
 	== OK)
172
       state_server.lib_state.cabundle = TRUE;
173
-    }
174
+
175
+    /* If we can, preload the server-side cert, key and ocsp */
176
+
177
+    if (  opt_set_and_noexpand(tls_certificate)
178
+# ifndef DISABLE_OCSP
179
+       && opt_unset_or_noexpand(tls_ocsp_file)
180
+# endif
181
+       && opt_unset_or_noexpand(tls_privatekey))
182
+      {
183
+      /* Set watches on the filenames.  The implementation does de-duplication
184
+      so we can just blindly do them all.  */
185
+
186
+      if (  tls_set_watch(tls_certificate, TRUE)
187
+# ifndef DISABLE_OCSP
188
+	 && tls_set_watch(tls_ocsp_file, TRUE)
189
+# endif
190
+	 && tls_set_watch(tls_privatekey, TRUE))
191
+	{
192
+	state_server.certificate = tls_certificate;
193
+	state_server.privatekey = tls_privatekey;
194
+#ifndef DISABLE_OCSP
195
+	state_server.u_ocsp.server.file = tls_ocsp_file;
196
+# endif
197
+
198
+	DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
199
+	if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
200
+	  state_server.lib_state.conn_certs = TRUE;
201
+	}
202
+      }
203
+    else if (  !tls_certificate && !tls_privatekey
204
+# ifndef DISABLE_OCSP
205
+	    && !tls_ocsp_file
206
+# endif
207
+       )
208
+      {		/* Generate & preload a selfsigned cert. No files to watch. */
209
+      if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
210
+	{
211
+	state_server.lib_state.conn_certs = TRUE;
212
+	lifetime = f.running_in_test_harness ? 2 : 60 * 60;		/* 1 hour */
213
+	}
214
+      }
215
+    else
216
+      DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
217
+	}
218
   }
219
 else
220
   DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n");
221
+
222
+
223
 #endif	/* EXIM_HAVE_INOTIFY */
224
 
225
 
226
 /* If we can, preload the ciphers control string */
227
 
228
 if (opt_set_and_noexpand(tls_require_ciphers))
229
   {
230
-- 
231
2.35.1
232
(-)a/mail/exim/files/debian/75_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch (-931 lines)
Removed Link Here
1
From dd19ce4f24eec64177cdcfcf294b8efbb631a24b Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Wed, 17 Nov 2021 17:19:54 +0000
4
Subject: [PATCH] select() -> poll().  Bug 2831
5
6
---
7
 doc/ChangeLog     |   8 +++
8
 src/daemon.c          | 126 +++++++++++++++++++-------------------
9
 src/deliver.c         |  54 ++++++++--------
10
 src/exim.c            |   9 +--
11
 src/expand.c          |   6 +-
12
 src/functions.h       |   7 +++
13
 src/ip.c              |  12 +---
14
 src/malware.c         |   6 +-
15
 src/receive.c         |  15 +----
16
 src/smtp_in.c         |  18 +-----
17
 src/spam.c            |  42 ++++---------
18
 src/transport.c       |   4 +-
19
 src/transports/smtp.c |  37 ++++-------
20
 13 files changed, 142 insertions(+), 202 deletions(-)
21
22
diff --git a/doc/ChangeLog b/doc/ChangeLog
23
index 7f6814d5e..58996c3f8 100644
24
--- a/doc/ChangeLog
25
+++ b/doc/ChangeLog
26
@@ -40,6 +40,14 @@ JH/09 Fix macro-definition during "-be" expansion testing.  The move to
27
       write-protected store for macros had not accounted for these runtime
28
       additions; fix by removing this protection for "-be" mode.
29
 
30
+JH/10 Convert all uses of select() to poll().  FreeBSD 12.2 was found to be
31
+      handing out large-numbered file descriptors, violating the usual Unix
32
+      assumption (and required by Posix) that the lowest possible number will be
33
+      allocated by the kernel when a new one is needed.  In the daemon, and any
34
+      child procesees, values higher than 1024 (being bigger than FD_SETSIZE)
35
+      are not useable for FD_SET() [and hence select()] and overwrite the stack.
36
+      Assorted crashes happen.
37
+
38
 
39
 Exim version 4.95
40
 -----------------
41
diff --git a/src/daemon.c b/src/daemon.c
42
index 0b8d5d595..a248a4f40 100644
43
--- a/src/daemon.c
44
+++ b/src/daemon.c
45
@@ -87,7 +87,7 @@ sigchld_seen = TRUE;
46
 }
47
 
48
 
49
-/* SIGTERM handler.  Try to get the damon pif file removed
50
+/* SIGTERM handler.  Try to get the damon pid file removed
51
 before exiting. */
52
 
53
 static void
54
@@ -141,7 +141,7 @@ Uunlink(s);
55
 
56
 static void
57
 close_daemon_sockets(int daemon_notifier_fd,
58
-  int * listen_sockets, int listen_socket_count)
59
+  struct pollfd * fd_polls, int listen_socket_count)
60
 {
61
 if (daemon_notifier_fd >= 0)
62
   {
63
@@ -152,7 +152,7 @@ if (daemon_notifier_fd >= 0)
64
 #endif
65
   }
66
 
67
-for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]);
68
+for (int i = 0; i < listen_socket_count; i++) (void) close(fd_polls[i].fd);
69
 }
70
 
71
 
72
@@ -167,7 +167,7 @@ is required so that they can be closed in the sub-process. Take care not to
73
 leak store in this process - reset the stacking pool at the end.
74
 
75
 Arguments:
76
-  listen_sockets        sockets which are listening for incoming calls
77
+  fd_polls        sockets which are listening for incoming calls
78
   listen_socket_count   count of listening sockets
79
   accept_socket         socket of the current accepted call
80
   accepted              socket information about the current call
81
@@ -176,7 +176,7 @@ Returns:            nothing
82
 */
83
 
84
 static void
85
-handle_smtp_call(int *listen_sockets, int listen_socket_count,
86
+handle_smtp_call(struct pollfd *fd_polls, int listen_socket_count,
87
   int accept_socket, struct sockaddr *accepted)
88
 {
89
 pid_t pid;
90
@@ -459,7 +459,7 @@ if (pid == 0)
91
   extensive comment before the reception loop in exim.c for a fuller
92
   explanation of this logic. */
93
 
94
-  close_daemon_sockets(daemon_notifier_fd, listen_sockets, listen_socket_count);
95
+  close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
96
 
97
   /* Set FD_CLOEXEC on the SMTP socket. We don't want any rogue child processes
98
   to be able to communicate with them, under any circumstances. */
99
@@ -1305,13 +1305,6 @@ return FALSE;
100
 
101
 
102
 
103
-static void
104
-add_listener_socket(int fd, fd_set * fds, int * fd_max)
105
-{
106
-FD_SET(fd, fds);
107
-if (fd > *fd_max) *fd_max = fd;
108
-}
109
-
110
 /*************************************************
111
 *              Exim Daemon Mainline              *
112
 *************************************************/
113
@@ -1339,9 +1332,8 @@ void
114
 daemon_go(void)
115
 {
116
 struct passwd * pw;
117
-int * listen_sockets = NULL;
118
-int listen_socket_count = 0, listen_fd_max = 0;
119
-fd_set select_listen;
120
+struct pollfd * fd_polls, * tls_watch_poll = NULL, * dnotify_poll = NULL;
121
+int listen_socket_count = 0, poll_fd_count;
122
 ip_address_item * addresses = NULL;
123
 time_t last_connection_time = (time_t)0;
124
 int local_queue_run_max = atoi(CS expand_string(queue_run_max));
125
@@ -1353,17 +1345,21 @@ debugging lines get the pid added. */
126
 
127
 DEBUG(D_any|D_v) debug_selector |= D_pid;
128
 
129
-FD_ZERO(&select_listen);
130
+/* Allocate enough pollstructs for inetd mode plus the ancillary sockets;
131
+also used when there are no listen sockets. */
132
+
133
+fd_polls = store_get(sizeof(struct pollfd) * 3, FALSE);
134
+
135
 if (f.inetd_wait_mode)
136
   {
137
   listen_socket_count = 1;
138
-  listen_sockets = store_get(sizeof(int), FALSE);
139
   (void) close(3);
140
   if (dup2(0, 3) == -1)
141
     log_write(0, LOG_MAIN|LOG_PANIC_DIE,
142
         "failed to dup inetd socket safely away: %s", strerror(errno));
143
 
144
-  listen_sockets[0] = 3;
145
+  fd_polls[0].fd = 3;
146
+  fd_polls[0].events = POLLIN;
147
   (void) close(0);
148
   (void) close(1);
149
   (void) close(2);
150
@@ -1390,9 +1386,6 @@ if (f.inetd_wait_mode)
151
     if (setsockopt(3, IPPROTO_TCP, TCP_NODELAY, US &on, sizeof(on)))
152
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to set socket NODELAY: %s",
153
 	strerror(errno));
154
-
155
-  FD_SET(3, &select_listen);
156
-  listen_fd_max = 3;
157
   }
158
 
159
 
160
@@ -1686,11 +1679,16 @@ if (f.daemon_listen && !f.inetd_wait_mode)
161
         }
162
     }
163
 
164
-  /* Get a vector to remember all the sockets in */
165
+  /* Get a vector to remember all the sockets in.
166
+  Two extra elements for the ancillary sockets */
167
 
168
   for (ipa = addresses; ipa; ipa = ipa->next)
169
     listen_socket_count++;
170
-  listen_sockets = store_get(sizeof(int) * listen_socket_count, FALSE);
171
+  fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2),
172
+			    FALSE);
173
+  for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2;
174
+       p++)
175
+    { p->fd = -1; p->events = POLLIN; }
176
 
177
   } /* daemon_listen but not inetd_wait_mode */
178
 
179
@@ -1795,7 +1793,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
180
       wildcard = ipa->address[0] == 0;
181
       }
182
 
183
-    if ((listen_sockets[sk] = fd = ip_socket(SOCK_STREAM, af)) < 0)
184
+    if ((fd_polls[sk].fd = fd = ip_socket(SOCK_STREAM, af)) < 0)
185
       {
186
       if (check_special_case(0, addresses, ipa, FALSE))
187
         {
188
@@ -1804,7 +1802,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
189
         goto SKIP_SOCKET;
190
         }
191
       log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
192
-        (af == AF_INET6)? '6' : '4', strerror(errno));
193
+        af == AF_INET6 ? '6' : '4', strerror(errno));
194
       }
195
 
196
     /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
197
@@ -1903,8 +1901,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)
198
 	f.tcp_fastopen_ok = FALSE;
199
 	}
200
 #endif
201
-
202
-      add_listener_socket(fd, &select_listen, &listen_fd_max);
203
+      fd_polls[sk].fd = fd;
204
       continue;
205
       }
206
 
207
@@ -2187,14 +2184,21 @@ tls_daemon_init();
208
 
209
 /* Add ancillary sockets to the set for select */
210
 
211
+poll_fd_count = listen_socket_count;
212
 #ifndef DISABLE_TLS
213
 if (tls_watch_fd >= 0)
214
-  add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max);
215
+  {
216
+  tls_watch_poll = &fd_polls[poll_fd_count++];
217
+  tls_watch_poll->fd = tls_watch_fd;
218
+  tls_watch_poll->events = POLLIN;
219
+  }
220
 #endif
221
 if (daemon_notifier_fd >= 0)
222
-  add_listener_socket(daemon_notifier_fd, &select_listen, &listen_fd_max);
223
-
224
-listen_fd_max++;
225
+  {
226
+  dnotify_poll = &fd_polls[poll_fd_count++];
227
+  dnotify_poll->fd = daemon_notifier_fd;
228
+  dnotify_poll->events = POLLIN;
229
+  }
230
 
231
 /* Close the log so it can be renamed and moved. In the few cases below where
232
 this long-running process writes to the log (always exceptional conditions), it
233
@@ -2293,7 +2297,7 @@ for (;;)
234
           /* Close any open listening sockets in the child */
235
 
236
 	  close_daemon_sockets(daemon_notifier_fd,
237
-	    listen_sockets, listen_socket_count);
238
+	    fd_polls, listen_socket_count);
239
 
240
           /* Reset SIGHUP and SIGCHLD in the child in both cases. */
241
 
242
@@ -2421,9 +2425,8 @@ for (;;)
243
 
244
   if (f.daemon_listen)
245
     {
246
-    int check_lsk = 0, lcount;
247
+    int lcount;
248
     BOOL select_failed = FALSE;
249
-    fd_set fds = select_listen;
250
 
251
     DEBUG(D_any) debug_printf("Listening...\n");
252
 
253
@@ -2440,8 +2443,7 @@ for (;;)
254
       errno = EINTR;
255
       }
256
     else
257
-      lcount = select(listen_fd_max, (SELECT_ARG2_TYPE *)&fds,
258
-        NULL, NULL, NULL);
259
+      lcount = poll(fd_polls, poll_fd_count, -1);
260
 
261
     if (lcount < 0)
262
       {
263
@@ -2461,15 +2463,15 @@ for (;;)
264
       handle_ending_processes();
265
 
266
 #ifndef DISABLE_TLS
267
+      {
268
+      int old_tfd;
269
       /* Create or rotate any required keys; handle (delayed) filewatch event */
270
-      for (int old_tfd = tls_daemon_tick(); old_tfd >= 0; )
271
-	{
272
-	FD_CLR(old_tfd, &select_listen);
273
-	if (old_tfd == listen_fd_max - 1) listen_fd_max = old_tfd;
274
-	if (tls_watch_fd >= 0)
275
-	  add_listener_socket(tls_watch_fd, &select_listen, &listen_fd_max);
276
-	break;
277
-	}
278
+
279
+      if ((old_tfd = tls_daemon_tick()) >= 0)
280
+	for (struct pollfd * p = &fd_polls[listen_socket_count];
281
+	     p < fd_polls + poll_fd_count; p++)
282
+	  if (p->fd == old_tfd) { p->fd = tls_watch_fd ; break; }
283
+      }
284
 #endif
285
       errno = select_errno;
286
       }
287
@@ -2490,22 +2492,23 @@ for (;;)
288
       if (!select_failed)
289
 	{
290
 #if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
291
-	if (tls_watch_fd >= 0 && FD_ISSET(tls_watch_fd, &fds))
292
+	if (tls_watch_poll && tls_watch_poll->revents & POLLIN)
293
 	  {
294
+	  tls_watch_poll->revents = 0;
295
           tls_watch_trigger_time = time(NULL);	/* Set up delayed event */
296
 	  tls_watch_discard_event(tls_watch_fd);
297
 	  break;	/* to top of daemon loop */
298
 	  }
299
 #endif
300
-	if (daemon_notifier_fd >= 0 && FD_ISSET(daemon_notifier_fd, &fds))
301
+	if (dnotify_poll && dnotify_poll->revents & POLLIN)
302
 	  {
303
+	  dnotify_poll->revents = 0;
304
 	  sigalrm_seen = daemon_notification();
305
 	  break;	/* to top of daemon loop */
306
 	  }
307
-	while (check_lsk < listen_socket_count)
308
-	  {
309
-	  int lfd = listen_sockets[check_lsk++];
310
-          if (FD_ISSET(lfd, &fds))
311
+	for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count;
312
+	     p++)
313
+	  if (p->revents & POLLIN)
314
             {
315
 	    EXIM_SOCKLEN_T alen = sizeof(accepted);
316
 #ifdef TCP_INFO
317
@@ -2516,23 +2519,23 @@ for (;;)
318
 
319
 	    smtp_listen_backlog = 0;
320
 	    if (  smtp_backlog_monitor > 0
321
-	       && getsockopt(lfd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0)
322
+	       && getsockopt(p->fd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0)
323
 	      {
324
 # ifdef EXIM_HAVE_TCPI_UNACKED
325
 	      DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
326
-		      lfd, ti.tcpi_sacked, ti.tcpi_unacked);
327
+		      p->fd, ti.tcpi_sacked, ti.tcpi_unacked);
328
 	      smtp_listen_backlog = ti.tcpi_unacked;
329
 # elif defined(__FreeBSD__)	/* This does not work. Investigate kernel sourcecode. */
330
 	      DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
331
-		      lfd, ti.__tcpi_sacked, ti.__tcpi_unacked);
332
+		      p->fd, ti.__tcpi_sacked, ti.__tcpi_unacked);
333
 	      smtp_listen_backlog = ti.__tcpi_unacked;
334
 # endif
335
 	      }
336
 #endif
337
-            accept_socket = accept(lfd, (struct sockaddr *)&accepted, &alen);
338
+	    p->revents = 0;
339
+            accept_socket = accept(p->fd, (struct sockaddr *)&accepted, &alen);
340
             break;
341
             }
342
-	  }
343
 	}
344
 
345
       /* If select or accept has failed and this was not caused by an
346
@@ -2591,7 +2594,7 @@ for (;;)
347
 #endif
348
         if (inetd_wait_timeout)
349
           last_connection_time = time(NULL);
350
-        handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,
351
+        handle_smtp_call(fd_polls, listen_socket_count, accept_socket,
352
           (struct sockaddr *)&accepted);
353
         }
354
       }
355
@@ -2606,10 +2609,8 @@ for (;;)
356
 
357
   else
358
     {
359
-    struct timeval tv;
360
-    tv.tv_sec = queue_interval;
361
-    tv.tv_usec = 0;
362
-    select(0, NULL, NULL, NULL, &tv);
363
+    struct pollfd p;
364
+    poll(&p, 0, queue_interval * 1000);
365
     handle_ending_processes();
366
     }
367
 
368
@@ -2634,8 +2635,7 @@ for (;;)
369
     {
370
     log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
371
       getpid());
372
-    close_daemon_sockets(daemon_notifier_fd,
373
-      listen_sockets, listen_socket_count);
374
+    close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
375
     ALARM_CLR(0);
376
     signal(SIGHUP, SIG_IGN);
377
     sighup_argv[0] = exim_path;
378
diff --git a/src/deliver.c b/src/deliver.c
379
index 4594c4a1d..8aad811c6 100644
380
--- a/src/deliver.c
381
+++ b/src/deliver.c
382
@@ -74,6 +74,7 @@ static BOOL update_spool;
383
 static BOOL remove_journal;
384
 static int  parcount = 0;
385
 static pardata *parlist = NULL;
386
+static struct pollfd *parpoll;
387
 static int  return_count;
388
 static uschar *frozen_info = US"";
389
 static uschar *used_return_path = NULL;
390
@@ -3306,7 +3307,7 @@ BOOL done = p->done;
391
 
392
 /* Loop through all items, reading from the pipe when necessary. The pipe
393
 used to be non-blocking. But I do not see a reason for using non-blocking I/O
394
-here, as the preceding select() tells us, if data is available for reading.
395
+here, as the preceding poll() tells us, if data is available for reading.
396
 
397
 A read() on a "selected" handle should never block, but(!) it may return
398
 less data then we expected. (The buffer size we pass to read() shouldn't be
399
@@ -3840,7 +3841,7 @@ static address_item *
400
 par_wait(void)
401
 {
402
 int poffset, status;
403
-address_item *addr, *addrlist;
404
+address_item * addr, * addrlist;
405
 pid_t pid;
406
 
407
 set_process_info("delivering %s: waiting for a remote delivery subprocess "
408
@@ -3850,18 +3851,18 @@ set_process_info("delivering %s: waiting for a remote delivery subprocess "
409
 existence - in which case give an error return. We cannot proceed just by
410
 waiting for a completion, because a subprocess may have filled up its pipe, and
411
 be waiting for it to be emptied. Therefore, if no processes have finished, we
412
-wait for one of the pipes to acquire some data by calling select(), with a
413
+wait for one of the pipes to acquire some data by calling poll(), with a
414
 timeout just in case.
415
 
416
 The simple approach is just to iterate after reading data from a ready pipe.
417
 This leads to non-ideal behaviour when the subprocess has written its final Z
418
 item, closed the pipe, and is in the process of exiting (the common case). A
419
-call to waitpid() yields nothing completed, but select() shows the pipe ready -
420
+call to waitpid() yields nothing completed, but poll() shows the pipe ready -
421
 reading it yields EOF, so you end up with busy-waiting until the subprocess has
422
 actually finished.
423
 
424
 To avoid this, if all the data that is needed has been read from a subprocess
425
-after select(), an explicit wait() for it is done. We know that all it is doing
426
+after poll(), an explicit wait() for it is done. We know that all it is doing
427
 is writing to the pipe and then exiting, so the wait should not be long.
428
 
429
 The non-blocking waitpid() is to some extent just insurance; if we could
430
@@ -3881,9 +3882,7 @@ for (;;)   /* Normally we do not repeat this loop */
431
   {
432
   while ((pid = waitpid(-1, &status, WNOHANG)) <= 0)
433
     {
434
-    struct timeval tv;
435
-    fd_set select_pipes;
436
-    int maxpipe, readycount;
437
+    int readycount;
438
 
439
     /* A return value of -1 can mean several things. If errno != ECHILD, it
440
     either means invalid options (which we discount), or that this process was
441
@@ -3907,7 +3906,7 @@ for (;;)   /* Normally we do not repeat this loop */
442
     subprocesses are still in existence. If kill() gives an OK return, we know
443
     it must be for one of our processes - it can't be for a re-use of the pid,
444
     because if our process had finished, waitpid() would have found it. If any
445
-    of our subprocesses are in existence, we proceed to use select() as if
446
+    of our subprocesses are in existence, we proceed to use poll() as if
447
     waitpid() had returned zero. I think this is safe. */
448
 
449
     if (pid < 0)
450
@@ -3931,7 +3930,7 @@ for (;;)   /* Normally we do not repeat this loop */
451
       if (poffset >= remote_max_parallel)
452
         {
453
         DEBUG(D_deliver) debug_printf("*** no delivery children found\n");
454
-        return NULL;   /* This is the error return */
455
+	return NULL;	/* This is the error return */
456
         }
457
       }
458
 
459
@@ -3940,28 +3939,23 @@ for (;;)   /* Normally we do not repeat this loop */
460
     subprocess, but there are no completed subprocesses. See if any pipes are
461
     ready with any data for reading. */
462
 
463
-    DEBUG(D_deliver) debug_printf("selecting on subprocess pipes\n");
464
+    DEBUG(D_deliver) debug_printf("polling subprocess pipes\n");
465
 
466
-    maxpipe = 0;
467
-    FD_ZERO(&select_pipes);
468
     for (poffset = 0; poffset < remote_max_parallel; poffset++)
469
       if (parlist[poffset].pid != 0)
470
-        {
471
-        int fd = parlist[poffset].fd;
472
-        FD_SET(fd, &select_pipes);
473
-        if (fd > maxpipe) maxpipe = fd;
474
-        }
475
+	{
476
+	parpoll[poffset].fd = parlist[poffset].fd;
477
+	parpoll[poffset].events = POLLIN;
478
+	}
479
+      else
480
+	parpoll[poffset].fd = -1;
481
 
482
     /* Stick in a 60-second timeout, just in case. */
483
 
484
-    tv.tv_sec = 60;
485
-    tv.tv_usec = 0;
486
-
487
-    readycount = select(maxpipe + 1, (SELECT_ARG2_TYPE *)&select_pipes,
488
-         NULL, NULL, &tv);
489
+    readycount = poll(parpoll, remote_max_parallel, 60 * 1000);
490
 
491
     /* Scan through the pipes and read any that are ready; use the count
492
-    returned by select() to stop when there are no more. Select() can return
493
+    returned by poll() to stop when there are no more. Select() can return
494
     with no processes (e.g. if interrupted). This shouldn't matter.
495
 
496
     If par_read_pipe() returns TRUE, it means that either the terminating Z was
497
@@ -3978,7 +3972,7 @@ for (;;)   /* Normally we do not repeat this loop */
498
          poffset++)
499
       {
500
       if (  (pid = parlist[poffset].pid) != 0
501
-         && FD_ISSET(parlist[poffset].fd, &select_pipes)
502
+	 && parpoll[poffset].revents
503
 	 )
504
         {
505
         readycount--;
506
@@ -4016,7 +4010,7 @@ for (;;)   /* Normally we do not repeat this loop */
507
     "transport process list", pid);
508
   }  /* End of the "for" loop */
509
 
510
-/* Come here when all the data was completely read after a select(), and
511
+/* Come here when all the data was completely read after a poll(), and
512
 the process in pid has been wait()ed for. */
513
 
514
 PROCESS_DONE:
515
@@ -4051,7 +4045,7 @@ if ((status & 0xffff) != 0)
516
     "%s %d",
517
     addrlist->transport->driver_name,
518
     status,
519
-    (msb == 0)? "terminated by signal" : "exit code",
520
+    msb == 0 ? "terminated by signal" : "exit code",
521
     code);
522
 
523
   if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT))
524
@@ -4069,7 +4063,8 @@ if ((status & 0xffff) != 0)
525
 /* Else complete reading the pipe to get the result of the delivery, if all
526
 the data has not yet been obtained. */
527
 
528
-else if (!parlist[poffset].done) (void)par_read_pipe(poffset, TRUE);
529
+else if (!parlist[poffset].done)
530
+  (void) par_read_pipe(poffset, TRUE);
531
 
532
 /* Put the data count and return path into globals, mark the data slot unused,
533
 decrement the count of subprocesses, and return the address chain. */
534
@@ -4218,6 +4213,7 @@ if (!parlist)
535
   parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
536
   for (poffset = 0; poffset < remote_max_parallel; poffset++)
537
     parlist[poffset].pid = 0;
538
+  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), FALSE);
539
   }
540
 
541
 /* Now loop for each remote delivery */
542
@@ -4613,7 +4609,7 @@ nonmatch domains
543
     that it can use either of them, though it prefers O_NONBLOCK, which
544
     distinguishes between EOF and no-more-data. */
545
 
546
-/* The data appears in a timely manner and we already did a select on
547
+/* The data appears in a timely manner and we already did a poll on
548
 all pipes, so I do not see a reason to use non-blocking IO here
549
 
550
 #ifdef O_NONBLOCK
551
diff --git a/src/exim.c b/src/exim.c
552
index 133761de9..42db457c0 100644
553
--- a/src/exim.c
554
+++ b/src/exim.c
555
@@ -5735,13 +5735,8 @@ for (BOOL more = TRUE; more; )
556
     the file copy. */
557
 
558
     if (!receive_timeout)
559
-      {
560
-      struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 };	/* 30 minutes */
561
-      fd_set r;
562
-
563
-      FD_ZERO(&r); FD_SET(0, &r);
564
-      if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
565
-      }
566
+      if (poll_one_fd(0, POLLIN, 30*60*1000) == 0)	/* 30 minutes */
567
+	mainlog_close();
568
 
569
     /* Read the data for the message. If filter_test is not FTEST_NONE, this
570
     will just read the headers for the message, and not write anything onto the
571
diff --git a/src/expand.c b/src/expand.c
572
index 59554840e..bfae2a3c0 100644
573
--- a/src/expand.c
574
+++ b/src/expand.c
575
@@ -1760,8 +1760,6 @@ const uschar * where;
576
 #ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
577
 uschar * sname;
578
 #endif
579
-fd_set fds;
580
-struct timeval tv;
581
 
582
 if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
583
   {
584
@@ -1805,9 +1803,7 @@ if (connect(fd, (const struct sockaddr *)&sa_un, len) < 0)
585
 buf[0] = NOTIFY_QUEUE_SIZE_REQ;
586
 if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
587
 
588
-FD_ZERO(&fds); FD_SET(fd, &fds);
589
-tv.tv_sec = 2; tv.tv_usec = 0;
590
-if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1)
591
+if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1)
592
   {
593
   DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
594
   len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
595
diff --git a/src/functions.h b/src/functions.h
596
index 3dd890a00..0cf80dfbb 100644
597
--- a/src/functions.h
598
+++ b/src/functions.h
599
@@ -1255,6 +1255,13 @@ child_open(uschar **argv, uschar **envp, int newumask, int *infdptr,
600
   outfdptr, make_leader, purpose);
601
 }
602
 
603
+static inline int
604
+poll_one_fd(int fd, short pollbits, int tmo_millisec)
605
+{
606
+struct pollfd p = {.fd = fd, .events = pollbits};
607
+return poll(&p, 1, tmo_millisec);
608
+}
609
+
610
 # endif	/* !COMPILE_UTILITY */
611
 
612
 /******************************************************************************/
613
diff --git a/src/ip.c b/src/ip.c
614
index d83d6f910..aa42343fb 100644
615
--- a/src/ip.c
616
+++ b/src/ip.c
617
@@ -589,9 +589,7 @@ Returns:      TRUE => ready for i/o
618
 BOOL
619
 fd_ready(int fd, time_t timelimit)
620
 {
621
-fd_set select_inset;
622
-int time_left = timelimit - time(NULL);
623
-int rc;
624
+int rc, time_left = timelimit - time(NULL);
625
 
626
 if (time_left <= 0)
627
   {
628
@@ -602,12 +600,8 @@ if (time_left <= 0)
629
 
630
 do
631
   {
632
-  struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 };
633
-  FD_ZERO (&select_inset);
634
-  FD_SET (fd, &select_inset);
635
-
636
   /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
637
-  rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv);
638
+  rc = poll_one_fd(fd, POLLIN, time_left * 1000);
639
 
640
   /* If some interrupt arrived, just retry. We presume this to be rare,
641
   but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes
642
@@ -636,7 +630,7 @@ do
643
   /* Checking the FD_ISSET is not enough, if we're interrupted, the
644
   select_inset may still contain the 'input'. */
645
   }
646
-while (rc < 0 || !FD_ISSET(fd, &select_inset));
647
+while (rc < 0);
648
 return TRUE;
649
 }
650
 
651
diff --git a/src/malware.c b/src/malware.c
652
index 10a390dfa..d9ab3b9dd 100644
653
--- a/src/malware.c
654
+++ b/src/malware.c
655
@@ -277,11 +277,7 @@ int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
656
 /* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
657
 and, getting no response, wait for a long time.  Impose a 5s max. */
658
 if (fd >= 0)
659
-  {
660
-  struct timeval tv = {.tv_sec = 5};
661
-  fd_set fds;
662
-  FD_ZERO(&fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv);
663
-  }
664
+  (void) poll_one_fd(fd, POLLOUT, 5 * 1000);
665
 #endif
666
 return fd;
667
 }
668
diff --git a/src/receive.c b/src/receive.c
669
index fab0f00c4..3adcbbd88 100644
670
--- a/src/receive.c
671
+++ b/src/receive.c
672
@@ -624,12 +624,8 @@ if (!receive_timeout && !receive_hasc())
673
   if (t.tv_sec > 30*60)
674
     mainlog_close();
675
   else
676
-    {
677
-    fd_set r;
678
-    FD_ZERO(&r); FD_SET(0, &r);
679
-    t.tv_sec = 30*60 - t.tv_sec; t.tv_usec = 0;
680
-    if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
681
-    }
682
+    if (poll_one_fd(0, POLLIN, (30*60 - t.tv_sec) * 1000) == 0)
683
+      mainlog_close();
684
   }
685
 }
686
 
687
@@ -4234,12 +4230,7 @@ response, but the chance of this happening should be small. */
688
 if (smtp_input && sender_host_address && !f.sender_host_notsocket &&
689
     !receive_smtp_buffered())
690
   {
691
-  struct timeval tv = {.tv_sec = 0, .tv_usec = 0};
692
-  fd_set select_check;
693
-  FD_ZERO(&select_check);
694
-  FD_SET(fileno(smtp_in), &select_check);
695
-
696
-  if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
697
+  if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0)
698
     {
699
     int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
700
     if (c != EOF) (receive_ungetc)(c); else
701
diff --git a/src/smtp_in.c b/src/smtp_in.c
702
index 824178e4d..7cb966f24 100644
703
--- a/src/smtp_in.c
704
+++ b/src/smtp_in.c
705
@@ -346,8 +346,6 @@ static BOOL
706
 wouldblock_reading(void)
707
 {
708
 int fd, rc;
709
-fd_set fds;
710
-struct timeval tzero = {.tv_sec = 0, .tv_usec = 0};
711
 
712
 #ifndef DISABLE_TLS
713
 if (tls_in.active.sock >= 0)
714
@@ -358,9 +356,7 @@ if (smtp_inptr < smtp_inend)
715
   return FALSE;
716
 
717
 fd = fileno(smtp_in);
718
-FD_ZERO(&fds);
719
-FD_SET(fd, &fds);
720
-rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero);
721
+rc = poll_one_fd(fd, POLLIN, 0);
722
 
723
 if (rc <= 0) return TRUE;     /* Not ready to read */
724
 rc = smtp_getc(GETC_BUFFER_UNLIMITED);
725
@@ -3942,16 +3938,8 @@ log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
726
 /* Pause, hoping client will FIN first so that they get the TIME_WAIT.
727
 The socket should become readble (though with no data) */
728
 
729
-  {
730
-  int fd = fileno(smtp_in);
731
-  fd_set fds;
732
-  struct timeval t_limit = {.tv_sec = 0, .tv_usec = 200*1000};
733
-
734
-  FD_ZERO(&fds);
735
-  FD_SET(fd, &fds);
736
-  (void) select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &t_limit);
737
-  }
738
-#endif	/*!DAEMON_CLOSE_NOWAIT*/
739
+(void) poll_one_fd(fileno(smtp_in), POLLIN, 200);
740
+#endif	/*!SERVERSIDE_CLOSE_NOWAIT*/
741
 }
742
 
743
 
744
diff --git a/src/spam.c b/src/spam.c
745
index 470e5fae7..e3316ed96 100644
746
--- a/src/spam.c
747
+++ b/src/spam.c
748
@@ -194,12 +194,6 @@ uschar *p,*q;
749
 int override = 0;
750
 time_t start;
751
 size_t read, wrote;
752
-#ifndef NO_POLL_H
753
-struct pollfd pollfd;
754
-#else                               /* Patch posted by Erik ? for OS X */
755
-struct timeval select_tv;         /* and applied by PH */
756
-fd_set select_fd;
757
-#endif
758
 uschar *spamd_address_work;
759
 spamd_address_container * sd;
760
 
761
@@ -395,19 +389,19 @@ if (wrote == -1)
762
   }
763
 
764
 /* now send the file */
765
-/* spamd sometimes accepts connections but doesn't read data off
766
- * the connection.  We make the file descriptor non-blocking so
767
- * that the write will only write sufficient data without blocking
768
- * and we poll the descriptor to make sure that we can write without
769
- * blocking.  Short writes are gracefully handled and if the whole
770
- * transaction takes too long it is aborted.
771
- * Note: poll() is not supported in OSX 10.2 and is reported to be
772
- *       broken in more recent versions (up to 10.4).
773
+/* spamd sometimes accepts connections but doesn't read data off the connection.
774
+We make the file descriptor non-blocking so that the write will only write
775
+sufficient data without blocking and we poll the descriptor to make sure that we
776
+can write without blocking.  Short writes are gracefully handled and if the
777
+whole transaction takes too long it is aborted.
778
+
779
+Note: poll() is not supported in OSX 10.2 and is reported to be broken in more
780
+      recent versions (up to 10.4). Workaround using select() removed 2021/11 (jgh).
781
  */
782
-#ifndef NO_POLL_H
783
-pollfd.fd = spamd_cctx.sock;
784
-pollfd.events = POLLOUT;
785
+#ifdef NO_POLL_H
786
+# error Need poll(2) support
787
 #endif
788
+
789
 (void)fcntl(spamd_cctx.sock, F_SETFL, O_NONBLOCK);
790
 do
791
   {
792
@@ -416,19 +410,7 @@ do
793
     {
794
     offset = 0;
795
 again:
796
-#ifndef NO_POLL_H
797
-    result = poll(&pollfd, 1, 1000);
798
-
799
-/* Patch posted by Erik ? for OS X and applied by PH */
800
-#else
801
-    select_tv.tv_sec = 1;
802
-    select_tv.tv_usec = 0;
803
-    FD_ZERO(&select_fd);
804
-    FD_SET(spamd_cctx.sock, &select_fd);
805
-    result = select(spamd_cctx.sock+1, NULL, &select_fd, NULL, &select_tv);
806
-#endif
807
-/* End Erik's patch */
808
-
809
+    result = poll_one_fd(spamd_cctx.sock, POLLOUT, 1000);
810
     if (result == -1 && errno == EINTR)
811
       goto again;
812
     else if (result < 1)
813
diff --git a/src/transport.c b/src/transport.c
814
index 8c74030f0..ef523657e 100644
815
--- a/src/transport.c
816
+++ b/src/transport.c
817
@@ -253,7 +253,6 @@ for (int i = 0; i < 100; i++)
818
 
819
   for(;;)
820
     {
821
-    fd_set fds;
822
     /* This code makes use of alarm() in order to implement the timeout. This
823
     isn't a very tidy way of doing things. Using non-blocking I/O with select()
824
     provides a neater approach. However, I don't know how to do this when TLS is
825
@@ -281,8 +280,7 @@ for (int i = 0; i < 100; i++)
826
     if (rc >= 0 || errno != ENOTCONN || connretry <= 0)
827
       break;
828
 
829
-    FD_ZERO(&fds); FD_SET(fd, &fds);
830
-    select(fd+1, NULL, &fds, NULL, NULL);	/* could set timout? */
831
+    poll_one_fd(fd, POLLOUT, -1);		/* could set timeout? retval check? */
832
     connretry--;
833
     }
834
 
835
diff --git a/src/transports/smtp.c b/src/transports/smtp.c
836
index d321bd69e..c64bb7010 100644
837
--- a/src/transports/smtp.c
838
+++ b/src/transports/smtp.c
839
@@ -3550,8 +3550,8 @@ void
840
 smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd,
841
   int timeout)
842
 {
843
-fd_set rfds, efds;
844
-int max_fd = MAX(pfd[0], tls_out.active.sock) + 1;
845
+struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN},
846
+		      {.fd = pfd[0], .events = POLLIN}};
847
 int rc, i;
848
 BOOL send_tls_shutdown = TRUE;
849
 
850
@@ -3560,23 +3560,16 @@ if ((rc = exim_fork(US"tls-proxy")))
851
   _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
852
 
853
 set_process_info("proxying TLS connection for continued transport");
854
-FD_ZERO(&rfds);
855
-FD_SET(tls_out.active.sock, &rfds);
856
-FD_SET(pfd[0], &rfds);
857
 
858
-for (int fd_bits = 3; fd_bits; )
859
+do
860
   {
861
   time_t time_left = timeout;
862
   time_t time_start = time(NULL);
863
 
864
   /* wait for data */
865
-  efds = rfds;
866
   do
867
     {
868
-    struct timeval tv = { time_left, 0 };
869
-
870
-    rc = select(max_fd,
871
-      (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv);
872
+    rc = poll(p, 2, time_left * 1000);
873
 
874
     if (rc < 0 && errno == EINTR)
875
       if ((time_left -= time(NULL) - time_start) > 0) continue;
876
@@ -3589,23 +3582,22 @@ for (int fd_bits = 3; fd_bits; )
877
 
878
     /* For errors where not readable, bomb out */
879
 
880
-    if (FD_ISSET(tls_out.active.sock, &efds) || FD_ISSET(pfd[0], &efds))
881
+    if (p[0].revents & POLLERR || p[1].revents & POLLERR)
882
       {
883
       DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
884
-	FD_ISSET(pfd[0], &efds) ? "proxy" : "tls");
885
-      if (!(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds)))
886
+	p[0].revents & POLLERR ? "tls" : "proxy");
887
+      if (!(p[0].revents & POLLIN || p[1].events & POLLIN))
888
 	goto done;
889
       DEBUG(D_transport) debug_printf("- but also readable; no exit yet\n");
890
       }
891
     }
892
-  while (rc < 0 || !(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds)));
893
+  while (rc < 0 || !(p[0].revents & POLLIN || p[1].revents & POLLIN));
894
 
895
   /* handle inbound data */
896
-  if (FD_ISSET(tls_out.active.sock, &rfds))
897
+  if (p[0].revents & POLLIN)
898
     if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0)	/* Expect -1 for EOF; */
899
     {				    /* that reaps the TLS Close Notify record */
900
-      fd_bits &= ~1;
901
-      FD_CLR(tls_out.active.sock, &rfds);
902
+      p[0].fd = -1;
903
       shutdown(pfd[0], SHUT_WR);
904
       timeout = 5;
905
       }
906
@@ -3616,11 +3608,10 @@ for (int fd_bits = 3; fd_bits; )
907
   /* Handle outbound data.  We cannot combine payload and the TLS-close
908
   due to the limitations of the (pipe) channel feeding us.  Maybe use a unix-domain
909
   socket? */
910
-  if (FD_ISSET(pfd[0], &rfds))
911
+  if (p[1].revents & POLLIN)
912
     if ((rc = read(pfd[0], buf, bsize)) <= 0)
913
       {
914
-      fd_bits &= ~2;
915
-      FD_CLR(pfd[0], &rfds);
916
+      p[1].fd = -1;
917
 
918
 # ifdef EXIM_TCP_CORK  /* Use _CORK to get TLS Close Notify in FIN segment */
919
       (void) setsockopt(tls_out.active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
920
@@ -3633,10 +3624,8 @@ for (int fd_bits = 3; fd_bits; )
921
       for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
922
 	if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0)
923
 	  goto done;
924
-
925
-  if (fd_bits & 1) FD_SET(tls_out.active.sock, &rfds);
926
-  if (fd_bits & 2) FD_SET(pfd[0], &rfds);
927
   }
928
+while (p[0].fd >= 0 || p[1].fd >= 0);
929
 
930
 done:
931
   if (send_tls_shutdown) tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT);
(-)b/mail/exim/files/debian/75_38-OpenSSL-fix-double-expansion-of-tls_verify_certifica.patch (+217 lines)
Added Link Here
1
From 62b97c2ecf148ee86053d82e5509e4c3a5a20054 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sat, 29 Oct 2022 22:33:43 +0100
4
Subject: [PATCH 2/2] OpenSSL: fix double-expansion of tls_verify_certificates
5
6
---
7
 src/tls-openssl.c | 66 +++++++++++++++++++++----------------------
8
 1 file changed, 33 insertions(+), 33 deletions(-)
9
10
diff --git a/src/tls-openssl.c b/src/tls-openssl.c
11
index fdf0d92b2..2e09882d2 100644
12
--- a/src/tls-openssl.c
13
+++ b/src/tls-openssl.c
14
@@ -435,15 +435,15 @@ typedef struct exim_openssl_state {
15
 /* should figure out a cleanup of API to handle state preserved per
16
 implementation, for various reasons, which can be void * in the APIs.
17
 For now, we hack around it. */
18
 exim_openssl_state_st *client_static_state = NULL;	/*XXX should not use static; multiple concurrent clients! */
19
 exim_openssl_state_st state_server = {.is_server = TRUE};
20
 
21
 static int
22
-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
23
+setup_certs(SSL_CTX * sctx, uschar ** certs, uschar * crl, host_item * host,
24
     uschar ** errstr );
25
 
26
 /* Callbacks */
27
 #ifndef DISABLE_OCSP
28
 static int tls_server_stapling_cb(SSL *s, void *arg);
29
 static void x509_stack_dump_cert_s_names(const STACK_OF(X509) * sk);
30
 static void x509_store_dump_cert_s_names(X509_STORE * store);
31
@@ -1762,18 +1762,18 @@ if (  opt_set_and_noexpand(tls_verify_certificates)
32
   {
33
   /* Watch the default dir also as they are always included */
34
 
35
   if (  tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
36
      && tls_set_watch(tls_verify_certificates, FALSE)
37
      && tls_set_watch(tls_crl, FALSE))
38
     {
39
+    uschar * v_certs = tls_verify_certificates;
40
     DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
41
 
42
-    if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr)
43
-	== OK)
44
+    if (setup_certs(ctx, &v_certs, tls_crl, NULL, &dummy_errstr) == OK)
45
       state_server.lib_state.cabundle = TRUE;
46
 
47
     /* If we can, preload the server-side cert, key and ocsp */
48
 
49
     if (  opt_set_and_noexpand(tls_certificate)
50
 # ifndef DISABLE_OCSP
51
        && opt_unset_or_noexpand(tls_ocsp_file)
52
@@ -1897,18 +1897,19 @@ if (  opt_set_and_noexpand(ob->tls_verify_certificates)
53
   {
54
   if (  !watch
55
      ||    tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
56
         && tls_set_watch(ob->tls_verify_certificates, FALSE)
57
 	&& tls_set_watch(ob->tls_crl, FALSE)
58
      )
59
     {
60
+    uschar * v_certs = ob->tls_verify_certificates;
61
     DEBUG(D_tls)
62
       debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
63
 
64
-    if (setup_certs(ctx, ob->tls_verify_certificates,
65
+    if (setup_certs(ctx, &v_certs,
66
 	  ob->tls_crl, dummy_host, &dummy_errstr) == OK)
67
       ob->tls_preload.cabundle = TRUE;
68
     }
69
   }
70
 else
71
   DEBUG(D_tls)
72
       debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
73
@@ -2238,22 +2239,20 @@ if (state->u_ocsp.server.file)
74
   {
75
   SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
76
   SSL_CTX_set_tlsext_status_arg(server_sni, state);
77
   }
78
 #endif
79
 
80
   {
81
-  uschar * expcerts;
82
-  if (  !expand_check(tls_verify_certificates, US"tls_verify_certificates",
83
-		  &expcerts, &dummy_errstr)
84
-     || (rc = setup_certs(server_sni, expcerts, tls_crl, NULL,
85
+  uschar * v_certs = tls_verify_certificates;
86
+  if ((rc = setup_certs(server_sni, &v_certs, tls_crl, NULL,
87
 			&dummy_errstr)) != OK)
88
     goto bad;
89
 
90
-  if (expcerts && *expcerts)
91
+  if (v_certs && *v_certs)
92
     setup_cert_verify(server_sni, FALSE, verify_callback_server);
93
   }
94
 
95
 /* do this after setup_certs, because this can require the certs for verifying
96
 OCSP information. */
97
 if ((rc = tls_expand_session_files(server_sni, state, &dummy_errstr)) != OK)
98
   goto bad;
99
@@ -3017,32 +3016,33 @@ return TRUE;
100
 
101
 
102
 /* Called by both client and server startup; on the server possibly
103
 repeated after a Server Name Indication.
104
 
105
 Arguments:
106
   sctx          SSL_CTX* to initialise
107
-  certs         certs file, expanded
108
+  certs         certs file, returned expanded
109
   crl           CRL file or NULL
110
   host          NULL in a server; the remote host in a client
111
   errstr	error string pointer
112
 
113
 Returns:        OK/DEFER/FAIL
114
 */
115
 
116
 static int
117
-setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
118
+setup_certs(SSL_CTX * sctx, uschar ** certsp, uschar * crl, host_item * host,
119
     uschar ** errstr)
120
 {
121
-uschar *expcerts, *expcrl;
122
+uschar * expcerts, * expcrl;
123
 
124
-if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr))
125
+if (!expand_check(*certsp, US"tls_verify_certificates", &expcerts, errstr))
126
   return DEFER;
127
 DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
128
 
129
+*certsp = expcerts;
130
 if (expcerts && *expcerts)
131
   {
132
   /* Tell the library to use its compiled-in location for the system default
133
   CA bundle. Then add the ones specified in the config, if any. */
134
 
135
   if (!SSL_CTX_set_default_verify_paths(sctx))
136
     return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr);
137
@@ -3330,28 +3330,28 @@ if (verify_check_host(&tls_verify_hosts) == OK)
138
   server_verify_optional = FALSE;
139
 else if (verify_check_host(&tls_try_verify_hosts) == OK)
140
   server_verify_optional = TRUE;
141
 else
142
   goto skip_certs;
143
 
144
  {
145
-  uschar * expcerts;
146
-  if (!expand_check(tls_verify_certificates, US"tls_verify_certificates",
147
-		    &expcerts, errstr))
148
-    return DEFER;
149
-  DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
150
+  uschar * v_certs = tls_verify_certificates;
151
 
152
   if (state_server.lib_state.cabundle)
153
-    { DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); }
154
+    {
155
+    DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n");
156
+    setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
157
+    }
158
   else
159
-    if ((rc = setup_certs(ctx, expcerts, tls_crl, NULL, errstr)) != OK)
160
+    {
161
+    if ((rc = setup_certs(ctx, &v_certs, tls_crl, NULL, errstr)) != OK)
162
       return rc;
163
-
164
-  if (expcerts && *expcerts)
165
-    setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
166
+    if (v_certs && *v_certs)
167
+      setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
168
+    }
169
  }
170
 skip_certs: ;
171
 
172
 #ifndef DISABLE_TLS_RESUME
173
 # if OPENSSL_VERSION_NUMBER < 0x30000000L
174
 SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback);
175
 /* despite working, appears to always return failure, so ignoring */
176
@@ -3606,28 +3606,28 @@ if (  (  (  !ob->tls_verify_hosts || !ob->tls_verify_hosts
177
   client_verify_optional = FALSE;
178
 else if (verify_check_given_host(CUSS &ob->tls_try_verify_hosts, host) == OK)
179
   client_verify_optional = TRUE;
180
 else
181
   return OK;
182
 
183
  {
184
-  uschar * expcerts;
185
-  if (!expand_check(ob->tls_verify_certificates, US"tls_verify_certificates",
186
-		    &expcerts, errstr))
187
-    return DEFER;
188
-  DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
189
+  uschar * v_certs = ob->tls_verify_certificates;
190
 
191
   if (state->lib_state.cabundle)
192
-    { DEBUG(D_tls) debug_printf("TLS: CA bundle was preloaded\n"); }
193
+    {
194
+    DEBUG(D_tls) debug_printf("TLS: CA bundle for tpt was preloaded\n");
195
+    setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
196
+    }
197
   else
198
-    if ((rc = setup_certs(ctx, expcerts, ob->tls_crl, host, errstr)) != OK)
199
+    {
200
+    if ((rc = setup_certs(ctx, &v_certs, ob->tls_crl, host, errstr)) != OK)
201
       return rc;
202
-
203
-  if (expcerts && *expcerts)
204
-    setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
205
+    if (v_certs && *v_certs)
206
+      setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
207
+    }
208
  }
209
 
210
 if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
211
   {
212
   state->verify_cert_hostnames =
213
 #ifdef SUPPORT_I18N
214
     string_domain_utf8_to_alabel(host->certname, NULL);
215
-- 
216
2.35.1
217
(-)a/mail/exim/files/debian/75_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch (-140 lines)
Removed Link Here
1
From d73b9f478a2a5b299634acee4e05ff8ea25375a2 Mon Sep 17 00:00:00 2001
2
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
3
Date: Sun, 28 Nov 2021 17:26:40 +0000
4
Subject: [PATCH] Fix basic memory use for SPARC.  Bug 2838
5
6
---
7
 doc/ChangeLog |  5 +++++
8
 src/store.c       | 34 +++++++++++++++++++---------------
9
 src/store.h       |  2 +-
10
 3 files changed, 25 insertions(+), 16 deletions(-)
11
12
--- a/doc/ChangeLog
13
+++ b/doc/ChangeLog
14
@@ -14,6 +14,11 @@
15
       are not useable for FD_SET() [and hence select()] and overwrite the stack.
16
       Assorted crashes happen.
17
 
18
+JH/12 Bug 2838: Fix for i32lp64 hard-align platforms. Found for SPARC Linux,
19
+      though only once PCRE2 was introduced: the memory accounting used under
20
+      debug offset allocations by an int, giving a hard trap in early startup.
21
+      Change to using a size_t.  Debug and fix by John Paul Adrian Glaubitz.
22
+
23
 
24
 Exim version 4.95
25
 -----------------
26
--- a/src/store.c
27
+++ b/src/store.c
28
@@ -190,11 +190,11 @@
29
 [POOL_TAINT_MESSAGE] =	US"tainted",
30
 };
31
 #endif
32
 
33
 
34
-static void * internal_store_malloc(int, const char *, int);
35
+static void * internal_store_malloc(size_t, const char *, int);
36
 static void   internal_store_free(void *, const char *, int linenumber);
37
 
38
 /******************************************************************************/
39
 /* Initialisation, for things fragile with parameter channges when using
40
 static initialisers. */
41
@@ -859,30 +859,33 @@
42
 
43
 Returns:      pointer to gotten store (panic on failure)
44
 */
45
 
46
 static void *
47
-internal_store_malloc(int size, const char *func, int line)
48
+internal_store_malloc(size_t size, const char *func, int line)
49
 {
50
 void * yield;
51
 
52
-if (size < 0 || size >= INT_MAX/2)
53
+/* Check specifically for a possibly result of conversion from
54
+a negative int, to the (unsigned, wider) size_t */
55
+
56
+if (size >= INT_MAX/2)
57
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
58
-            "bad memory allocation requested (%d bytes) at %s %d",
59
-            size, func, line);
60
+            "bad memory allocation requested (%lld bytes) at %s %d",
61
+            (unsigned long long)size, func, line);
62
 
63
-size += sizeof(int);	/* space to store the size, used under debug */
64
+size += sizeof(size_t);	/* space to store the size, used under debug */
65
 if (size < 16) size = 16;
66
 
67
-if (!(yield = malloc((size_t)size)))
68
+if (!(yield = malloc(size)))
69
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: "
70
     "called from line %d in %s", size, line, func);
71
 
72
 #ifndef COMPILE_UTILITY
73
-DEBUG(D_any) *(int *)yield = size;
74
+DEBUG(D_any) *(size_t *)yield = size;
75
 #endif
76
-yield = US yield + sizeof(int);
77
+yield = US yield + sizeof(size_t);
78
 
79
 if ((nonpool_malloc += size) > max_nonpool_malloc)
80
   max_nonpool_malloc = nonpool_malloc;
81
 
82
 /* Cut out the debugging stuff for utilities, but stop picky compilers from
83
@@ -891,20 +894,20 @@
84
 #ifndef COMPILE_UTILITY
85
 /* If running in test harness, spend time making sure all the new store
86
 is not filled with zeros so as to catch problems. */
87
 
88
 if (f.running_in_test_harness)
89
-  memset(yield, 0xF0, (size_t)size - sizeof(int));
90
-DEBUG(D_memory) debug_printf("--Malloc %6p %5d bytes\t%-20s %4d\tpool %5d  nonpool %5d\n",
91
+  memset(yield, 0xF0, size - sizeof(size_t));
92
+DEBUG(D_memory) debug_printf("--Malloc %6p %5lld bytes\t%-20s %4d\tpool %5d  nonpool %5d\n",
93
   yield, size, func, line, pool_malloc, nonpool_malloc);
94
 #endif  /* COMPILE_UTILITY */
95
 
96
 return yield;
97
 }
98
 
99
 void *
100
-store_malloc_3(int size, const char *func, int linenumber)
101
+store_malloc_3(size_t size, const char *func, int linenumber)
102
 {
103
 if (n_nonpool_blocks++ > max_nonpool_blocks)
104
   max_nonpool_blocks = n_nonpool_blocks;
105
 return internal_store_malloc(size, func, linenumber);
106
 }
107
@@ -925,14 +928,15 @@
108
 */
109
 
110
 static void
111
 internal_store_free(void * block, const char * func, int linenumber)
112
 {
113
-uschar * p = US block - sizeof(int);
114
+uschar * p = US block - sizeof(size_t);
115
 #ifndef COMPILE_UTILITY
116
-DEBUG(D_any) nonpool_malloc -= *(int *)p;
117
-DEBUG(D_memory) debug_printf("----Free %6p %5d bytes\t%-20s %4d\n", block, *(int *)p, func, linenumber);
118
+DEBUG(D_any) nonpool_malloc -= *(size_t *)p;
119
+DEBUG(D_memory) debug_printf("----Free %6p %5lld bytes\t%-20s %4d\n",
120
+		    block, (unsigned long long) *(size_t *)p, func, linenumber);
121
 #endif
122
 free(p);
123
 }
124
 
125
 void
126
--- a/src/store.h
127
+++ b/src/store.h
128
@@ -63,11 +63,11 @@
129
 typedef void ** rmark;
130
 
131
 extern BOOL    store_extend_3(void *, BOOL, int, int, const char *, int);
132
 extern void    store_free_3(void *, const char *, int);
133
 /* store_get_3 & store_get_perm_3 are in local_scan.h */
134
-extern void   *store_malloc_3(int, const char *, int)		ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
135
+extern void   *store_malloc_3(size_t, const char *, int)		ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
136
 extern rmark   store_mark_3(const char *, int);
137
 extern void   *store_newblock_3(void *, BOOL, int, int, const char *, int);
138
 extern void    store_release_above_3(void *, const char *, int);
139
 extern rmark   store_reset_3(rmark, const char *, int);
140
 
(-)a/mail/exim/files/debian/75_43-BSD-fix-resource-leak.patch (-61 lines)
Removed Link Here
1
From c57309a50444d858c0a2dc1581846a850d78a9ad Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Tue, 11 Jan 2022 11:21:45 +0000
4
Subject: [PATCH 077/151] BSD: fix resource leak
5
6
---
7
 doc/ChangeLog | 4 ++++
8
 src/tls.c         | 9 +++++----
9
10
diff --git a/doc/ChangeLog b/doc/ChangeLog
11
index e7c7085f8..567399483 100644
12
--- a/doc/ChangeLog
13
+++ b/doc/ChangeLog
14
@@ -65,6 +65,10 @@ JH/13 Bug 2845: Fix handling of tls_require_ciphers for OpenSSL when a value
15
 
16
 JH/14 Bug 1895: TLS: Deprecate RFC 5114 Diffie-Hellman parameters.
17
 
18
+JH/15 Fix a resource leak in *BSD.  An off-by-one error resulted in the daemon
19
+      failing to close the certificates directory, every hour or any time it
20
+      was touched.
21
+
22
 
23
 Exim version 4.95
24
 -----------------
25
diff --git a/src/tls.c b/src/tls.c
26
index d5d11bcea..e6b1bf7a7 100644
27
--- a/src/tls.c
28
+++ b/src/tls.c
29
@@ -185,8 +185,8 @@ for (;;)
30
     {
31
     if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0)
32
       { s = US"open file"; goto bad; }
33
-    DEBUG(D_tls) debug_printf("watch file '%s'\n", filename);
34
-    EV_SET(&kev[++kev_used],
35
+    DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1);
36
+    EV_SET(&kev[kev_used++],
37
 	(uintptr_t)fd1,
38
 	EVFILT_VNODE,
39
 	EV_ADD | EV_ENABLE | EV_ONESHOT,
40
@@ -196,8 +196,8 @@ for (;;)
41
 	NULL);
42
     cnt++;
43
     }
44
-  DEBUG(D_tls) debug_printf("watch dir  '%s'\n", s);
45
-  EV_SET(&kev[++kev_used],
46
+  DEBUG(D_tls) debug_printf("watch dir  '%s':\t%d\n", s, fd2);
47
+  EV_SET(&kev[kev_used++],
48
 	(uintptr_t)fd2,
49
 	EVFILT_VNODE,
50
 	EV_ADD | EV_ENABLE | EV_ONESHOT,
51
@@ -320,6 +320,7 @@ if (tls_watch_fd < 0) return;
52
 /* Close the files we had open for kevent */
53
 for (int i = 0; i < kev_used; i++)
54
   {
55
+  DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident);
56
   (void) close((int) kev[i].ident);
57
   kev[i].ident = (uintptr_t)-1;
58
   }
59
-- 
60
2.35.1
61
(-)a/mail/exim/files/debian/75_45-Fix-bogus-error-message-copy.-Bug-2857.patch (-38 lines)
Removed Link Here
1
From 7ad863f3819407559cd654639c25dcae427c190f Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sun, 6 Feb 2022 19:00:26 +0000
4
Subject: [PATCH] Fix bogus error message copy.  Bug 2857
5
6
Broken-by: bb43acbd98
7
---
8
 src/parse.c | 9 +++++----
9
 1 file changed, 5 insertions(+), 4 deletions(-)
10
11
diff --git a/src/parse.c b/src/parse.c
12
index 5bf97eab9..edbee2646 100644
13
--- a/src/parse.c
14
+++ b/src/parse.c
15
@@ -1354,15 +1354,16 @@ for (;;)
16
 
17
   if (special)
18
     {
19
-    uschar *ss = Ustrchr(s+1, ':') + 1;
20
+    uschar * ss = Ustrchr(s+1, ':') + 1; /* line after the special... */
21
     if ((options & specopt) == specbit)
22
       {
23
       *error = string_sprintf("\"%.*s\" is not permitted", len, s);
24
       return FF_ERROR;
25
       }
26
-    while (*ss && isspace(*ss)) ss++;
27
-    while (s[len] && s[len] != '\n') len++;
28
-    *error = string_copyn(ss, s + len - ss);
29
+    while (*ss && isspace(*ss)) ss++;	/* skip leading whitespace */
30
+    if ((len = Ustrlen(ss)) > 0)	/* ignore trailing newlines */
31
+      for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--;
32
+    *error = string_copyn(ss, len);	/* becomes the error */
33
     return special;
34
     }
35
 
36
-- 
37
2.34.1
38
(-)a/mail/exim/files/debian/75_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch (-62 lines)
Removed Link Here
1
From 7f8394e7c983b1c199866fc6b1c14feb857b651d Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sun, 13 Feb 2022 12:00:55 +0000
4
Subject: [PATCH] Fix include_directory in redirect routers.  Bug 2715
5
6
Broken-by: 10c50704c1
7
---
8
 doc/ChangeLog        | 5 +++++
9
 src/parse.c              | 9 ++++++---
10
 test/confs/0313              | 4 +++-
11
 test/log/0313                | 2 ++
12
 test/scripts/0000-Basic/0313 | 2 ++
13
 5 files changed, 18 insertions(+), 4 deletions(-)
14
15
--- a/doc/ChangeLog
16
+++ b/doc/ChangeLog
17
@@ -23,6 +23,11 @@ JH/15 Fix a resource leak in *BSD.  An off-by-one erro
18
       failing to close the certificates directory, every hour or any time it
19
       was touched.
20
 
21
+JH/18 Bug 2751: Fix include_directory in redirect routers.  Previously a
22
+      bad comparison between the option value and the name of the file to
23
+      be included was done, and a mismatch was wrongly identified.
24
+      4.88 to 4.95 are affected.
25
+
26
 
27
 Exim version 4.95
28
 -----------------
29
--- a/src/parse.c
30
+++ b/src/parse.c
31
@@ -1422,11 +1422,13 @@
32
     /* Check file name if required */
33
 
34
     if (directory)
35
       {
36
       int len = Ustrlen(directory);
37
-      uschar *p = filename + len;
38
+      uschar * p;
39
+      while (len > 0 && directory[len-1] == '/') len--;		/* ignore trailing '/' */
40
+      p = filename + len;
41
 
42
       if (Ustrncmp(filename, directory, len) != 0 || *p != '/')
43
         {
44
         *error = string_sprintf("included file %s is not in directory %s",
45
           filename, directory);
46
@@ -1448,13 +1450,14 @@
47
 	}
48
       while (*p)
49
 	{
50
 	uschar temp;
51
 	int fd2;
52
-	uschar * q = p;
53
+	uschar * q = p + 1;		/* skip dividing '/' */
54
 
55
-	while (*++p && *p != '/') ;
56
+	while (*q == '/') q++;		/* skip extra '/' */
57
+	while (*++p && *p != '/') ;	/* end of component */
58
 	temp = *p;
59
 	*p = '\0';
60
 
61
 	fd2 = exim_openat(fd, CS q, O_RDONLY|O_NOFOLLOW);
62
 	close(fd);
(-)b/mail/exim/files/debian/75_50-Fix-logging-of-max-size-log-line.patch (+82 lines)
Added Link Here
1
From 1ed24e36e279c922d3366f6c3144570cc5f54d7a Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Mon, 19 Dec 2022 21:09:17 +0000
4
Subject: [PATCH] Fix logging of max-size log line
5
6
Broken-by: d12746bc15d8
7
---
8
 doc/ChangeLog        |  5 +++++
9
 src/log.c                |  7 ++++---
10
 test/confs/0633              | 21 ++++++++++++++++++++
11
 test/scripts/0000-Basic/0633 |  9 +++++++++
12
 test/stderr/0633             | 38 ++++++++++++++++++++++++++++++++++++
13
 test/stdout/0633             | 15 ++++++++++++++
14
 6 files changed, 92 insertions(+), 3 deletions(-)
15
 create mode 100644 test/confs/0633
16
 create mode 100644 test/scripts/0000-Basic/0633
17
 create mode 100644 test/stderr/0633
18
 create mode 100644 test/stdout/0633
19
20
--- a/doc/ChangeLog
21
+++ b/doc/ChangeLog
22
@@ -28,10 +28,15 @@ JH/13 Bug 2929: Fix using $recipients af
23
 JH/14 Bug 2933: Fix regex substring match variables for null matches. Since 4.96
24
       a capture group which obtained no text (eg. "(abc)*" matching zero
25
       occurrences) could cause a segfault if the corresponding $<n> was
26
       expanded.
27
 
28
+JH/18 Fix a fencepost error in logging.  Previously (since 4.92) when a log line
29
+      was exactly sized compared to the log buffer, a crash occurred with the
30
+      misleading message "bad memory reference; pool not found".
31
+      Found and traced by Jasen Betts.
32
+
33
 
34
 
35
 Exim version 4.96
36
 -----------------
37
 
38
--- a/src/log.c
39
+++ b/src/log.c
40
@@ -803,11 +803,11 @@ Returns:    nothing
41
 void
42
 log_write(unsigned int selector, int flags, const char *format, ...)
43
 {
44
 int paniclogfd;
45
 ssize_t written_len;
46
-gstring gs = { .size = LOG_BUFFER_SIZE-1, .ptr = 0, .s = log_buffer };
47
+gstring gs = { .size = LOG_BUFFER_SIZE-2, .ptr = 0, .s = log_buffer };
48
 gstring * g;
49
 va_list ap;
50
 
51
 /* If panic_recurseflag is set, we have failed to open the panic log. This is
52
 the ultimate disaster. First try to write the message to a debug file and/or
53
@@ -949,15 +949,14 @@ DEBUG(D_any|D_v)
54
     g->ptr = i;
55
     g = string_cat(g, US"**** log string overflowed log buffer ****");
56
     }
57
   va_end(ap);
58
 
59
-  g->size = LOG_BUFFER_SIZE;
60
   g = string_catn(g, US"\n", 1);
61
   debug_printf("%s", string_from_gstring(g));
62
 
63
-  gs.size = LOG_BUFFER_SIZE-1;	/* Having used the buffer for debug output, */
64
+  gs.size = LOG_BUFFER_SIZE-2;	/* Having used the buffer for debug output, */
65
   gs.ptr = 0;			/* reset it for the real use. */
66
   gs.s = log_buffer;
67
   }
68
 /* If no log file is specified, we are in a mess. */
69
 
70
@@ -1035,10 +1034,12 @@ if (  flags & LOG_RECIPIENTS
71
     if (LOG_BUFFER_SIZE - g->ptr < Ustrlen(s) + 3) break;
72
     g = string_fmt_append_f(g, SVFMT_TAINT_NOCHK, " %s", s);
73
     }
74
   }
75
 
76
+/* actual size, now we are placing the newline (and space for NUL) */
77
+gs.size = LOG_BUFFER_SIZE;
78
 g = string_catn(g, US"\n", 1);
79
 string_from_gstring(g);
80
 
81
 /* Handle loggable errors when running a utility, or when address testing.
82
 Write to log_stderr unless debugging (when it will already have been written),
(-)b/mail/exim/files/debian/75_55-Fix-recursion-on-dns_again_means_nonexist.-Bug-2911.patch (+76 lines)
Added Link Here
1
From 1d38781da934809e6ce0b8c3718c4b3bccdfe1d2 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Wed, 28 Dec 2022 19:39:06 +0000
4
Subject: [PATCH] Fix recursion on dns_again_means_nonexist. Bug 2911
5
6
---
7
 doc/ChangeLog        |  8 +++++
8
 src/dns.c                | 12 ++++++++
9
 test/confs/2202              | 18 +++++++++--
10
 test/scripts/2200-dnsdb/2202 |  8 +++++
11
 test/stderr/2202             | 58 +++++++++++++++++++++++++++++++++++-
12
 test/stdout/2202             |  8 +++++
13
 6 files changed, 108 insertions(+), 4 deletions(-)
14
15
--- a/doc/ChangeLog
16
+++ b/doc/ChangeLog
17
@@ -33,10 +33,18 @@ JH/14 Bug 2933: Fix regex substring matc
18
 JH/18 Fix a fencepost error in logging.  Previously (since 4.92) when a log line
19
       was exactly sized compared to the log buffer, a crash occurred with the
20
       misleading message "bad memory reference; pool not found".
21
       Found and traced by Jasen Betts.
22
 
23
+JH/19 Bug 2911: Fix a recursion in DNS lookups.  Previously, if the main option
24
+      dns_again_means_nonexist included an element causing a DNS lookup which
25
+      iteslf returned DNS_AGAIN, unbounded recursion occurred.  Possible results
26
+      included (though probably not limited to) a process crash from stack
27
+      memory limit, or from excessive open files.  Replace this with a paniclog
28
+      whine (as this is likely a configuration error), and returning
29
+      DNS_NOMATCH.
30
+
31
 
32
 
33
 Exim version 4.96
34
 -----------------
35
 
36
--- a/src/dns.c
37
+++ b/src/dns.c
38
@@ -799,10 +799,11 @@ int
39
 dns_basic_lookup(dns_answer * dnsa, const uschar * name, int type)
40
 {
41
 int rc;
42
 #ifndef STAND_ALONE
43
 const uschar * save_domain;
44
+static BOOL try_again_recursion = FALSE;
45
 #endif
46
 
47
 /* DNS lookup failures of any kind are cached in a tree. This is mainly so that
48
 a timeout on one domain doesn't happen time and time again for messages that
49
 have many addresses in the same domain. We rely on the resolver and name server
50
@@ -903,15 +904,26 @@ if (dnsa->answerlen < 0) switch (h_errno
51
     DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n",
52
       name, dns_text_type(type));
53
 
54
     /* Cut this out for various test programs */
55
 #ifndef STAND_ALONE
56
+    if (try_again_recursion)
57
+      {
58
+      log_write(0, LOG_MAIN|LOG_PANIC,
59
+	"dns_again_means_nonexist recursion seen for %s (assuming nonexist)",
60
+	name);
61
+      return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH);
62
+      }
63
+
64
+    try_again_recursion = TRUE;
65
     save_domain = deliver_domain;
66
     deliver_domain = string_copy(name);  /* set $domain */
67
     rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
68
       &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
69
     deliver_domain = save_domain;
70
+    try_again_recursion = FALSE;
71
+
72
     if (rc != OK)
73
       {
74
       DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
75
       return dns_fail_return(name, type, 0, DNS_AGAIN);
76
       }
(-)a/mail/exim/files/debian/75_55-Specific-check-for-null-pointer.patch (-67 lines)
Removed Link Here
1
From b249717db8ced250a586385f06e61cf7107d5222 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Fri, 18 Feb 2022 15:45:37 +0000
4
Subject: [PATCH] Specific check for null pointer
5
6
---
7
 src/smtp_out.c | 18 +++++++++++++-----
8
 1 file changed, 13 insertions(+), 5 deletions(-)
9
10
diff --git a/src/smtp_out.c b/src/smtp_out.c
11
index 608a781eb..fc1e6cecd 100644
12
--- a/src/smtp_out.c
13
+++ b/src/smtp_out.c
14
@@ -524,13 +524,21 @@ flush_buffer(smtp_outblock * outblock, int mode)
15
 int rc;
16
 int n = outblock->ptr - outblock->buffer;
17
 BOOL more = mode == SCMD_MORE;
18
+client_conn_ctx * cctx;
19
 
20
 HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
21
   more ? " (more expected)" : "");
22
 
23
+if (!(cctx = outblock->cctx))
24
+  {
25
+  log_write(0, LOG_MAIN|LOG_PANIC, "null conn-context pointer");
26
+  errno = 0;
27
+  return FALSE;
28
+  }
29
+
30
 #ifndef DISABLE_TLS
31
-if (outblock->cctx->tls_ctx)
32
-  rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more);
33
+if (cctx->tls_ctx)		/*XXX have seen a null cctx here, rvfy sending QUIT, hence check above */
34
+  rc = tls_write(cctx->tls_ctx, outblock->buffer, n, more);
35
 else
36
 #endif
37
 
38
@@ -544,7 +552,7 @@ else
39
     requirement: TFO with data can, in rare cases, replay the data to the
40
     receiver. */
41
 
42
-    if (  (outblock->cctx->sock = smtp_connect(outblock->conn_args, &early_data))
43
+    if (  (cctx->sock = smtp_connect(outblock->conn_args, &early_data))
44
        < 0)
45
       return FALSE;
46
     outblock->conn_args = NULL;
47
@@ -552,7 +560,7 @@ else
48
     }
49
   else
50
     {
51
-    rc = send(outblock->cctx->sock, outblock->buffer, n,
52
+    rc = send(cctx->sock, outblock->buffer, n,
53
 #ifdef MSG_MORE
54
 	      more ? MSG_MORE : 0
55
 #else
56
@@ -567,7 +575,7 @@ else
57
     https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */
58
 
59
     if (!more)
60
-      setsockopt(outblock->cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
61
+      setsockopt(cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
62
 #endif
63
     }
64
   }
65
-- 
66
2.34.1
67
(-)b/mail/exim/files/debian/75_58-Close-server-smtp-socket-explicitly-on-connect-ACL-d.patch (+50 lines)
Added Link Here
1
From 57d70161718e02927a22d6a3481803b72035ac46 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sat, 31 Dec 2022 13:37:17 +0000
4
Subject: [PATCH] Close server smtp socket explicitly on connect ACL "drop"
5
6
---
7
 src/smtp_in.c            | 13 ++++++++
8
 test/confs/0022              |  2 ++
9
 test/log/0022                |  2 ++
10
 test/rejectlog/0022          |  3 ++
11
 test/scripts/0000-Basic/0022 | 13 ++++++++
12
 test/stderr/0022             | 60 ++++++++++++++++++------------------
13
 test/stdout/0022             |  6 ++++
14
 7 files changed, 69 insertions(+), 30 deletions(-)
15
 create mode 100644 test/rejectlog/0022
16
17
diff --git a/src/smtp_in.c b/src/smtp_in.c
18
index 1cfcc0404..6880e3c09 100644
19
--- a/src/smtp_in.c
20
+++ b/src/smtp_in.c
21
@@ -3563,10 +3563,23 @@ log_write(L_smtp_connection, LOG_MAIN, "%s closed by DROP in ACL",
22
 /* Run the not-quit ACL, but without any custom messages. This should not be a
23
 problem, because we get here only if some other ACL has issued "drop", and
24
 in that case, *its* custom messages will have been used above. */
25
 
26
 smtp_notquit_exit(US"acl-drop", NULL, NULL);
27
+
28
+/* An overenthusiastic fail2ban/iptables implimentation has been seen to result
29
+in the TCP conn staying open, and retrying, despite this process exiting. A
30
+malicious client could possibly do the same, tying up server netowrking
31
+resources. Close the socket explicitly to try to avoid that (there's a note in
32
+the Linux socket(7) manpage, SO_LINGER para, to the effect that exim() without
33
+close() results in the socket always lingering). */
34
+
35
+(void) poll_one_fd(fileno(smtp_in), POLLIN, 200);
36
+DEBUG(D_any) debug_printf_indent("SMTP(close)>>\n");
37
+(void) fclose(smtp_in);
38
+(void) fclose(smtp_out);
39
+
40
 return 2;
41
 }
42
 
43
 
44
 
45
diff --git a/test/rejectlog/0022 b/test/rejectlog/0022
46
new file mode 100644
47
index 000000000..68e21fff3
48
-- 
49
2.39.0
50
(-)b/mail/exim/files/debian/75_60-OpenSSL-fix-tls_eccurve-setting-explicit-curve-group.patch (+184 lines)
Added Link Here
1
From ca4014de81e6aa367aa0a54c49b4c3d4b137814c Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Sun, 1 Jan 2023 12:18:38 +0000
4
Subject: [PATCH] OpenSSL: fix tls_eccurve setting explicit curve/group.  Bug
5
 2954
6
7
---
8
 doc/ChangeLog          |  4 +++
9
 src/tls-openssl.c          | 39 ++++++++++++++----------
10
 test/confs/2148                | 54 ++++++++++++++++++++++++++++++++++
11
 test/confs/2149                | 39 +++++++++++++-----------
12
 test/log/2148                  | 48 ++++++++++++++++++++++++++++++
13
 test/log/2149                  | 39 ++++++++++++------------
14
 test/paniclog/{2149 => 2148}   |  0
15
 test/scripts/2100-OpenSSL/2148 | 50 +++++++++++++++++++++++++++++++
16
 test/scripts/2100-OpenSSL/2149 | 50 ++++++++++++++++---------------
17
 test/stderr/2148               |  5 ++++
18
 test/stderr/2149               |  3 --
19
 11 files changed, 250 insertions(+), 81 deletions(-)
20
 create mode 100644 test/confs/2148
21
 create mode 100644 test/log/2148
22
 rename test/paniclog/{2149 => 2148} (100%)
23
 create mode 100644 test/scripts/2100-OpenSSL/2148
24
 create mode 100644 test/stderr/2148
25
26
--- a/doc/ChangeLog
27
+++ b/doc/ChangeLog
28
@@ -41,10 +41,14 @@ JH/19 Bug 2911: Fix a recursion in DNS l
29
       included (though probably not limited to) a process crash from stack
30
       memory limit, or from excessive open files.  Replace this with a paniclog
31
       whine (as this is likely a configuration error), and returning
32
       DNS_NOMATCH.
33
 
34
+JH/20 Bug 2954: (OpenSSL) Fix setting of explicit EC curve/group.  Previously
35
+      this always failed, probably leading to the usual downgrade to in-clear
36
+      connections.
37
+
38
 
39
 
40
 Exim version 4.96
41
 -----------------
42
 
43
--- a/src/tls-openssl.c
44
+++ b/src/tls-openssl.c
45
@@ -657,16 +657,16 @@ if (dh_bitsize <= tls_dh_max_bits)
46
     /* EVP_PKEY_free(pkey);  crashes */
47
 #endif
48
     }
49
   else
50
     DEBUG(D_tls)
51
-      debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
52
+      debug_printf(" Diffie-Hellman initialized from %s with %d-bit prime\n",
53
 	dhexpanded ? dhexpanded : US"default", dh_bitsize);
54
   }
55
 else
56
   DEBUG(D_tls)
57
-    debug_printf("dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
58
+    debug_printf(" dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
59
 	dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits);
60
 
61
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
62
 DH_free(dh);
63
 #endif
64
@@ -712,23 +712,31 @@ init_ecdh(SSL_CTX * sctx, uschar ** errs
65
 #ifdef OPENSSL_NO_ECDH
66
 return TRUE;
67
 #else
68
 
69
 uschar * exp_curve;
70
-int nid;
71
-BOOL rv;
72
+int nid, rc;
73
 
74
 # ifndef EXIM_HAVE_ECDH
75
 DEBUG(D_tls)
76
-  debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
77
+  debug_printf(" No OpenSSL API to define ECDH parameters, skipping\n");
78
 return TRUE;
79
 # else
80
 
81
 if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
82
   return FALSE;
83
+
84
+/* Is the option deliberately empty? */
85
+
86
 if (!exp_curve || !*exp_curve)
87
+  {
88
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
89
+  DEBUG(D_tls) debug_printf( " ECDH OpenSSL 1.0.2+: clearing curves list\n");
90
+  (void) SSL_CTX_set1_curves(sctx, &nid, 0);
91
+#endif
92
   return TRUE;
93
+  }
94
 
95
 /* "auto" needs to be handled carefully.
96
  * OpenSSL <  1.0.2: we do not select anything, but fallback to prime256v1
97
  * OpenSSL <  1.1.0: we have to call SSL_CTX_set_ecdh_auto
98
  *                   (openssl/ssl.h defines SSL_CTRL_SET_ECDH_AUTO)
99
@@ -737,27 +745,26 @@ if (!exp_curve || !*exp_curve)
100
  */
101
 if (Ustrcmp(exp_curve, "auto") == 0)
102
   {
103
 #if OPENSSL_VERSION_NUMBER < 0x10002000L
104
   DEBUG(D_tls) debug_printf(
105
-    "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
106
+    " ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
107
   exp_curve = US"prime256v1";
108
 #else
109
 # if defined SSL_CTRL_SET_ECDH_AUTO
110
   DEBUG(D_tls) debug_printf(
111
-    "ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
112
+    " ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
113
   SSL_CTX_set_ecdh_auto(sctx, 1);
114
   return TRUE;
115
 # else
116
   DEBUG(D_tls) debug_printf(
117
-    "ECDH OpenSSL 1.1.0+: temp key parameter settings: default selection\n");
118
+    " ECDH OpenSSL 1.1.0+: temp key parameter settings: library default selection\n");
119
   return TRUE;
120
 # endif
121
 #endif
122
   }
123
 
124
-DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
125
 if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
126
 #   ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
127
    && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
128
 #   endif
129
    )
130
@@ -777,27 +784,27 @@ if (  (nid = OBJ_sn2nid       (CCS exp_c
131
     }
132
 
133
   /* The "tmp" in the name here refers to setting a temporary key
134
   not to the stability of the interface. */
135
 
136
-  if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
137
+  if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
138
     tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
139
   else
140
-    DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
141
+    DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve);
142
   EC_KEY_free(ecdh);
143
  }
144
 
145
 #else	/* v 3.0.0 + */
146
 
147
-if ((rv = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
148
+if ((rc = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
149
   tls_error(string_sprintf("Error enabling '%s' group", exp_curve), NULL, NULL, errstr);
150
 else
151
-  DEBUG(D_tls) debug_printf("ECDH: enabled '%s' group\n", exp_curve);
152
+  DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' group\n", exp_curve);
153
 
154
 #endif
155
 
156
-return !rv;
157
+return !!rc;
158
 
159
 # endif	/*EXIM_HAVE_ECDH*/
160
 #endif /*OPENSSL_NO_ECDH*/
161
 }
162
 
163
@@ -1719,19 +1726,19 @@ state_server.lib_state.lib_ctx = ctx;
164
 
165
 /* Preload DH params and EC curve */
166
 
167
 if (opt_unset_or_noexpand(tls_dhparam))
168
   {
169
-  DEBUG(D_tls) debug_printf("TLS: preloading DH params for server\n");
170
+  DEBUG(D_tls) debug_printf("TLS: preloading DH params '%s' for server\n", tls_dhparam);
171
   if (init_dh(ctx, tls_dhparam, &dummy_errstr))
172
     state_server.lib_state.dh = TRUE;
173
   }
174
 else
175
   DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n");
176
 if (opt_unset_or_noexpand(tls_eccurve))
177
   {
178
-  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n");
179
+  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve '%s' for server\n", tls_eccurve);
180
   if (init_ecdh(ctx, &dummy_errstr))
181
     state_server.lib_state.ecdh = TRUE;
182
   }
183
 else
184
   DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n");
(-)b/mail/exim/files/debian/75_62-OpenSSL-Fix-tls_eccurve-on-earlier-versions-than-3.0.patch (+42 lines)
Added Link Here
1
From 7fa5764c203f2f4a900898a79ed02d674075313f Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Mon, 2 Jan 2023 15:04:14 +0000
4
Subject: [PATCH 1/3] OpenSSL: Fix tls_eccurve on earlier versions than 3.0.0. 
5
 Bug 2954
6
7
Broken-by: ca4014de81e6
8
---
9
 src/tls-openssl.c          |  7 ++++---
10
 test/log/2149                  | 28 ++++++++++++++--------------
11
 test/runtest                   |  3 +++
12
 test/scripts/2100-OpenSSL/2149 | 22 ++++++++++++----------
13
 4 files changed, 33 insertions(+), 27 deletions(-)
14
15
diff --git a/src/tls-openssl.c b/src/tls-openssl.c
16
index 4d0f99ea9..e063d29bd 100644
17
--- a/src/tls-openssl.c
18
+++ b/src/tls-openssl.c
19
@@ -786,8 +786,9 @@ if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
20
 #   endif
21
    )
22
   {
23
-  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
24
-    NULL, NULL, errstr);
25
+  uschar * s = string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve);
26
+  DEBUG(D_tls) debug_printf("TLS error '%s'\n", s);
27
+  if (errstr) *errstr = s;
28
   return FALSE;
29
   }
30
 
31
@@ -803,7 +804,7 @@ if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
32
   /* The "tmp" in the name here refers to setting a temporary key
33
   not to the stability of the interface. */
34
 
35
-  if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
36
+  if ((rc = SSL_CTX_set_tmp_ecdh(sctx, ecdh)) == 0)
37
     tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
38
   else
39
     DEBUG(D_tls) debug_printf(" ECDH: enabled '%s' curve\n", exp_curve);
40
-- 
41
2.39.0
42
(-)b/mail/exim/files/debian/75_63-OpenSSL-log-conns-rejected-for-bad-ALPN-with-the-off.patch (+99 lines)
Added Link Here
1
From e1aca33756f73c22b00a98d40ce2be8ed94464b1 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 5 Jan 2023 13:03:37 +0000
4
Subject: [PATCH 2/3] OpenSSL: log conns rejected for bad ALPN, with the
5
 offered value
6
7
Unfortunately, no way to do this under GnuTLS
8
---
9
 src/match.c       |  1 +
10
 src/tls-gnu.c     |  9 ++++++++-
11
 src/tls-openssl.c | 13 +++++++++++--
12
 test/log/1190         |  2 ++
13
 test/runtest          |  3 +++
14
 5 files changed, 25 insertions(+), 3 deletions(-)
15
16
diff --git a/src/match.c b/src/match.c
17
index 91a49c0f0..07070362d 100644
18
--- a/src/match.c
19
+++ b/src/match.c
20
@@ -968,6 +968,7 @@ Arguments:
21
   s              string to search for
22
   listptr        ptr to ptr to colon separated list of patterns, or NULL
23
   sep            a separator value for the list (see string_nextinlist())
24
+		 or zero for auto
25
   anchorptr      ptr to tree for named items, or NULL if no named items
26
   cache_bits     ptr to cache_bits for ditto, or NULL if not caching
27
   type           MCL_DOMAIN when matching a domain list
28
diff --git a/src/tls-gnu.c b/src/tls-gnu.c
29
index 729fb5879..b47fabf1d 100644
30
--- a/src/tls-gnu.c
31
+++ b/src/tls-gnu.c
32
@@ -1119,21 +1119,28 @@ switch (tls_id)
33
     /* The format of "data" here doesn't seem to be documented, but appears
34
     to be a 2-byte field with a (redundant, given the "size" arg) total length
35
     then a sequence of one-byte size then string (not nul-term) names.  The
36
-    latter is as described in OpenSSL documentation. */
37
+    latter is as described in OpenSSL documentation.
38
+    Note that we do not get called for a match_fail, making it hard to log
39
+    a single bad ALPN being offered (the common case). */
40
+    {
41
+    gstring * g = NULL;
42
 
43
     DEBUG(D_tls) debug_printf("Seen ALPN extension from client (s=%u):", size);
44
     for (const uschar * s = data+2; s-data < size-1; s += *s + 1)
45
       {
46
       server_seen_alpn++;
47
+      g = string_append_listele_n(g, ':', s+1, *s);
48
       DEBUG(D_tls) debug_printf(" '%.*s'", (int)*s, s+1);
49
       }
50
     DEBUG(D_tls) debug_printf("\n");
51
     if (server_seen_alpn > 1)
52
       {
53
+      log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g));
54
       DEBUG(D_tls) debug_printf("TLS: too many ALPNs presented in handshake\n");
55
       return GNUTLS_E_NO_APPLICATION_PROTOCOL;
56
       }
57
     break;
58
+    }
59
 #endif
60
   }
61
 return 0;
62
diff --git a/src/tls-openssl.c b/src/tls-openssl.c
63
index e063d29bd..513ba0d3a 100644
64
--- a/src/tls-openssl.c
65
+++ b/src/tls-openssl.c
66
@@ -2324,6 +2324,8 @@ static int
67
 tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen,
68
   const uschar * in, unsigned int inlen, void * arg)
69
 {
70
+gstring * g = NULL;
71
+
72
 server_seen_alpn = TRUE;
73
 DEBUG(D_tls)
74
   {
75
@@ -2354,12 +2356,19 @@ if (  inlen > 1		/* at least one name */
76
       }
77
   }
78
 
79
-/* More than one name from clilent, or name did not match our list. */
80
+/* More than one name from client, or name did not match our list. */
81
 
82
 /* This will be fatal to the TLS conn; would be nice to kill TCP also.
83
 Maybe as an option in future; for now leave control to the config (must-tls). */
84
 
85
-DEBUG(D_tls) debug_printf("TLS ALPN rejected\n");
86
+for (int pos = 0, siz; pos < inlen; pos += siz+1)
87
+  {
88
+  siz = in[pos];
89
+  if (pos + 1 + siz > inlen) siz = inlen - pos - 1;
90
+  g = string_append_listele_n(g, ':', in + pos + 1, siz);
91
+  }
92
+log_write(0, LOG_MAIN, "TLS ALPN (%s) rejected", string_from_gstring(g));
93
+gstring_release_unused(g);
94
 return SSL_TLSEXT_ERR_ALERT_FATAL;
95
 }
96
 #endif	/* EXIM_HAVE_ALPN */
97
-- 
98
2.39.0
99
(-)b/mail/exim/files/debian/75_64-DANE-do-not-check-dns_again_means_nonexist-for-TLSA-.patch (+96 lines)
Added Link Here
1
From 30520c8f87fcf660ed99a2344cae7f9787f7bc89 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 5 Jan 2023 18:39:51 +0000
4
Subject: [PATCH 3/3] DANE: do not check dns_again_means_nonexist for TLSA
5
 results of TRY_AGAIN
6
7
---
8
 doc/doc-docbook/spec.xfpt |  7 ++++++-
9
 doc/ChangeLog     |  4 ++++
10
 src/dns.c             | 35 ++++++++++++++++++++++-------------
11
 3 files changed, 32 insertions(+), 14 deletions(-)
12
13
--- a/doc/ChangeLog
14
+++ b/doc/ChangeLog
15
@@ -46,10 +46,14 @@ JH/19 Bug 2911: Fix a recursion in DNS l
16
 JH/20 Bug 2954: (OpenSSL) Fix setting of explicit EC curve/group.  Previously
17
       this always failed, probably leading to the usual downgrade to in-clear
18
       connections.
19
 
20
 
21
+JH/20 Fix TLSA lookups.  Previously dns_again_means_nonexist would affect
22
+      SERVFAIL results, which breaks the downgrade resistance of DANE.  Change
23
+      to not checking that list for these looks.
24
+
25
 
26
 Exim version 4.96
27
 -----------------
28
 
29
 JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
30
--- a/src/dns.c
31
+++ b/src/dns.c
32
@@ -904,25 +904,34 @@ if (dnsa->answerlen < 0) switch (h_errno
33
     DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave TRY_AGAIN\n",
34
       name, dns_text_type(type));
35
 
36
     /* Cut this out for various test programs */
37
 #ifndef STAND_ALONE
38
-    if (try_again_recursion)
39
+    /* Permitting dns_again_means nonexist for TLSA lookups breaks the
40
+    doewngrade resistance of dane, so avoid for those. */
41
+
42
+    if (type == T_TLSA)
43
+      rc = FAIL;
44
+    else
45
       {
46
-      log_write(0, LOG_MAIN|LOG_PANIC,
47
-	"dns_again_means_nonexist recursion seen for %s (assuming nonexist)",
48
-	name);
49
-      return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type), DNS_NOMATCH);
50
-      }
51
+      if (try_again_recursion)
52
+	{
53
+	log_write(0, LOG_MAIN|LOG_PANIC,
54
+	  "dns_again_means_nonexist recursion seen for %s"
55
+	  " (assuming nonexist)", name);
56
+	return dns_fail_return(name, type, dns_expire_from_soa(dnsa, type),
57
+			      DNS_NOMATCH);
58
+	}
59
 
60
-    try_again_recursion = TRUE;
61
-    save_domain = deliver_domain;
62
-    deliver_domain = string_copy(name);  /* set $domain */
63
-    rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
64
-      &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
65
-    deliver_domain = save_domain;
66
-    try_again_recursion = FALSE;
67
+      try_again_recursion = TRUE;
68
+      save_domain = deliver_domain;
69
+      deliver_domain = string_copy(name);  /* set $domain */
70
+      rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0,
71
+	&domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL);
72
+      deliver_domain = save_domain;
73
+      try_again_recursion = FALSE;
74
+      }
75
 
76
     if (rc != OK)
77
       {
78
       DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
79
       return dns_fail_return(name, type, 0, DNS_AGAIN);
80
--- a/doc/spec.txt
81
+++ b/doc/spec.txt
82
@@ -14246,11 +14246,13 @@ dns_again_means_nonexist, it is treated
83
 should be used with care. You can make it apply to reverse lookups by a setting
84
 such as this:
85
 
86
 dns_again_means_nonexist = *.in-addr.arpa
87
 
88
-This option applies to all DNS lookups that Exim does. It also applies when the
89
+This option applies to all DNS lookups that Exim does, except for TLSA lookups
90
+(where knowing about such failures +is security-relevant). It also applies
91
+when the
92
 gethostbyname() or getipnodebyname() functions give temporary errors, since
93
 these are most likely to be caused by DNS lookup problems. The dnslookup router
94
 has some options of its own for controlling what happens when lookups for MX or
95
 SRV records give temporary errors. These more specific options are applied
96
 after this global option.
(-)b/mail/exim/files/debian/75_66-Fix-crash-in-expansions.patch (+84 lines)
Added Link Here
1
From 70069b65a39a7ba73a36fbd95371ff03cde1eb23 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 2 Feb 2023 20:00:35 +0000
4
Subject: [PATCH] Fix crash in expansions
5
6
Broken-by: 1058096b8c53
7
---
8
 doc/ChangeLog | 4 ++++
9
 src/expand.c      | 9 +++++----
10
 test/stderr/0630      | 1 +
11
 3 files changed, 10 insertions(+), 4 deletions(-)
12
13
--- a/doc/ChangeLog
14
+++ b/doc/ChangeLog
15
@@ -50,10 +50,14 @@ JH/20 Bug 2954: (OpenSSL) Fix setting of
16
 
17
 JH/20 Fix TLSA lookups.  Previously dns_again_means_nonexist would affect
18
       SERVFAIL results, which breaks the downgrade resistance of DANE.  Change
19
       to not checking that list for these looks.
20
 
21
+JH/23 Fix crash in string expansions. Previously, if an empty variable was
22
+      immediately followed by an expansion operator, a null-indirection read
23
+      was done, killing the process.
24
+
25
 
26
 Exim version 4.96
27
 -----------------
28
 
29
 JH/01 Move the wait-for-next-tick (needed for unique message IDs) from
30
--- a/src/expand.c
31
+++ b/src/expand.c
32
@@ -4652,11 +4652,11 @@ while (*s)
33
       yield = string_catn(yield, value, len);
34
 
35
     continue;
36
     }
37
 
38
-  if (isdigit(*s))
39
+  if (isdigit(*s))		/* A $<n> variable */
40
     {
41
     int n;
42
     s = read_cnumber(&n, s);
43
     if (n >= 0 && n <= expand_nmax)
44
       yield = string_catn(yield, expand_nstring[n], expand_nlength[n]);
45
@@ -7060,10 +7060,11 @@ NOT_ITEM: ;
46
       if (arg) *arg++ = '_';		/* Put back for error messages */
47
       }
48
 
49
     /* Deal specially with operators that might take a certificate variable
50
     as we do not want to do the usual expansion. For most, expand the string.*/
51
+
52
     switch(c)
53
       {
54
 #ifndef DISABLE_TLS
55
       case EOP_MD5:
56
       case EOP_SHA1:
57
@@ -7107,11 +7108,11 @@ NOT_ITEM: ;
58
 
59
     /* Otherwise, switch on the operator type.  After handling go back
60
     to the main loop top. */
61
 
62
      {
63
-     int start = yield->ptr;
64
+     unsigned expansion_start = gstring_length(yield);
65
      switch(c)
66
       {
67
       case EOP_BASE32:
68
 	{
69
 	uschar *t;
70
@@ -8168,12 +8169,12 @@ NOT_ITEM: ;
71
 	  goto EXPAND_FAILED;
72
 	}	/* EOP_* switch */
73
 
74
        DEBUG(D_expand)
75
 	{
76
-	const uschar * s = yield->s + start;
77
-	int i = yield->ptr - start;
78
+	const uschar * s = yield->s + expansion_start;
79
+	int i = gstring_length(yield) - expansion_start;
80
 	BOOL tainted = is_tainted(s);
81
 
82
 	DEBUG(D_noutf8)
83
 	  {
84
 	  debug_printf_indent("|-----op-res: %.*s\n", i, s);
(-)a/mail/exim/files/patch-OS__Makefile-Default (-10 lines)
Removed Link Here
1
--- OS/Makefile-Default.orig	2019-01-30 14:59:52.000000000 +0100
2
+++ OS/Makefile-Default	2019-02-13 00:34:40.753182000 +0100
3
@@ -242,6 +242,7 @@
4
 # The default setting points to a template function that doesn't actually do
5
 # any scanning, but just accepts the message.
6
 
7
+# HAVE_LOCAL_SCAN=no
8
 LOCAL_SCAN_SOURCE=src/local_scan.c
9
 
10
 # If you want to specify options for your local_scan() that can be set from
(-)b/mail/exim/files/patch-OS__Makefile-FreeBSD (-9 / +11 lines)
Lines 1-11 Link Here
1
--- OS/Makefile-FreeBSD.orig	2009-11-14 21:13:45.000000000 +0300
1
--- OS/Makefile-FreeBSD.orig	2023-04-09 09:45:04.226201000 +0200
2
+++ OS/Makefile-FreeBSD	2009-11-14 21:15:39.000000000 +0300
2
+++ OS/Makefile-FreeBSD	2023-04-09 09:48:01.819463000 +0200
3
@@ -7,7 +7,7 @@
3
@@ -18,8 +18,8 @@
4
 PORTOBJFORMAT!= test -x /usr/bin/objformat && /usr/bin/objformat || echo aout
4
 # Dynamically loaded modules need to be built with -fPIC
5
 CFLAGS_DYNAMIC=-shared -rdynamic -fPIC
5
 
6
 
6
 CHOWN_COMMAND=/usr/sbin/chown
7
-# FreeBSD always ships with Berkeley DB
7
-STRIP_COMMAND=/usr/bin/strip
8
-USE_DB=yes
8
+STRIP_COMMAND=XX_STRIPCMD_XX
9
+# FreeBSD ships with Berkeley DB until 13.1, but ndbm is always included
9
 CHMOD_COMMAND=/bin/chmod
10
+USE_NDBM=yes
10
 
11
 
11
 HAVE_SA_LEN=YES
12
 # This code for building outside ports suggested by Richard Clayton
13
 .ifdef   X11BASE
(-)a/mail/exim/files/patch-OS_os.c-FreeBSD (-15 lines)
Removed Link Here
1
--- OS/os.c-FreeBSD.orig	2021-10-11 17:03:56.119681000 +0200
2
+++ OS/os.c-FreeBSD	2021-10-11 17:04:27.802597000 +0200
3
@@ -16,10 +16,11 @@
4
 ssize_t
5
 os_sendfile(int out, int in, off_t * offp, size_t cnt)
6
 {
7
-off_t loff = *offp, written;
8
+off_t loff = offp ? *offp : 0;
9
+off_t written;
10
11
 if (sendfile(in, out, loff, cnt, NULL, &written, 0) < 0) return (ssize_t)-1;
12
-*offp = loff + written;
13
+if (offp) *offp = loff + written;
14
 return (ssize_t)written;
15
 }
(-)a/mail/exim/files/patch-src-dmarc.c (-19 lines)
Removed Link Here
1
--- src/dmarc.c.orig	2021-04-30 12:08:21 UTC
2
+++ src/dmarc.c
3
@@ -37,6 +37,7 @@ uschar *spf_human_readable = NULL;
4
 u_char *header_from_sender = NULL;
5
 int history_file_status    = DMARC_HIST_OK;
6
 uschar *dkim_history_buffer= NULL;
7
+uschar *dkim_selector = NULL;
8
 
9
 typedef struct dmarc_exim_p {
10
   uschar *name;
11
@@ -446,7 +447,7 @@ if (!dmarc_abort && !sender_host_authenticated)
12
 		  vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
13
 		  DMARC_POLICY_DKIM_OUTCOME_NONE;
14
     libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain,
15
-					       dkim_result, US"");
16
+					       dkim_selector, dkim_result, US"");
17
     DEBUG(D_receive)
18
       debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
19
     if (libdm_status != DMARC_PARSE_OKAY)
(-)a/mail/exim/files/tls/patch-tls1 (-43 lines)
Removed Link Here
1
From fc624b8cb4c3312d7450dfa86adfa3fe8dd9cbeb Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Tue, 11 Jan 2022 14:50:09 +0000
4
Subject: [PATCH] Ensure server tls close alert not delayed
5
6
---
7
 src/src/tls-gnu.c     | 5 +++++
8
 src/src/tls-openssl.c | 3 +++
9
 2 files changed, 8 insertions(+)
10
11
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
12
index 53635ac..3adadb8 100644
13
--- a/src/tls-gnu.c
14
+++ b/src/tls-gnu.c
15
@@ -3731,6 +3731,11 @@ if (do_shutdown)
16
 
17
   tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
18
 
19
+#ifdef EXIM_TCP_CORK
20
+  if (do_shutdown > 1)
21
+    (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
22
+#endif
23
+
24
   ALARM(2);
25
   gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
26
   ALARM_CLR(0);
27
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
28
index 5130455..576f62b 100644
29
--- a/src/tls-openssl.c
30
+++ b/src/tls-openssl.c
31
@@ -4516,6 +4516,9 @@ if (do_shutdown)
32
   if (  (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
33
      && do_shutdown > 1)
34
     {
35
+#ifdef EXIM_TCP_CORK
36
+    (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
37
+#endif
38
     ALARM(2);
39
     rc = SSL_shutdown(*sslp);		/* wait for response */
40
     ALARM_CLR(0);
41
-- 
42
1.9.1
43
(-)a/mail/exim/files/tls/patch-tls2 (-174 lines)
Removed Link Here
1
From 2ead369f8435918f3f15408b9394e580bcaf0910 Mon Sep 17 00:00:00 2001
2
From: Jeremy Harris <jgh146exb@wizmail.org>
3
Date: Thu, 10 Mar 2022 15:23:26 +0000
4
Subject: [PATCH] OpenSSL: track shutdown calls.  Bug 2864
5
6
---
7
 doc/doc-txt/ChangeLog     |  5 +++++
8
 src/src/macros.h          |  7 ++++---
9
 src/src/tls-gnu.c         | 10 +++++++---
10
 src/src/tls-openssl.c     | 13 ++++++++-----
11
 src/src/transports/smtp.c | 19 +++++++++++++------
12
 5 files changed, 37 insertions(+), 17 deletions(-)
13
14
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
15
index 5ba587b..1c799b6 100644
16
--- a/doc/ChangeLog
17
+++ b/doc/ChangeLog
18
@@ -95,6 +95,11 @@ JH/21 Remove the "allow_insecure_tainted_data" main config option and the
19
 JH/22 Fix static address-list lookups to properly return the matched item.
20
       Previously only the domain part was returned.
21
 
22
+JH/23 Bug 2864: FreeBSD: fix transport hang after 4xx/5xx response. Previously
23
+      the call into OpenSSL to send a TLS Close was being repeated; this
24
+      resulted in the library waiting for the peer's Close.  If that was never
25
+      sent we waited forever.  Fix by tracking send calls.
26
+
27
 
28
 Exim version 4.95
29
 -----------------
30
diff --git a/src/src/macros.h b/src/src/macros.h
31
index 92f2cc0..659a70f 100644
32
--- a/src/macros.h
33
+++ b/src/macros.h
34
@@ -1051,9 +1051,10 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
35
 
36
 
37
 /* Options on tls_close */
38
-#define TLS_NO_SHUTDOWN		0
39
-#define TLS_SHUTDOWN_NOWAIT	1
40
-#define TLS_SHUTDOWN_WAIT	2
41
+#define TLS_NO_SHUTDOWN		0	/* Just forget the context */
42
+#define TLS_SHUTDOWN_NOWAIT	1	/* Send alert; do not wait */
43
+#define TLS_SHUTDOWN_WAIT	2	/* Send alert & wait for peer's alert */
44
+#define TLS_SHUTDOWN_WONLY	3	/* only wait for peer's alert */
45
 
46
 
47
 #ifdef COMPILE_UTILITY
48
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
49
index 1215f85..6227823 100644
50
--- a/src/tls-gnu.c
51
+++ b/src/tls-gnu.c
52
@@ -3744,17 +3744,21 @@ if (!tlsp || tlsp->active.sock < 0) return;  /* TLS was not active */
53
 if (do_shutdown)
54
   {
55
   DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
56
-    do_shutdown > 1 ? " (with response-wait)" : "");
57
+    do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : "");
58
 
59
   tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
60
 
61
 #ifdef EXIM_TCP_CORK
62
-  if (do_shutdown > 1)
63
+  if (do_shutdown == TLS_SHUTDOWN_WAIT)
64
     (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
65
 #endif
66
 
67
+  /* The library seems to have no way to only wait for a peer's
68
+  shutdown, so handle the same as TLS_SHUTDOWN_WAIT */
69
+
70
   ALARM(2);
71
-  gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
72
+  gnutls_bye(state->session,
73
+      do_shutdown > TLS_SHUTDOWN_NOWAIT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
74
   ALARM_CLR(0);
75
   }
76
 
77
diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
78
index d5c5778..7bf62f5 100644
79
--- a/src/tls-openssl.c
80
+++ b/src/tls-openssl.c
81
@@ -4519,22 +4519,25 @@ int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
82
 
83
 if (*fdp < 0) return;  /* TLS was not active */
84
 
85
-if (do_shutdown)
86
+if (do_shutdown > TLS_NO_SHUTDOWN)
87
   {
88
   int rc;
89
   DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
90
-    do_shutdown > 1 ? " (with response-wait)" : "");
91
+    do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : "");
92
 
93
   tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
94
 
95
-  if (  (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
96
-     && do_shutdown > 1)
97
+  if (  (  do_shutdown >= TLS_SHUTDOWN_WONLY
98
+	|| (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
99
+	)
100
+     && do_shutdown > TLS_SHUTDOWN_NOWAIT
101
+     )
102
     {
103
 #ifdef EXIM_TCP_CORK
104
     (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
105
 #endif
106
     ALARM(2);
107
-    rc = SSL_shutdown(*sslp);		/* wait for response */
108
+    rc = SSL_shutdown(*sslp);			/* wait for response */
109
     ALARM_CLR(0);
110
     }
111
 
112
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
113
index e2c2680..524f186 100644
114
--- a/src/transports/smtp.c
115
+++ b/src/transports/smtp.c
116
@@ -4085,7 +4085,7 @@ else
117
       sx->send_quit = FALSE;	/* avoid sending it later */
118
 
119
 #ifndef DISABLE_TLS
120
-      if (sx->cctx.tls_ctx)	/* need to send TLS Close Notify */
121
+      if (sx->cctx.tls_ctx && sx->send_tlsclose)	/* need to send TLS Close Notify */
122
 	{
123
 # ifdef EXIM_TCP_CORK		/* Use _CORK to get Close Notify in FIN segment */
124
 	(void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
125
@@ -4429,7 +4429,8 @@ if (!sx->ok)
126
 # ifndef DISABLE_TLS
127
 	if (sx->cctx.tls_ctx)
128
 	  {
129
-	  tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
130
+	  tls_close(sx->cctx.tls_ctx,
131
+		    sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
132
 	  sx->cctx.tls_ctx = NULL;
133
 	  }
134
 # endif
135
@@ -4640,7 +4641,8 @@ if (sx->completed_addr && sx->ok && sx->send_quit)
136
 	    a new EHLO. If we don't get a good response, we don't attempt to pass
137
 	    the socket on. */
138
 
139
-	  tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
140
+	  tls_close(sx->cctx.tls_ctx,
141
+	    sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
142
 	  sx->send_tlsclose = FALSE;
143
 	  sx->cctx.tls_ctx = NULL;
144
 	  tls_out.active.sock = -1;
145
@@ -4742,7 +4744,7 @@ if (sx->send_quit)
146
   {			/* Use _MORE to get QUIT in FIN segment */
147
   (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n");
148
 #ifndef DISABLE_TLS
149
-  if (sx->cctx.tls_ctx)
150
+  if (sx->cctx.tls_ctx && sx->send_tlsclose)
151
     {
152
 # ifdef EXIM_TCP_CORK	/* Use _CORK to get TLS Close Notify in FIN segment */
153
     (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
154
@@ -4797,10 +4799,15 @@ if (sx->send_quit || tcw_done && !tcw)
155
     while (!sigalrm_seen && n > 0);
156
     ALARM_CLR(0);
157
 
158
+    if (sx->send_tlsclose)
159
+      {
160
 # ifdef EXIM_TCP_CORK
161
-    (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
162
+      (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
163
 # endif
164
-    tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
165
+      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
166
+      }
167
+    else
168
+      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WONLY);
169
     sx->cctx.tls_ctx = NULL;
170
     }
171
 #endif
172
-- 
173
1.9.1
174

Return to bug 265098