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

Collapse All | Expand All

(-)b/mail/exim/Makefile (-16 / +16 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 64-85 SPF_LIB_DEPENDS= libspf2.so:mail/libspf2 Link Here
64
SQLITE_LIB_DEPENDS=	libicudata.so:devel/icu
64
SQLITE_LIB_DEPENDS=	libicudata.so:devel/icu
65
SQLITE_USES=	pkgconfig sqlite
65
SQLITE_USES=	pkgconfig sqlite
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}_30-Avoid-calling-gettimeofday-select-per-char-for-cmdli.patch:-p1 \
70
		${DEBIAN_PATCHES_PREFIX}_32-Fix-PAM-auth.-Bug-2813.patch:-p1 \
70
#		${DEBIAN_PATCHES_PREFIX}_32-Fix-PAM-auth.-Bug-2813.patch:-p1 \
71
		${DEBIAN_PATCHES_PREFIX}_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch:-p1 \
71
#		${DEBIAN_PATCHES_PREFIX}_35-Exiqgrep-check-arg-parsing.-Bug-2821.patch:-p1 \
72
		${DEBIAN_PATCHES_PREFIX}_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch:-p1 \
72
#		${DEBIAN_PATCHES_PREFIX}_38-Convert-all-uses-of-select-to-poll.-Bug-2831.patch:-p1 \
73
		${DEBIAN_PATCHES_PREFIX}_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch:-p1 \
73
#		${DEBIAN_PATCHES_PREFIX}_40-Fix-basic-memory-use-for-SPARC.-Bug-2838.patch:-p1 \
74
		${DEBIAN_PATCHES_PREFIX}_43-BSD-fix-resource-leak.patch:-p1 \
74
#		${DEBIAN_PATCHES_PREFIX}_43-BSD-fix-resource-leak.patch:-p1 \
75
		${DEBIAN_PATCHES_PREFIX}_45-Fix-bogus-error-message-copy.-Bug-2857.patch:-p1 \
75
#		${DEBIAN_PATCHES_PREFIX}_45-Fix-bogus-error-message-copy.-Bug-2857.patch:-p1 \
76
		${DEBIAN_PATCHES_PREFIX}_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch:-p1 \
76
#		${DEBIAN_PATCHES_PREFIX}_50-Fix-include_directory-in-redirect-routers.-Bug-2715.patch:-p1 \
77
		${DEBIAN_PATCHES_PREFIX}_55-Specific-check-for-null-pointer.patch:-p1
77
#		${DEBIAN_PATCHES_PREFIX}_55-Specific-check-for-null-pointer.patch:-p1
78
78
79
TLS_PATCHES_PREFIX=	${FILESDIR}/tls/
79
TLS_PATCHES_PREFIX=	${FILESDIR}/tls/
80
EXTRA_PATCHES+= \
80
EXTRA_PATCHES+= \
81
		${TLS_PATCHES_PREFIX}patch-tls1:-p1 \
81
		${TLS_PATCHES_PREFIX}patch-tls1:-p1
82
		${TLS_PATCHES_PREFIX}patch-tls2:-p1
82
#		${TLS_PATCHES_PREFIX}patch-tls2:-p1
83
83
84
.include <bsd.port.options.mk>
84
.include <bsd.port.options.mk>
85
85
Lines 120-126 EXTRA_PATCHES+= ${FILESDIR}/extra-patch-Local-sa-exim.c Link Here
120
EXTRA_PATCHES+=	${FILESDIR}/extra-patch-Local-sa-exim.conf
120
EXTRA_PATCHES+=	${FILESDIR}/extra-patch-Local-sa-exim.conf
121
.endif
121
.endif
122
122
123
EXIM_VERSION=	4.95
123
EXIM_VERSION=	4.96
124
SA_EXIM_VERSION=4.2.1
124
SA_EXIM_VERSION=4.2.1
125
EXIM_INSTALL_ARG+=	"-no_chown" "-no_symlink"
125
EXIM_INSTALL_ARG+=	"-no_chown" "-no_symlink"
126
EXTRA_PATCHES+=	`${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`
126
EXTRA_PATCHES+=	`${FIND} ${PATCHDIR} -name '74_*.patch'|${SORT} -h`
Lines 210-216 WITH_DEFAULT_CHARSET?= ISO-8859-1 Link Here
210
210
211
# You should not need to fiddle with anything below this point.
211
# You should not need to fiddle with anything below this point.
212
212
213
LIB_DEPENDS+=	libpcre.so:devel/pcre
213
LIB_DEPENDS+=	libpcre2-posix.so:devel/pcre2
214
214
215
.if ! ${PORT_OPTIONS:MDKIM}
215
.if ! ${PORT_OPTIONS:MDKIM}
216
SEDLIST+=	-e 's,^\# (DISABLE_DKIM=),\1,'
216
SEDLIST+=	-e 's,^\# (DISABLE_DKIM=),\1,'
(-)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
(-)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,
(-)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
(-)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
(-)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);
(-)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);
(-)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
(-)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
 }
(-)b/mail/exim/files/tls/patch-tls1 (-16 / +1 lines)
Lines 5-12 Subject: [PATCH] Ensure server tls close alert not delayed Link Here
5
5
6
---
6
---
7
 src/src/tls-gnu.c     | 5 +++++
7
 src/src/tls-gnu.c     | 5 +++++
8
 src/src/tls-openssl.c | 3 +++
8
 1 files changed, 5 insertions(+)
9
 2 files changed, 8 insertions(+)
10
9
11
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
10
diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
12
index 53635ac..3adadb8 100644
11
index 53635ac..3adadb8 100644
Lines 24-43 index 53635ac..3adadb8 100644 Link Here
24
   ALARM(2);
23
   ALARM(2);
25
   gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
24
   gnutls_bye(state->session, do_shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
26
   ALARM_CLR(0);
25
   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
-- 
26
-- 
42
1.9.1
27
1.9.1
43
28
(-)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