mcst-linux-kernel/patches-2024.06.26/exim-4.94.2/0000-all-debian-patches-for...

2063 lines
73 KiB
Diff

diff -ruN a/doc/ChangeLog b/doc/ChangeLog
--- a/doc/ChangeLog 2021-04-30 15:08:21.000000000 +0300
+++ b/doc/ChangeLog 2023-09-14 18:46:51.395566820 +0300
@@ -220,6 +220,17 @@
QS/04 Always die if requested from internal logging, even is logging is
disabled.
+JH/52 Fix ${ip6norm:} operator. Previously, any trailing line text was dropped,
+ making it unusable in complex expressions.
+
+JH/53 Bug 2743: fix immediate-delivery via named queue. Previously this would
+ fail with a taint-check on the spoolfile name, and leave the message
+ queued.
+
+JH/57 Fix control=fakreject for a custom message containing tainted data.
+ Previously this resulted in a log complaint, due to a re-expansion present
+ since fakereject was originally introduced.
+
Exim version 4.94
-----------------
diff -ruN a/doc/exim.8 b/doc/exim.8
--- a/doc/exim.8 2021-04-30 15:12:05.000000000 +0300
+++ b/doc/exim.8 2023-09-14 18:49:54.436045697 +0300
@@ -1,9 +1,9 @@
-.TH EXIM 8
+.TH EXIM4 8
.SH NAME
-exim \- a Mail Transfer Agent
+exim4 \- a Mail Transfer Agent
.SH SYNOPSIS
.nf
-.B exim [options] arguments ...
+.B exim4 [options] arguments ...
.B mailq [options] arguments ...
.B rsmtp [options] arguments ...
.B rmail [options] arguments ...
@@ -40,7 +40,7 @@
recipients) is assumed. Thus, for example, if Exim is installed in
\fI/usr/sbin\fP, you can send a message from the command line like this:
.sp
- /usr/sbin/exim -i <recipient-address(es)>
+ /usr/sbin/exim4 -i <recipient-address(es)>
<message content, including all the header lines>
CTRL-D
.sp
@@ -125,8 +125,8 @@
.sp
When a listening daemon
is started without the use of \fB\-oX\fP (that is, without overriding the normal
-configuration), it writes its process id to a file called exim\-daemon.pid
-in Exim's spool directory. This location can be overridden by setting
+configuration), it writes its process id to a file called
+/run/exim4/exim.pid. This location can be overridden by setting
PID_FILE_PATH in Local/Makefile. The file is written while Exim is still
running as root.
.sp
@@ -180,7 +180,7 @@
This option operates like \fB\-be\fP except that it must be followed by the name
of a file. For example:
.sp
- exim \-bem /tmp/testmessage
+ exim4 \-bem /tmp/testmessage
.sp
The file is read as a message (as if receiving a locally\-submitted non\-SMTP
message) before any of the test expansions are done. Thus, message\-specific
@@ -206,7 +206,7 @@
can use both \fB\-bF\fP and \fB\-bf\fP on the same command, in order to test a system
filter and a user filter in the same run. For example:
.sp
- exim \-bF /system/filter \-bf /user/filter </test/message
+ exim4 \-bF /system/filter \-bf /user/filter </test/message
.sp
This is helpful when the system filter adds header lines or sets filter
variables that are used by the user filter.
@@ -258,8 +258,8 @@
standard input and output. The IP address may include a port number at the end,
after a full stop. For example:
.sp
- exim \-bh 10.9.8.7.1234
- exim \-bh fe80::a00:20ff:fe86:a061.5678
+ exim4 \-bh 10.9.8.7.1234
+ exim4 \-bh fe80::a00:20ff:fe86:a061.5678
.sp
When an IPv6 address is given, it is converted into canonical form. In the case
of the second example above, the value of \fI$sender_host_address\fP after
@@ -417,7 +417,7 @@
of one or more specific options can be requested by giving their names as
arguments, for example:
.sp
- exim \-bP qualify_domain hold_domains
+ exim4 \-bP qualify_domain hold_domains
.sp
However, any option setting that is preceded by the word "hide" in the
configuration file is not shown in full, except to an admin user. For other
@@ -445,7 +445,7 @@
.sp
If \fB\-bP\fP is followed by a name preceded by +, for example,
.sp
- exim \-bP +local_domains
+ exim4 \-bP +local_domains
.sp
it searches for a matching named list of any type (domain, host, address, or
local part) and outputs what it finds.
@@ -454,7 +454,7 @@
followed by the name of an appropriate driver instance, the option settings for
that driver are output. For example:
.sp
- exim \-bP transport local_delivery
+ exim4 \-bP transport local_delivery
.sp
The generic driver options are output first, followed by the driver's private
options. A list of the names of drivers of a particular type can be obtained by
@@ -539,7 +539,7 @@
arguments. It causes Exim to look for a retry rule that matches the values
and to write it to the standard output. For example:
.sp
- exim \-brt bach.comp.mus.example
+ exim4 \-brt bach.comp.mus.example
Retry rule: *.comp.mus.example F,2h,15m; F,4d,30m;
.sp
The first
@@ -552,7 +552,7 @@
sought. Finally, an argument that is the name of a specific delivery error, as
used in setting up retry rules, can be given. For example:
.sp
- exim \-brt haydn.comp.mus.example quota_3d
+ exim4 \-brt haydn.comp.mus.example quota_3d
Retry rule: *@haydn.comp.mus.example quota_3d F,1h,15m
.TP 10
\fB\-brw\fP
@@ -655,7 +655,7 @@
.TP 10
\fB\-bV\fP
This option causes Exim to write the current version number, compilation
-number, and compilation date of the \fIexim\fP binary to the standard output.
+number, and compilation date of the \fIexim4\fP binary to the standard output.
It also lists the DBM library that is being used, the optional modules (such as
specific lookup types), the drivers that are included in the binary, and the
name of the runtime configuration file that is in use.
@@ -683,7 +683,7 @@
right angle bracket for addresses to be verified.
.sp
Unlike the \fB\-be\fP test option, you cannot arrange for Exim to use the
-readline() function, because it is running as \fIexim\fP and there are
+readline() function, because it is running as \fIexim4\fP and there are
security issues.
.sp
Verification differs from address testing (the \fB\-bt\fP option) in that routers
@@ -796,14 +796,14 @@
string, in which case the equals sign is optional. These two commands are
synonymous:
.sp
- exim \-DABC ...
- exim \-DABC= ...
+ exim4 \-DABC ...
+ exim4 \-DABC= ...
.sp
To include spaces in a macro definition item, quotes must be used. If you use
quotes, spaces are permitted around the macro name and the equals sign. For
example:
.sp
- exim '\-D ABC = something' ...
+ exim4 '\-D ABC = something' ...
.sp
\fB\-D\fP may be repeated up to 10 times on a command line.
Only macro names up to 22 letters long can be set.
@@ -939,8 +939,8 @@
string, or as a pair of angle brackets with nothing between them, as in these
examples of shell commands:
.sp
- exim \-f '<>' user@domain
- exim \-f "" user@domain
+ exim4 \-f '<>' user@domain
+ exim4 \-f "" user@domain
.sp
In addition, the use of \fB\-f\fP is not restricted when testing a filter file
with \fB\-bf\fP or when testing or verifying addresses using the \fB\-bt\fP or
@@ -1337,12 +1337,12 @@
The \fB\-oMa\fP option sets the sender host address. This may include a port
number at the end, after a full stop (period). For example:
.sp
- exim \-bs \-oMa 10.9.8.7.1234
+ exim4 \-bs \-oMa 10.9.8.7.1234
.sp
An alternative syntax is to enclose the IP address in square brackets,
followed by a colon and the port number:
.sp
- exim \-bs \-oMa [10.9.8.7]:1234
+ exim4 \-bs \-oMa [10.9.8.7]:1234
.sp
The IP address is placed in the \fI$sender_host_address\fP variable, and the
port, if present, in \fI$sender_host_port\fP. If both \fB\-oMa\fP and \fB\-bh\fP
@@ -1449,6 +1449,17 @@
is also given. It controls which ports and interfaces the daemon uses. When \fB\-oX\fP is used to start a daemon, no pid
file is written unless \fB\-oP\fP is also present to specify a pid filename.
.TP 10
+\fB\-oY\fP
+This option controls the creation of an inter-process communications endpoint
+by the Exim daemon. It is only relevant when the \fB\-bd\fP (start listening
+daemon) option is also given.
+Normally the daemon creates this socket, unless a \fB\-oX\fP and no \fB\-oP\fP
+option is also present.
+If this option is given then the socket will not be created. This could be
+required if the system is running multiple daemons.
+The socket is currently used for fast ramp-up of queue runner processes and
+obtaining a current queue size.
+.TP 10
\fB\-pd\fP
This option applies when an embedded Perl interpreter is linked with Exim. It overrides the setting of the \fBperl_at_start\fP
option, forcing the starting of the interpreter to be delayed until it is
@@ -1555,22 +1566,22 @@
will specify a queue to operate on.
For example:
.sp
- exim \-bp \-qGquarantine
+ exim4 \-bp \-qGquarantine
mailq \-qGquarantine
- exim \-qGoffpeak \-Rf @special.domain.example
+ exim4 \-qGoffpeak \-Rf @special.domain.example
.TP 10
\fB\-q\fP<\fIqflags\fP> <\fIstart id\fP> <\fIend id\fP>
When scanning the queue, Exim can be made to skip over messages whose ids are
lexically less than a given value by following the \fB\-q\fP option with a
starting message id. For example:
.sp
- exim \-q 0t5C6f\-0000c8\-00
+ exim4 \-q 0t5C6f\-0000c8\-00
.sp
Messages that arrived earlier than 0t5C6f\-0000c8\-00 are not inspected. If a
second message id is given, messages whose ids are lexically greater than it
are also skipped. If the same id is given twice, for example,
.sp
- exim \-q 0t5C6f\-0000c8\-00 0t5C6f\-0000c8\-00
+ exim4 \-q 0t5C6f\-0000c8\-00 0t5C6f\-0000c8\-00
.sp
just one delivery process is started, for that message. This differs from
\fB\-M\fP in that retry data is respected, and it also differs from \fB\-Mc\fP in
@@ -1586,7 +1597,7 @@
single daemon process handles both functions. A common way of starting up a
combined daemon at system boot time is to use a command such as
.sp
- /usr/exim/bin/exim \-bd \-q30m
+ /usr/sbin/exim4 \-bd \-q30m
.sp
Such a daemon listens for incoming SMTP calls, and also starts a queue runner
process every 30 minutes.
@@ -1617,7 +1628,7 @@
If you want to do periodic queue runs for messages with specific recipients,
you can combine \fB\-R\fP with \fB\-q\fP and a time value. For example:
.sp
- exim \-q25m \-R @special.domain.example
+ exim4 \-q25m \-R @special.domain.example
.sp
This example does a queue run for messages with recipients in the given domain
every 25 minutes. Any additional flags that are specified with \fB\-q\fP are
@@ -1733,6 +1744,26 @@
.sp
.
.SH "SEE ALSO"
+.BR exicyclog (8),
+.BR exigrep (8),
+.BR exim_checkaccess (8),
+.BR exim_convert4r4 (8),
+.BR exim_db (8),
+.BR exim_dbmbuild (8),
+.BR exim_lock (8),
+.BR eximon (8),
+.BR exinext (8),
+.BR exiqgrep (8),
+.BR exiqsumm (8),
+.BR exiwhat (8),
+.BR update\-exim4.conf (8),
+.BR update\-exim4defaults (8),
+/usr/share/doc/exim4\-base/,
+/usr/share/doc/exim4\-base/README.Debian.[gz|html].
.rs
.sp
The full Exim specification, the Exim book, and the Exim wiki.
+
+.SH AUTHOR
+This manual page was provided with the upstream Exim source package.
+It was enhanced for the Debian GNU/Linux system.
diff -ruN a/doc/NewStuff b/doc/NewStuff
--- a/doc/NewStuff 2021-04-30 15:08:21.000000000 +0300
+++ b/doc/NewStuff 2023-09-14 18:49:54.420045306 +0300
@@ -6,6 +6,57 @@
test from the snapshots or the Git before the documentation is updated. Once
the documentation is updated, this file is reduced to a short list.
+Cherrypicked from GIT master:
+------------
+
+10. A command-line option to have a daemon not create a notifier socket.
+
+
+Version 4.95
+------------
+
+ 1. The fast-ramp two phase queue run support, previously experimental, is
+ now supported by default.
+
+ 2. The native SRS support, previously experimental, is now supported. It is
+ not built unless specified in the Local/Makefile.
+
+ 3. TLS resumption support, previously experimental, is now supported and
+ included in default builds.
+
+ 4. Single-key LMDB lookups, previously experimental, are now supported.
+ The support is not built unless specified in the Local/Makefile.
+
+ 5. Option "message_linelength_limit" on the smtp transport to enforce (by
+ default) the RFC 998 character limit.
+
+ 6. An option to ignore the cache on a lookup.
+
+ 7. Quota checking during reception (i.e. at SMTP time) for appendfile-
+ transport-managed quotas.
+
+ 8. Sqlite lookups accept a "file=<path>" option to specify a per-operation
+ db file, replacing the previous prefix to the SQL string (which had
+ issues when the SQL used tainted values).
+
+ 9. Lsearch lookups accept a "ret=full" option, to return both the portion
+ of the line matching the key, and the remainder.
+
+10. A command-line option to have a daemon not create a notifier socket.
+
+11. Faster TLS startup. When various configuration options contain no
+ expandable elements, the information can be preloaded and cached rather
+ than the provious behaviour of always loading at startup time for every
+ connection. This helps particularly for the CA bundle.
+
+12. Proxy Protocol Timeout is configurable via "proxy_protocol_timeout"
+ main config option.
+
+13. Option "smtp_accept_msx_per_connection" is now expanded.
+
+13. A main config option "allow_insecure_tainted_data" allows to turn
+ taint errors into warnings.
+
Version 4.94
------------
diff -ruN a/doc/spec.txt b/doc/spec.txt
--- a/doc/spec.txt 2021-04-30 15:12:05.000000000 +0300
+++ b/doc/spec.txt 2023-09-14 18:49:54.436045697 +0300
@@ -4193,6 +4193,19 @@
options, are given in chapter 13. When -oX is used to start a daemon, no
pid file is written unless -oP is also present to specify a pid filename.
+-oY
+
+ This option controls the creation of an inter-process communications
+ endpoint by the Exim daemon. It is only relevant when the -bd
+ (start listening daemon) option is also given. Normally the daemon
+ creates this socket, unless a oX and no -oP option is also
+ present. If this option is given then the socket will not be created.
+ This could be required if the system is running multiple daemons.
+
+ The socket is currently used for
+ * fast ramp-up of queue runner processes
+ * obtaining a current queue size
+
-pd
This option applies when an embedded Perl interpreter is linked with Exim
@@ -8651,8 +8664,16 @@
options for which string expansion is performed are marked with * after the
data type. ACL rules always expand strings. A couple of expansion conditions do
not expand some of the brace-delimited branches, for security reasons, and
-expansion of data deriving from the sender ("tainted data") is not permitted.
-
+expansion of data deriving from the sender ("tainted data") is not permitted
+(including acessing a file using a tainted name). The main config
+option allow_insecure_tainted_data can be used as mitigation during
+uprades to more secure configurations.
+
+Common ways of obtaining untainted equivalents of variables with tainted
+values come down to using the tainted value as a lookup key in a trusted
+database. This database could be the filesystem structure, or the
+password file, or accessed via a DBMS. Specific methods are indexed
+under "de-tainting".
11.1 Literal text in expanded strings
-------------------------------------
@@ -11729,6 +11750,8 @@
This variable contains the number of messages queued. It is evaluated on
demand, but no more often than once every minute.
+ If there is no daemon notifier socket open, the value will be
+ an empty string.
$r_...
@@ -12944,6 +12967,8 @@
14.1 Miscellaneous
------------------
+add_environment environment variables
+allow_insecure_tainted_data turn taint errors into warnings
bi_command to run for -bi command line option
debug_store do extra internal checks
disable_ipv6 do no IPv6 processing
@@ -13551,6 +13576,16 @@
matches the domain literal form of all the local host's IP addresses.
+-----------------------------------------------------+
+|allow_insecure_tainted_data main boolean false |
++-----------------------------------------------------+
+
+The handling of tainted data may break older (pre 4.94) configurations.
+Setting this option to "true" turns taint errors (which result in a temporary
+message rejection) into warnings. This option is meant as mitigation only
+and deprecated already today. Future releases of Exim may ignore it.
+The taint log selector can be used to suppress even the warnings.
+
++-----------------------------------------------------+
|allow_mx_to_ip|Use: main|Type: boolean|Default: false|
+-----------------------------------------------------+
@@ -15211,10 +15246,12 @@
sharing a spool directory should need to modify the default.
The option is expanded before use. If the platform supports Linux-style
-abstract socket names, the result is used with a nul byte prefixed. Otherwise,
-it should be a full path name and use a directory accessible to Exim.
+abstract socket names, the result is used with a nul byte prefixed.
+Otherwise, if nonempty, it should be a full path name and use a directory
+accessible to Exim.
-If the Exim command line uses a -oX option and does not use -oP then a notifier
+If this option is set as empty, or the command line -oY option is used, or
+the command line uses a -oX option and does not use -oP, then a notifier
socket is not created.
+-----------------------------------------------------------------------------+
@@ -35330,6 +35367,7 @@
smtp_protocol_error SMTP protocol errors
smtp_syntax_error SMTP syntax errors
subject contents of Subject: on <= lines
+*taint taint errors or warnings
*tls_certificate_verified certificate verification status
*tls_cipher TLS cipher suite on <= and => lines
tls_peerdn TLS peer DN on <= and => lines
@@ -35618,7 +35656,9 @@
when TLS is in use. The item is "CV=yes" if the peer's certificate was
verified using a CA trust anchor, "CA=dane" if using a DNS trust anchor,
and "CV=no" if not.
-
+ * taint: Log warnings about tainted data. This selector can't be
+ turned of if allow_insecure_tainted_data is false (which is the
+ default).
* tls_cipher: When a message is sent or received over an encrypted
connection, the cipher suite used is added to the log line, preceded by X=.
diff -ruN a/OS/eximon.conf-Default b/OS/eximon.conf-Default
--- a/OS/eximon.conf-Default 2021-04-30 15:08:21.000000000 +0300
+++ b/OS/eximon.conf-Default 2023-09-14 18:45:28.069528181 +0300
@@ -5,7 +5,7 @@
# The name of the eximon binary, usually the same as the eximon script,
# with .bin stuck on the end.
-EXIMON_BINARY="${EXIMON_BINARY-$0.bin}"
+EXIMON_BINARY="/usr/libexec/exim4/${EXIMON_BINARY-${0##*/}.bin}"
# The remaining parameters are values likely to be changed to suit the
# user's taste. They are documented in the EDITME file.
diff -ruN a/OS/Makefile-Base b/OS/Makefile-Base
--- a/OS/Makefile-Base 2021-04-30 15:08:21.000000000 +0300
+++ b/OS/Makefile-Base 2023-09-14 18:41:42.980022143 +0300
@@ -228,7 +228,7 @@
$(FE)$(LNCC) -o $@ $(LFLAGS) $(OBJ_MACRO)
macro.c: macro_predef
- ./macro_predef > macro.c
+ macro_predef > macro.c
# This target is recognized specially by GNU make. It records those targets
# that do not correspond to files that are being built and which should
diff -ruN a/OS/Makefile-Linux b/OS/Makefile-Linux
--- a/OS/Makefile-Linux 2021-04-30 15:08:21.000000000 +0300
+++ b/OS/Makefile-Linux 2023-09-14 18:45:21.885376889 +0300
@@ -31,9 +31,9 @@
X11_LD_LIB=$(X11)/lib
EXIWHAT_PS_ARG=ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_EGREP_ARG='/exim4( |$$)'
EXIWHAT_MULTIKILL_CMD=killall
-EXIWHAT_MULTIKILL_ARG=exim
+EXIWHAT_MULTIKILL_ARG=exim4
EXIWHAT_KILL_SIGNAL=-USR1
# End
diff -ruN a/README b/README
--- a/README 2021-04-30 15:08:21.000000000 +0300
+++ b/README 2023-09-14 18:46:14.142655374 +0300
@@ -14,8 +14,16 @@
older book may be helpful for the background, but a lot of the detail has
changed, so it is likely to be confusing to newcomers.
-There is a website at https://www.exim.org; this contains details of the
-mailing list exim-users@exim.org.
+Information about the way Debian has built the binary packages is
+obtainable in /usr/share/doc/exim4-base/README.Debian.gz, and there
+is a Debian-centered mailing list,
+pkg-exim4-users@lists.alioth.debian.org. Please ask Debian-specific
+questions there, and only write to the upstream exim-users mailing
+list if you are sure that your question is not Debian-specific. You
+can find the subscription web page on
+http://lists.alioth.debian.org/mailman/listinfo/pkg-exim4-users
+
+There is a website at https://www.exim.org/.
A copy of the Exim FAQ should be available from the same source that you used
to obtain the Exim distribution. Additional formats for the documentation
diff -ruN a/src/acl.c b/src/acl.c
--- a/src/acl.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/acl.c 2023-09-14 18:48:55.194596003 +0300
@@ -3137,7 +3137,9 @@
{
const uschar *pp = p + 1;
while (*pp) pp++;
- fake_response_text = expand_string(string_copyn(p+1, pp-p-1));
+ /* The entire control= line was expanded at top so no need to expand
+ the part after the / */
+ fake_response_text = string_copyn(p+1, pp-p-1);
p = pp;
}
else /* Explicitly reset to default string */
@@ -3598,20 +3600,22 @@
#endif
case ACLC_QUEUE:
- if (is_tainted(arg))
{
- *log_msgptr = string_sprintf("Tainted name '%s' for queue not permitted",
- arg);
- return ERROR;
- }
- if (Ustrchr(arg, '/'))
- {
- *log_msgptr = string_sprintf(
- "Directory separator not permitted in queue name: '%s'", arg);
- return ERROR;
+ uschar *m;
+ if ((m = is_tainted2(arg, 0, "Tainted name '%s' for queue not permitted", arg)))
+ {
+ *log_msgptr = m;
+ return ERROR;
+ }
+ if (Ustrchr(arg, '/'))
+ {
+ *log_msgptr = string_sprintf(
+ "Directory separator not permitted in queue name: '%s'", arg);
+ return ERROR;
+ }
+ queue_name = string_copy_perm(arg, FALSE);
+ break;
}
- queue_name = string_copy_perm(arg, FALSE);
- break;
case ACLC_RATELIMIT:
rc = acl_ratelimit(arg, where, log_msgptr);
@@ -4007,10 +4011,8 @@
else if (*ss == '/')
{
struct stat statbuf;
- if (is_tainted(ss))
+ if (is_tainted2(ss, LOG_MAIN|LOG_PANIC, "Tainted ACL file name '%s'", ss))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to open tainted ACL file name \"%s\"", ss);
/* Avoid leaking info to an attacker */
*log_msgptr = US"internal configuration error";
return ERROR;
diff -ruN a/src/config.h.defaults b/src/config.h.defaults
--- a/src/config.h.defaults 2021-04-30 15:08:21.000000000 +0300
+++ b/src/config.h.defaults 2023-09-14 18:50:04.368288757 +0300
@@ -17,6 +17,8 @@
#define ALT_CONFIG_PREFIX
#define TRUSTED_CONFIG_LIST
+#define ALLOW_INSECURE_TAINTED_DATA
+
#define APPENDFILE_MODE 0600
#define APPENDFILE_DIRECTORY_MODE 0700
#define APPENDFILE_LOCKFILE_MODE 0600
@@ -33,6 +35,8 @@
#define AUTH_VARS 3
+#define DLOPEN_LOCAL_SCAN
+
#define BIN_DIRECTORY
#define CONFIGURE_FILE
diff -ruN a/src/convert4r4.src b/src/convert4r4.src
--- a/src/convert4r4.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/convert4r4.src 2023-09-14 18:45:56.406221440 +0300
@@ -666,6 +666,32 @@
print STDERR "Runtime configuration file converter for Exim release 4.\n";
+if( !defined $ENV{"CONVERT4R4"} || $ENV{"CONVERT4R4"} ne "I understand this is an unsupported tool" ) {
+
+ print STDERR <<EOF;
+convert4r4 on Debian GNU/Linux deprecated
+
+This tool is unsupported by upstream and discouraged by the Debian Exim 4
+maintainers. It has multiple known bugs, and you need to manually
+review its output after using it anyway. Please seriously consider complete
+manual regeneration of the Exim 4 configuration, preferably by using the new
+Debconf interface to Exim 4.
+
+If you decide to ignore this advice and to use this script anyway,
+setting the environment variable CONVERT4R4 to the value
+\"I understand this is an unsupported tool\"
+will allow you to run the script. If you find bugs, you get to keep
+the pieces. Please do not file bugs against this script in the Debian
+BTS without providing a patch fixing the bugs, and please do not
+expect the upstream exim-users mailing list to answer questions.
+
+Kind regards
+the Debian Exim4 Maintainers
+EOF
+
+ exit 1;
+}
+
$transport_start = $director_start = $router_start = $retry_start
= $rewrite_start = $auth_start = 999999;
diff -ruN a/src/daemon.c b/src/daemon.c
--- a/src/daemon.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/daemon.c 2023-09-14 18:49:54.424045404 +0300
@@ -1144,6 +1144,11 @@
struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
int len;
+if (!notifier_socket || !*notifier_socket)
+ {
+ DEBUG(D_any) debug_printf("-oY used so not creating notifier socket\n");
+ return;
+ }
if (override_local_interfaces && !override_pid_file_path)
{
DEBUG(D_any)
diff -ruN a/src/dbstuff.h b/src/dbstuff.h
--- a/src/dbstuff.h 2021-04-30 15:08:21.000000000 +0300
+++ b/src/dbstuff.h 2023-09-14 18:47:22.300322976 +0300
@@ -643,11 +643,9 @@
: (flags) == O_RDWR ? "O_RDWR" \
: (flags) == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT" \
: "??"); \
- if (is_tainted(name) || is_tainted(dirname)) \
- { \
- log_write(0, LOG_MAIN|LOG_PANIC, "Tainted name for DB file not permitted"); \
+ if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB file not permitted", name) \
+ || is_tainted2(dirname, LOG_MAIN|LOG_PANIC, "Tainted name '%s' for DB directory not permitted", dirname)) \
*dbpp = NULL; \
- } \
else \
{ EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); } \
DEBUG(D_hints_lookup) debug_printf_indent("returned from EXIM_DBOPEN: %p\n", *dbpp); \
diff -ruN a/src/deliver.c b/src/deliver.c
--- a/src/deliver.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/deliver.c 2023-09-14 18:48:55.194596003 +0300
@@ -5538,10 +5538,11 @@
if (!s || !*s)
log_write(0, LOG_MAIN|LOG_PANIC,
"Failed to expand %s: '%s'\n", varname, filename);
-else if (*s != '/' || is_tainted(s))
- log_write(0, LOG_MAIN|LOG_PANIC,
- "%s is not %s after expansion: '%s'\n",
- varname, *s == '/' ? "untainted" : "absolute", s);
+else if (*s != '/')
+ log_write(0, LOG_MAIN|LOG_PANIC, "%s is not absolute after expansion: '%s'\n",
+ varname, s);
+else if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted %s after expansion: '%s'\n", varname, s))
+ ;
else if (!(fp = Ufopen(s, "rb")))
log_write(0, LOG_MAIN|LOG_PANIC, "Failed to open %s for %s "
"message texts: %s", s, reason, strerror(errno));
@@ -6151,9 +6152,10 @@
if (!tmp)
p->message = string_sprintf("failed to expand \"%s\" as a "
"system filter transport name", tpname);
- if (is_tainted(tmp))
- p->message = string_sprintf("attempt to used tainted value '%s' for"
- "transport '%s' as a system filter", tmp, tpname);
+ { uschar *m;
+ if ((m = is_tainted2(tmp, 0, "Tainted values '%s' " "for transport '%s' as a system filter", tmp, tpname)))
+ p->message = m;
+ }
tpname = tmp;
}
else
diff -ruN a/src/directory.c b/src/directory.c
--- a/src/directory.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/directory.c 2023-09-14 18:49:28.279405608 +0300
@@ -44,6 +44,11 @@
struct stat statbuf;
uschar * path;
+/* does not work with 4.94
+if (is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted path '%s' for new directory", name))
+ { p = US"create"; path = US name; errno = EACCES; goto bad; }
+*/
+
if (parent)
{
path = string_sprintf("%s%s%s", parent, US"/", name);
diff -ruN a/src/EDITME b/src/EDITME
--- a/src/EDITME 2021-04-30 15:08:21.000000000 +0300
+++ b/src/EDITME 2023-09-14 18:50:04.368288757 +0300
@@ -749,6 +749,13 @@
# WHITELIST_D_MACROS=TLS:SPOOL
+# The next setting enables a main config option
+# "allow_insecure_tainted_data" to turn taint failures into warnings.
+# Though this option is new, it is deprecated already now, and will be
+# ignored in future releases of Exim. It is meant as mitigation for
+# upgrading old (possibly insecure) configurations to more secure ones.
+ALLOW_INSECURE_TAINTED_DATA=yes
+
#------------------------------------------------------------------------------
# Exim has support for the AUTH (authentication) extension of the SMTP
# protocol, as defined by RFC 2554. If you don't know what SMTP authentication
@@ -877,6 +884,21 @@
#------------------------------------------------------------------------------
+# On systems which support dynamic loading of shared libraries, Exim can
+# load a local_scan function specified in its config file instead of having
+# to be recompiled with the desired local_scan function. For a full
+# description of the API to this function, see the Exim specification.
+
+DLOPEN_LOCAL_SCAN=yes
+
+# If you set DLOPEN_LOCAL_SCAN, then you need to include -rdynamic in the
+# linker flags. Without it, the loaded .so won't be able to access any
+# functions from exim.
+
+LDFLAGS += -rdynamic
+CFLAGS += -fvisibility=hidden
+
+#------------------------------------------------------------------------------
# The default distribution of Exim contains only the plain text form of the
# documentation. Other forms are available separately. If you want to install
# the documentation in "info" format, first fetch the Texinfo documentation
diff -ruN a/src/exicyclog.src b/src/exicyclog.src
--- a/src/exicyclog.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exicyclog.src 2023-09-14 18:46:06.870477454 +0300
@@ -149,12 +149,12 @@
st=' '
exim_path=`grep "^[$st]*exim_path" $config | sed "s/.*=[$st]*//"`
-if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim; fi
+if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim4; fi
-spool_directory=`$exim_path -C $config -bP spool_directory | sed 's/.*=[ ]*//'`
+spool_directory=`$exim_path -bP spool_directory | sed 's/.*=[ ]*//'`
if [ "$log_file_path" = "" ] ; then
- log_file_path=`$exim_path -C $config -bP log_file_path | sed 's/.*=[ ]*//'`
+ log_file_path=`$exim_path -bP log_file_path | sed 's/.*=[ ]*//'`
fi
# If log_file_path contains only "syslog" then no Exim log files are in use.
diff -ruN a/src/exim.c b/src/exim.c
--- a/src/exim.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exim.c 2023-09-14 18:49:54.424045404 +0300
@@ -2789,9 +2789,11 @@
else badarg = TRUE;
break;
- /* -MCG: set the queue name, to a non-default value */
+ /* -MCG: set the queue name, to a non-default value. Arguably, anything
+ from the commandline should be tainted - but we will need an untainted
+ value for the spoolfile when doing a -odi delivery process. */
- case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), TRUE);
+ case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), FALSE);
else badarg = TRUE;
break;
@@ -3233,6 +3235,13 @@
else override_local_interfaces = string_copy_taint(exim_str_fail_toolong(argv[++i], 1024, "-oX"), TRUE);
break;
+ /* -oY: Override creation of daemon notifier socket */
+
+ case 'Y':
+ if (*argrest) badarg = TRUE;
+ else notifier_socket = NULL;
+ break;
+
/* Unknown -o argument */
default:
@@ -4820,7 +4829,7 @@
/* Ensure that the user name is in a suitable form for use as a "phrase" in an
RFC822 address.*/
-originator_name = parse_fix_phrase(originator_name, Ustrlen(originator_name));
+originator_name = US parse_fix_phrase(originator_name, Ustrlen(originator_name));
/* If a message is created by this call of Exim, the uid/gid of its originator
are those of the caller. These values are overridden if an existing message is
diff -ruN a/src/exim_checkaccess.src b/src/exim_checkaccess.src
--- a/src/exim_checkaccess.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exim_checkaccess.src 2023-09-14 18:45:21.885376889 +0300
@@ -52,7 +52,7 @@
# a tab to keep the tab in one place.
exim_path=`perl -ne 'chop;if (/^\s*exim_path\s*=\s*(.*)/){print "$1\n";last;}' $config`
-if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim; fi
+if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim4; fi
#########################################################################
diff -ruN a/src/eximon.src b/src/eximon.src
--- a/src/eximon.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/eximon.src 2023-09-14 18:46:06.870477454 +0300
@@ -79,10 +79,10 @@
st=' '
EXIM_PATH=`grep "^[$st]*exim_path" $config | sed "s/.*=[$st]*//"`
-if test "$EXIM_PATH" = ""; then EXIM_PATH=BIN_DIRECTORY/exim; fi
+if test "$EXIM_PATH" = ""; then EXIM_PATH=BIN_DIRECTORY/exim4; fi
-SPOOL_DIRECTORY=`$EXIM_PATH -C $config -bP spool_directory | sed 's/.*=[ ]*//'`
-LOG_FILE_PATH=`$EXIM_PATH -C $config -bP log_file_path | sed 's/.*=[ ]*//'`
+SPOOL_DIRECTORY=`$EXIM_PATH -bP spool_directory | sed 's/.*=[ ]*//'`
+LOG_FILE_PATH=`$EXIM_PATH -bP log_file_path | sed 's/.*=[ ]*//'`
# If log_file_path is "syslog" then logging is only to syslog, and the monitor
# is unable to display a log tail unless EXIMON_LOG_FILE_PATH is set to tell
diff -ruN a/src/eximstats.src b/src/eximstats.src
--- a/src/eximstats.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/eximstats.src 2023-09-14 18:46:14.142655374 +0300
@@ -501,6 +501,10 @@
make test
make install
+On B<Debian GNU/Linux> you can use
+C<apt-get install libgd-perl libgd-text-perl libgd-graph-perl>
+instead.
+
=item B<-chartdir>I <dir>
Create the charts in the directory <dir>
@@ -533,8 +537,7 @@
=head1 AUTHOR
-There is a website at https://www.exim.org - this contains details of the
-mailing list exim-users@exim.org.
+There is a website at https://www.exim.org/.
=head1 TO DO
diff -ruN a/src/exinext.src b/src/exinext.src
--- a/src/exinext.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exinext.src 2023-09-14 18:46:06.870477454 +0300
@@ -97,9 +97,9 @@
exim_path=`grep "^[$st]*exim_path" $config | sed "s/.*=[$st]*//"`
fi
-if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim; fi
-spool_directory=`$exim_path $eximmacdef -C $config -bP spool_directory | sed 's/.*=[ ]*//'`
-qualify_domain=`$exim_path $eximmacdef -C $config -bP qualify_domain | sed 's/.*=[ ]*//'`
+if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim4; fi
+spool_directory=`$exim_path $eximmacdef -bP spool_directory | sed 's/.*=[ ]*//'`
+qualify_domain=`$exim_path $eximmacdef -bP qualify_domain | sed 's/.*=[ ]*//'`
# Now do the job. Perl uses $ so frequently that we don't want to have to
# escape them all from the shell, so pass in shell variable values as
@@ -144,7 +144,7 @@
# Run Exim to get a list of hosts for the given domain; for
# each one construct the appropriate retry key.
- open(LIST, "$exim -C $config -v -bt $address |") ||
+ open(LIST, "$exim -v -bt $address |") ||
die "can't run exim to route $address";
while (<LIST>)
@@ -181,7 +181,7 @@
# Run exim_dumpdb to get out the retry data and pick off what we want
- open(DATA, "${exim}_dumpdb $spool retry |") ||
+ open(DATA, "/usr/sbin/exim_dumpdb $spool retry |") ||
die "can't run exim_dumpdb";
while (<DATA>)
diff -ruN a/src/exiqgrep.src b/src/exiqgrep.src
--- a/src/exiqgrep.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exiqgrep.src 2023-09-14 18:45:21.885376889 +0300
@@ -24,7 +24,7 @@
use File::Basename;
# Have this variable point to your exim binary.
-my $exim = 'BIN_DIRECTORY/exim';
+my $exim = 'BIN_DIRECTORY/exim4';
my $eargs = '-bpu';
my %id;
my %opt;
diff -ruN a/src/exiwhat.src b/src/exiwhat.src
--- a/src/exiwhat.src 2021-04-30 15:08:21.000000000 +0300
+++ b/src/exiwhat.src 2023-09-14 18:46:06.870477454 +0300
@@ -98,9 +98,9 @@
st=' '
exim_path=`grep "^[$st]*exim_path" $config | sed "s/.*=[$st]*//"`
-if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim; fi
-spool_directory=`$exim_path -C $config -bP spool_directory | sed "s/.*=[ ]*//"`
-process_log_path=`$exim_path -C $config -bP process_log_path | sed "s/.*=[ ]*//"`
+if test "$exim_path" = ""; then exim_path=BIN_DIRECTORY/exim4; fi
+spool_directory=`$exim_path -bP spool_directory | sed "s/.*=[ ]*//"`
+process_log_path=`$exim_path -bP process_log_path | sed "s/.*=[ ]*//"`
# The file that Exim writes when sent the SIGUSR1 signal is specified by
# the process_log_path option. If that is not defined, Exim uses the file
diff -ruN a/src/expand.c b/src/expand.c
--- a/src/expand.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/expand.c 2023-09-14 18:48:55.198596101 +0300
@@ -4383,13 +4383,13 @@
f.expand_string_forcedfail = FALSE;
expand_string_message = US"";
-if (is_tainted(string))
+{ uschar *m;
+if ((m = is_tainted2(string, LOG_MAIN|LOG_PANIC, "Tainted string '%s' in expansion", s)))
{
- expand_string_message =
- string_sprintf("attempt to expand tainted string '%s'", s);
- log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message);
+ expand_string_message = m;
goto EXPAND_FAILED;
}
+}
while (*s != 0)
{
@@ -7629,10 +7629,12 @@
/* Manually track tainting, as we deal in individual chars below */
if (is_tainted(sub))
+ {
if (yield->s && yield->ptr)
gstring_rebuffer(yield);
else
yield->s = store_get(yield->size = Ustrlen(sub), TRUE);
+ }
/* Check the UTF-8, byte-by-byte */
@@ -8193,6 +8195,7 @@
EXPAND_FAILED:
if (left) *left = s;
DEBUG(D_expand)
+ {
DEBUG(D_noutf8)
{
debug_printf_indent("|failed to expand: %s\n", string);
@@ -8212,6 +8215,7 @@
if (f.expand_string_forcedfail)
debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n");
}
+ }
if (resetok_p && !resetok) *resetok_p = FALSE;
expand_level--;
return NULL;
diff -ruN a/src/functions.h b/src/functions.h
--- a/src/functions.h 2021-04-30 15:08:21.000000000 +0300
+++ b/src/functions.h 2023-09-14 18:48:55.198596101 +0300
@@ -1084,36 +1084,66 @@
/******************************************************************************/
/* Taint-checked file opens */
+static inline uschar *
+is_tainted2(const void *p, int lflags, const char* fmt, ...)
+{
+va_list ap;
+uschar *msg;
+rmark mark;
+
+if (!is_tainted(p))
+ return NULL;
+
+mark = store_mark();
+va_start(ap, fmt);
+msg = string_from_gstring(string_vformat(NULL, SVFMT_TAINT_NOCHK|SVFMT_EXTEND, fmt, ap));
+va_end(ap);
+
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+if (allow_insecure_tainted_data)
+ {
+ if LOGGING(tainted) log_write(0, LOG_MAIN, "Warning: %s", msg);
+ store_reset(mark);
+ return NULL;
+ }
+#endif
+
+if (lflags) log_write(0, lflags, "%s", msg);
+return msg; /* no store_reset(), as the message might be used afterwards and Exim
+ is expected to exit anyway, so we do not care about the leaked
+ storage */
+}
static inline int
exim_open2(const char *pathname, int flags)
{
-if (!is_tainted(pathname)) return open(pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return open(pathname, flags);
errno = EACCES;
return -1;
}
+
static inline int
exim_open(const char *pathname, int flags, mode_t mode)
{
-if (!is_tainted(pathname)) return open(pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return open(pathname, flags, mode);
errno = EACCES;
return -1;
}
static inline int
exim_openat(int dirfd, const char *pathname, int flags)
{
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return openat(dirfd, pathname, flags);
errno = EACCES;
return -1;
}
static inline int
exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode)
{
-if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return openat(dirfd, pathname, flags, mode);
errno = EACCES;
return -1;
}
@@ -1121,8 +1151,8 @@
static inline FILE *
exim_fopen(const char *pathname, const char *mode)
{
-if (!is_tainted(pathname)) return fopen(pathname, mode);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname);
+if (!is_tainted2(pathname, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'", pathname))
+ return fopen(pathname, mode);
errno = EACCES;
return NULL;
}
@@ -1130,8 +1160,8 @@
static inline DIR *
exim_opendir(const uschar * name)
{
-if (!is_tainted(name)) return opendir(CCS name);
-log_write(0, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name);
+if (!is_tainted2(name, LOG_MAIN|LOG_PANIC, "Tainted dirname '%s'", name))
+ return opendir(CCS name);
errno = EACCES;
return NULL;
}
diff -ruN a/src/globals.c b/src/globals.c
--- a/src/globals.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/globals.c 2023-09-14 18:50:04.368288757 +0300
@@ -98,6 +98,10 @@
BOOL move_frozen_messages = FALSE;
#endif
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+BOOL allow_insecure_tainted_data = FALSE;
+#endif
+
/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. Note that these are
@@ -117,6 +121,10 @@
const pcre *regex_DSN = NULL;
uschar *dsn_advertise_hosts = NULL;
+#ifdef DLOPEN_LOCAL_SCAN
+uschar *local_scan_path = NULL;
+#endif
+
#ifndef DISABLE_TLS
BOOL gnutls_compat_mode = FALSE;
BOOL gnutls_allow_auto_pkcs11 = FALSE;
@@ -899,7 +907,7 @@
gid_t exim_gid = EXIM_GID;
-uschar *exim_path = US BIN_DIRECTORY "/exim"
+uschar *exim_path = US BIN_DIRECTORY "/exim4"
"\0<---------------Space to patch exim_path->";
uid_t exim_uid = EXIM_UID;
int expand_level = 0; /* Nesting depth, indent for debug */
@@ -1034,6 +1042,9 @@
Li_size_reject,
Li_skip_delivery,
Li_smtp_confirmation,
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ Li_tainted,
+#endif
Li_tls_certificate_verified,
Li_tls_cipher,
-1
@@ -1101,6 +1112,9 @@
BIT_TABLE(L, smtp_protocol_error),
BIT_TABLE(L, smtp_syntax_error),
BIT_TABLE(L, subject),
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ BIT_TABLE(L, tainted),
+#endif
BIT_TABLE(L, tls_certificate_verified),
BIT_TABLE(L, tls_cipher),
BIT_TABLE(L, tls_peerdn),
diff -ruN a/src/globals.h b/src/globals.h
--- a/src/globals.h 2021-04-30 15:08:21.000000000 +0300
+++ b/src/globals.h 2023-09-14 18:50:04.368288757 +0300
@@ -77,6 +77,10 @@
extern BOOL move_frozen_messages; /* Get them out of the normal directory */
#endif
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+extern BOOL allow_insecure_tainted_data;
+#endif
+
/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. */
@@ -148,6 +152,9 @@
extern const pcre *regex_DSN; /* For recognizing DSN settings */
extern uschar *dsn_advertise_hosts; /* host for which TLS is advertised */
+#ifdef DLOPEN_LOCAL_SCAN
+extern uschar *local_scan_path; /* Path to local_scan() library */
+#endif
/* Input-reading functions for messages, so we can use special ones for
incoming TCP/IP. */
diff -ruN a/src/host.c b/src/host.c
--- a/src/host.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/host.c 2023-09-14 18:46:43.911383705 +0300
@@ -1197,9 +1197,9 @@
c++;
}
-c[-1] = '\0'; /* drop trailing colon */
+*--c = '\0'; /* drop trailing colon */
-/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, d, d + 2*(k+1)); */
+/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, buffer, buffer + 2*(k+1)); */
if (k >= 0)
{ /* collapse */
c = d + 2*(k+1);
@@ -1581,7 +1581,7 @@
if (hosts->h_aliases)
{
- int count = 1;
+ int count = 1; /* need 1 more for terminating NULL */
uschar **ptr;
for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++;
@@ -1690,7 +1690,7 @@
{
uschar **aptr = NULL;
int ssize = 264;
- int count = 0;
+ int count = 1; /* need 1 more for terminating NULL */
int old_pool = store_pool;
sender_host_dnssec = dns_is_secure(dnsa);
diff -ruN a/src/local_scan.c b/src/local_scan.c
--- a/src/local_scan.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/local_scan.c 2023-09-14 18:50:04.368288757 +0300
@@ -6,22 +6,6 @@
/* See the file NOTICE for conditions of use and distribution. */
-/******************************************************************************
-This file contains a template local_scan() function that just returns ACCEPT.
-If you want to implement your own version, you should copy this file to, say
-Local/local_scan.c, and edit the copy. To use your version instead of the
-default, you must set
-
-HAVE_LOCAL_SCAN=yes
-LOCAL_SCAN_SOURCE=Local/local_scan.c
-
-in your Local/Makefile. This makes it easy to copy your version for use with
-subsequent Exim releases.
-
-For a full description of the API to this function, see the Exim specification.
-******************************************************************************/
-
-
/* This is the only Exim header that you should include. The effect of
including any other Exim header is not defined, and may change from release to
release. Use only the documented interface! */
@@ -29,37 +13,129 @@
#include "local_scan.h"
-/* This is a "do-nothing" version of a local_scan() function. The arguments
-are:
-
- fd The file descriptor of the open -D file, which contains the
- body of the message. The file is open for reading and
- writing, but modifying it is dangerous and not recommended.
-
- return_text A pointer to an unsigned char* variable which you can set in
- order to return a text string. It is initialized to NULL.
-
-The return values of this function are:
-
- LOCAL_SCAN_ACCEPT
- The message is to be accepted. The return_text argument is
- saved in $local_scan_data.
-
- LOCAL_SCAN_REJECT
- The message is to be rejected. The returned text is used
- in the rejection message.
-
- LOCAL_SCAN_TEMPREJECT
- This specifies a temporary rejection. The returned text
- is used in the rejection message.
-*/
+#ifdef DLOPEN_LOCAL_SCAN
+#include <dlfcn.h>
+static int (*local_scan_fn)(int fd, uschar **return_text) = NULL;
+static int load_local_scan_library(void);
+#endif
int
local_scan(int fd, uschar **return_text)
{
fd = fd; /* Keep picky compilers happy */
return_text = return_text;
-return LOCAL_SCAN_ACCEPT;
+#ifdef DLOPEN_LOCAL_SCAN
+/* local_scan_path is defined AND not the empty string */
+if (local_scan_path && *local_scan_path)
+ {
+ if (!local_scan_fn)
+ {
+ if (!load_local_scan_library())
+ {
+ char *base_msg , *error_msg , *final_msg ;
+ int final_length = -1 ;
+
+ base_msg=US"Local configuration error - local_scan() library failure\n";
+ error_msg = dlerror() ;
+
+ final_length = strlen(base_msg) + strlen(error_msg) + 1 ;
+ final_msg = (char*)malloc( final_length*sizeof(char) ) ;
+ *final_msg = '\0' ;
+
+ strcat( final_msg , base_msg ) ;
+ strcat( final_msg , error_msg ) ;
+
+ *return_text = final_msg ;
+ return LOCAL_SCAN_TEMPREJECT;
+ }
+ }
+ return local_scan_fn(fd, return_text);
+ }
+else
+#endif
+ return LOCAL_SCAN_ACCEPT;
}
+#ifdef DLOPEN_LOCAL_SCAN
+
+static int load_local_scan_library(void)
+{
+/* No point in keeping local_scan_lib since we'll never dlclose() anyway */
+void *local_scan_lib = NULL;
+int (*local_scan_version_fn)(void);
+int vers_maj;
+int vers_min;
+
+local_scan_lib = dlopen(local_scan_path, RTLD_NOW);
+if (!local_scan_lib)
+ {
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library open failed - "
+ "message temporarily rejected");
+ return FALSE;
+ }
+
+local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_major");
+if (!local_scan_version_fn)
+ {
+ dlclose(local_scan_lib);
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
+ "local_scan_version_major() function - message temporarily rejected");
+ return FALSE;
+ }
+
+/* The major number is increased when the ABI is changed in a non
+ backward compatible way. */
+vers_maj = local_scan_version_fn();
+
+local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_minor");
+if (!local_scan_version_fn)
+ {
+ dlclose(local_scan_lib);
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
+ "local_scan_version_minor() function - message temporarily rejected");
+ return FALSE;
+ }
+
+/* The minor number is increased each time a new feature is added (in a
+ way that doesn't break backward compatibility) -- Marc */
+vers_min = local_scan_version_fn();
+
+
+if (vers_maj != LOCAL_SCAN_ABI_VERSION_MAJOR)
+ {
+ dlclose(local_scan_lib);
+ local_scan_lib = NULL;
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible major"
+ "version number, you need to recompile your module for this version"
+ "of exim (The module was compiled for version %d.%d and this exim provides"
+ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
+ LOCAL_SCAN_ABI_VERSION_MINOR);
+ return FALSE;
+ }
+else if (vers_min > LOCAL_SCAN_ABI_VERSION_MINOR)
+ {
+ dlclose(local_scan_lib);
+ local_scan_lib = NULL;
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible minor"
+ "version number, you need to recompile your module for this version"
+ "of exim (The module was compiled for version %d.%d and this exim provides"
+ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
+ LOCAL_SCAN_ABI_VERSION_MINOR);
+ return FALSE;
+ }
+
+local_scan_fn = dlsym(local_scan_lib, "local_scan");
+if (!local_scan_fn)
+ {
+ dlclose(local_scan_lib);
+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
+ "local_scan() function - message temporarily rejected");
+ return FALSE;
+ }
+return TRUE;
+}
+
+#endif /* DLOPEN_LOCAL_SCAN */
+
+
/* End of local_scan.c */
diff -ruN a/src/local_scan.h b/src/local_scan.h
--- a/src/local_scan.h 2021-04-30 15:08:21.000000000 +0300
+++ b/src/local_scan.h 2023-09-14 18:50:04.368288757 +0300
@@ -27,6 +27,7 @@
#include <stdarg.h>
#include <sys/types.h>
+#pragma GCC visibility push(default)
#include "config.h"
#include "mytypes.h"
#include "store.h"
@@ -166,6 +167,9 @@
extern BOOL host_checking; /* Set when checking a host */
extern uschar *interface_address; /* Interface for incoming call */
extern int interface_port; /* Port number for incoming call */
+#ifdef DLOPEN_LOCAL_SCAN
+extern uschar *local_scan_path;
+#endif
extern uschar *message_id; /* Internal id of message being handled */
extern uschar *received_protocol; /* Name of incoming protocol */
extern int recipients_count; /* Number of recipients */
@@ -235,4 +239,6 @@
extern pid_t child_open_function(uschar **, uschar **, int, int *, int *, BOOL, const uschar *);
#endif
+#pragma GCC visibility pop
+
/* End of local_scan.h */
diff -ruN a/src/log.c b/src/log.c
--- a/src/log.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/log.c 2023-09-14 18:49:41.743735097 +0300
@@ -287,8 +287,11 @@
uschar *lastslash = Ustrrchr(name, '/');
*lastslash = 0;
created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
- DEBUG(D_any) debug_printf("%s log directory %s\n",
- created ? "created" : "failed to create", name);
+ DEBUG(D_any)
+ if (created)
+ debug_printf("created log directory %s\n", name);
+ else
+ debug_printf("failed to create log directory %s: %s\n", name, strerror(errno));
*lastslash = '/';
if (created) fd = Uopen(name, flags, LOG_MODE);
}
@@ -394,9 +397,7 @@
const uid_t euid = geteuid();
if (euid == exim_uid)
- {
fd = log_open_already_exim(name);
- }
else if (euid == root_uid)
{
int sock[2];
@@ -457,7 +458,7 @@
it does not exist. This may be called recursively on failure, in order to open
the panic log.
-The directory is in the static variable file_path. This is static so that it
+The directory is in the static variable file_path. This is static so that
the work of sorting out the path is done just once per Exim process.
Exim is normally configured to avoid running as root wherever possible, the log
@@ -492,60 +493,64 @@
ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
-/* Save the name of the mainlog for rollover processing. Without a datestamp,
-it gets statted to see if it has been cycled. With a datestamp, the datestamp
-will be compared. The static slot for saving it is the same size as buffer,
-and the text has been checked above to fit, so this use of strcpy() is OK. */
-
-if (type == lt_main && string_datestamp_offset >= 0)
+switch (type)
{
- Ustrcpy(mainlog_name, buffer);
- mainlog_datestamp = mainlog_name + string_datestamp_offset;
- }
+ case lt_main:
+ /* Save the name of the mainlog for rollover processing. Without a datestamp,
+ it gets statted to see if it has been cycled. With a datestamp, the datestamp
+ will be compared. The static slot for saving it is the same size as buffer,
+ and the text has been checked above to fit, so this use of strcpy() is OK. */
+
+ Ustrcpy(mainlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ mainlog_datestamp = mainlog_name + string_datestamp_offset;
+ break;
-/* Ditto for the reject log */
+ case lt_reject:
+ /* Ditto for the reject log */
-else if (type == lt_reject && string_datestamp_offset >= 0)
- {
- Ustrcpy(rejectlog_name, buffer);
- rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
- }
+ Ustrcpy(rejectlog_name, buffer);
+ if (string_datestamp_offset > 0)
+ rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ break;
-/* and deal with the debug log (which keeps the datestamp, but does not
-update it) */
+ case lt_debug:
+ /* and deal with the debug log (which keeps the datestamp, but does not
+ update it) */
-else if (type == lt_debug)
- {
- Ustrcpy(debuglog_name, buffer);
- if (tag)
- {
- /* this won't change the offset of the datestamp */
- ok2 = string_format(buffer, sizeof(buffer), "%s%s",
- debuglog_name, tag);
- if (ok2)
- Ustrcpy(debuglog_name, buffer);
- }
- }
+ Ustrcpy(debuglog_name, buffer);
+ if (tag)
+ {
+ /* this won't change the offset of the datestamp */
+ ok2 = string_format(buffer, sizeof(buffer), "%s%s",
+ debuglog_name, tag);
+ if (ok2)
+ Ustrcpy(debuglog_name, buffer);
+ }
+ break;
-/* Remove any datestamp if this is the panic log. This is rare, so there's no
-need to optimize getting the datestamp length. We remove one non-alphanumeric
-char afterwards if at the start, otherwise one before. */
+ default:
+ /* Remove any datestamp if this is the panic log. This is rare, so there's no
+ need to optimize getting the datestamp length. We remove one non-alphanumeric
+ char afterwards if at the start, otherwise one before. */
-else if (string_datestamp_offset >= 0)
- {
- uschar * from = buffer + string_datestamp_offset;
- uschar * to = from + string_datestamp_length;
+ if (string_datestamp_offset >= 0)
+ {
+ uschar * from = buffer + string_datestamp_offset;
+ uschar * to = from + string_datestamp_length;
- if (from == buffer || from[-1] == '/')
- {
- if (!isalnum(*to)) to++;
- }
- else
- if (!isalnum(from[-1])) from--;
+ if (from == buffer || from[-1] == '/')
+ {
+ if (!isalnum(*to)) to++;
+ }
+ else
+ if (!isalnum(from[-1])) from--;
- /* This copy is ok, because we know that to is a substring of from. But
- due to overlap we must use memmove() not Ustrcpy(). */
- memmove(from, to, Ustrlen(to)+1);
+ /* This copy is ok, because we know that to is a substring of from. But
+ due to overlap we must use memmove() not Ustrcpy(). */
+ memmove(from, to, Ustrlen(to)+1);
+ }
+ break;
}
/* If the file name is too long, it is an unrecoverable disaster */
@@ -559,9 +564,7 @@
*fd = log_open_as_exim(buffer);
if (*fd >= 0)
- {
return;
- }
euid = geteuid();
@@ -713,26 +716,62 @@
}
+/* Pull the file out of the configured or the compiled-in list.
+Called for an empty log_file_path element, for debug logging activation
+when file_path has not previously been set, and from the appenfile transport setup. */
-static void
-set_file_path(void)
+void
+set_file_path(BOOL *multiple)
{
+uschar *s;
int sep = ':'; /* Fixed separator - outside use */
-uschar *t;
-const uschar *tt = US LOG_FILE_PATH;
-while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
- {
- if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
- file_path = string_copy(t);
- break;
- }
+const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
+
+if (*ss)
+ for (logging_mode = 0;
+ s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE); )
+ {
+ if (Ustrcmp(s, "syslog") == 0)
+ logging_mode |= LOG_MODE_SYSLOG;
+ else if (!(logging_mode & LOG_MODE_FILE)) /* no file yet */
+ {
+ logging_mode |= LOG_MODE_FILE;
+ if (*s) file_path = string_copy(s); /* If a non-empty path is given, use it */
+ }
+ else if (multiple) *multiple = TRUE;
+ }
+else
+ logging_mode = LOG_MODE_FILE;
+
+/* Set up the ultimate default if necessary. */
+
+if (logging_mode & LOG_MODE_FILE && !*file_path)
+ if (LOG_FILE_PATH[0])
+ {
+ /* If we still do not have a file_path, we take
+ the first non-empty, non-syslog item in LOG_FILE_PATH, if there is
+ one. If there is no such item, use the ultimate default in the
+ spool directory. */
+
+ for (ss = US LOG_FILE_PATH;
+ s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE);)
+ {
+ if (*s != '/') continue;
+ file_path = string_copy(s);
+ }
+ }
+ else file_path = string_sprintf("%s/log/%%slog", spool_directory);
}
void
mainlog_close(void)
{
-if (mainlogfd < 0) return;
+/* avoid closing it if it is closed already or if we do not see a chance
+to open the file mainlog later again */
+if (mainlogfd < 0 /* already closed */
+ || !(geteuid() == 0 || geteuid() == exim_uid))
+ return;
(void)close(mainlogfd);
mainlogfd = -1;
mainlog_inode = 0;
@@ -844,41 +883,9 @@
store_pool = POOL_PERM;
- /* If nothing has been set, don't waste effort... the default values for the
- statics are file_path="" and logging_mode = LOG_MODE_FILE. */
-
- if (*log_file_path)
- {
- int sep = ':'; /* Fixed separator - outside use */
- uschar *s;
- const uschar *ss = log_file_path;
-
- logging_mode = 0;
- while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
- {
- if (Ustrcmp(s, "syslog") == 0)
- logging_mode |= LOG_MODE_SYSLOG;
- else if (logging_mode & LOG_MODE_FILE)
- multiple = TRUE;
- else
- {
- logging_mode |= LOG_MODE_FILE;
-
- /* If a non-empty path is given, use it */
-
- if (*s)
- file_path = string_copy(s);
-
- /* If the path is empty, we want to use the first non-empty, non-
- syslog item in LOG_FILE_PATH, if there is one, since the value of
- log_file_path may have been set at runtime. If there is no such item,
- use the ultimate default in the spool directory. */
-
- else
- set_file_path(); /* Empty item in log_file_path */
- } /* First non-syslog item in log_file_path */
- } /* Scan of log_file_path */
- }
+ /* make sure that we have a valid log file path in "file_path",
+ the open_log() later relies on it */
+ set_file_path(&multiple);
/* If no modes have been selected, it is a major disaster */
@@ -886,11 +893,8 @@
die(US"Neither syslog nor file logging set in log_file_path",
US"Unexpected logging failure");
- /* Set up the ultimate default if necessary. Then revert to the old store
- pool, and record that we've sorted out the path. */
+ /* Revert to the old store pool, and record that we've sorted out the path. */
- if (logging_mode & LOG_MODE_FILE && !file_path[0])
- file_path = string_sprintf("%s/log/%%slog", spool_directory);
store_pool = old_pool;
path_inspected = TRUE;
@@ -1244,6 +1248,7 @@
if (logging_mode & LOG_MODE_FILE)
{
+ if (!*file_path) set_file_path(NULL);
panic_recurseflag = TRUE;
open_log(&paniclogfd, lt_panic, NULL); /* Won't return on failure */
panic_recurseflag = FALSE;
@@ -1499,7 +1504,7 @@
resulting in certain setup not having been done. Hack this for now so we
do not segfault; note that nondefault log locations will not work */
-if (!*file_path) set_file_path();
+if (!*file_path) set_file_path(NULL);
open_log(&fd, lt_debug, tag_name);
@@ -1521,5 +1526,14 @@
unlink_log(lt_debug);
}
+/* Called from the appendfile transport setup. */
+void
+open_logs(void)
+{
+set_file_path(NULL);
+if (!(logging_mode & LOG_MODE_FILE)) return;
+open_log(&mainlogfd, lt_main, 0);
+open_log(&rejectlogfd, lt_reject, 0);
+}
/* End of log.c */
diff -ruN a/src/lookups/lf_sqlperform.c b/src/lookups/lf_sqlperform.c
--- a/src/lookups/lf_sqlperform.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/lookups/lf_sqlperform.c 2023-09-14 18:48:55.198596101 +0300
@@ -102,11 +102,13 @@
}
}
- if (is_tainted(server))
- {
- *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+ { uschar *m;
+ if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
+ {
+ *errmsg = m;
return DEFER;
}
+ }
rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
@@ -158,11 +160,13 @@
server = ele;
}
- if (is_tainted(server))
+ { uschar *m;
+ if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
{
- *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
+ *errmsg = m;
return DEFER;
}
+ }
rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
diff -ruN a/src/macros.h b/src/macros.h
--- a/src/macros.h 2021-04-30 15:08:21.000000000 +0300
+++ b/src/macros.h 2023-09-14 18:47:06.747942448 +0300
@@ -497,6 +497,9 @@
Li_smtp_mailauth,
Li_smtp_no_mail,
Li_subject,
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ Li_tainted,
+#endif
Li_tls_certificate_verified,
Li_tls_cipher,
Li_tls_peerdn,
diff -ruN a/src/parse.c b/src/parse.c
--- a/src/parse.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/parse.c 2023-09-14 18:48:55.198596101 +0300
@@ -1410,12 +1410,8 @@
return FF_ERROR;
}
- if (is_tainted(filename))
- {
- *error = string_sprintf("Tainted name '%s' for included file not permitted\n",
- filename);
+ if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for included file not permitted\n", filename)))
return FF_ERROR;
- }
/* Check file name if required */
diff -ruN a/src/rda.c b/src/rda.c
--- a/src/rda.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/rda.c 2023-09-14 18:48:55.198596101 +0300
@@ -179,10 +179,8 @@
/* Reading a file is a form of expansion; we wish to deny attackers the
capability to specify the file name. */
-if (is_tainted(filename))
+if ((*error = is_tainted2(filename, 0, "Tainted name '%s' for file read not permitted\n", filename)))
{
- *error = string_sprintf("Tainted name '%s' for file read not permitted\n",
- filename);
*yield = FF_ERROR;
return NULL;
}
diff -ruN a/src/readconf.c b/src/readconf.c
--- a/src/readconf.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/readconf.c 2023-09-14 18:50:04.372288856 +0300
@@ -68,6 +68,9 @@
{ "add_environment", opt_stringptr, {&add_environment} },
{ "admin_groups", opt_gidlist, {&admin_groups} },
{ "allow_domain_literals", opt_bool, {&allow_domain_literals} },
+#ifdef ALLOW_INSECURE_TAINTED_DATA
+ { "allow_insecure_tainted_data", opt_bool, {&allow_insecure_tainted_data} },
+#endif
{ "allow_mx_to_ip", opt_bool, {&allow_mx_to_ip} },
{ "allow_utf8_domains", opt_bool, {&allow_utf8_domains} },
{ "auth_advertise_hosts", opt_stringptr, {&auth_advertise_hosts} },
@@ -205,6 +208,9 @@
{ "local_from_prefix", opt_stringptr, {&local_from_prefix} },
{ "local_from_suffix", opt_stringptr, {&local_from_suffix} },
{ "local_interfaces", opt_stringptr, {&local_interfaces} },
+#ifdef DLOPEN_LOCAL_SCAN
+ { "local_scan_path", opt_stringptr, &local_scan_path },
+#endif
#ifdef HAVE_LOCAL_SCAN
{ "local_scan_timeout", opt_time, {&local_scan_timeout} },
#endif
diff -ruN a/src/routers/rf_get_transport.c b/src/routers/rf_get_transport.c
--- a/src/routers/rf_get_transport.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/routers/rf_get_transport.c 2023-09-14 18:48:15.485624338 +0300
@@ -66,10 +66,8 @@
"\"%s\" in %s router: %s", tpname, router_name, expand_string_message);
return FALSE;
}
- if (is_tainted(ss))
+ if (is_tainted2(ss, LOG_MAIN|LOG_PANIC, "Tainted tainted value '%s' from '%s' for transport", ss, tpname))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted value '%s' from '%s' for transport", ss, tpname);
addr->basic_errno = ERRNO_BADTRANSPORT;
/* Avoid leaking info to an attacker */
addr->message = US"internal configuration error";
diff -ruN a/src/search.c b/src/search.c
--- a/src/search.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/search.c 2023-09-14 18:47:18.844238414 +0300
@@ -343,12 +343,8 @@
uschar keybuffer[256];
int old_pool = store_pool;
-if (filename && is_tainted(filename))
- {
- log_write(0, LOG_MAIN|LOG_PANIC,
- "Tainted filename for search: '%s'", filename);
+if (filename && is_tainted2(filename, LOG_MAIN|LOG_PANIC, "Tainted filename for search '%s'", filename))
return NULL;
- }
/* Change to the search store pool and remember our reset point */
@@ -639,7 +635,7 @@
/* Arrange to put this database at the top of the LRU chain if it is a type
that opens real files. */
-if ( open_top != (tree_node *)handle
+if ( open_top != (tree_node *)handle
&& lookup_list[t->name[0]-'0']->type == lookup_absfile)
{
search_cache *c = (search_cache *)(t->data.ptr);
diff -ruN a/src/smtp_out.c b/src/smtp_out.c
--- a/src/smtp_out.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/smtp_out.c 2023-09-14 18:48:24.277839477 +0300
@@ -53,11 +53,8 @@
return FALSE;
}
-if (is_tainted(expint))
+if (is_tainted2(expint, LOG_MAIN|LOG_PANIC, "Tainted value '%s' from '%s' for interface", expint, istring))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted value '%s' from '%s' for interface",
- expint, istring);
addr->transport_return = PANIC;
addr->message = string_sprintf("failed to expand \"interface\" "
"option for %s: configuration error", msg);
@@ -425,7 +422,7 @@
{
int sock = socks_sock_connect(sc->host, sc->host_af, port, sc->interface,
sc->tblock, ob->connect_timeout);
-
+
if (sock >= 0)
{
if (early_data && early_data->data && early_data->len)
diff -ruN a/src/string.c b/src/string.c
--- a/src/string.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/string.c 2023-09-14 18:50:04.372288856 +0300
@@ -418,6 +418,7 @@
#if (defined(HAVE_LOCAL_SCAN) || defined(EXPAND_DLFUNC)) \
&& !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+#pragma GCC visibility push(default)
/*************************************************
* Copy and save string *
*************************************************/
@@ -470,6 +471,7 @@
ss[n] = 0;
return ss;
}
+#pragma GCC visibility pop
#endif
diff -ruN a/src/transports/appendfile.c b/src/transports/appendfile.c
--- a/src/transports/appendfile.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/transports/appendfile.c 2023-09-14 18:49:20.139206410 +0300
@@ -217,6 +217,9 @@
Returns: OK, FAIL, or DEFER
*/
+void
+open_logs(void);
+
static int
appendfile_transport_setup(transport_instance *tblock, address_item *addrlist,
transport_feedback *dummy, uid_t uid, gid_t gid, uschar **errmsg)
@@ -231,6 +234,9 @@
uid = uid;
gid = gid;
+/* we can't wait until we're not privileged anymore */
+open_logs();
+
if (ob->expand_maildir_use_size_file)
ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
US"`maildir_use_size_file` in transport", tblock->name);
@@ -1286,12 +1292,14 @@
expand_string_message);
goto ret_panic;
}
-if (is_tainted(path))
+{ uschar *m;
+if ((m = is_tainted2(path, 0, "Tainted '%s' (file or directory "
+ "name for %s transport) not permitted", path, tblock->name)))
{
- addr->message = string_sprintf("Tainted '%s' (file or directory "
- "name for %s transport) not permitted", path, tblock->name);
+ addr->message = m;
goto ret_panic;
}
+}
if (path[0] != '/')
{
diff -ruN a/src/transports/autoreply.c b/src/transports/autoreply.c
--- a/src/transports/autoreply.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/transports/autoreply.c 2023-09-14 18:48:55.198596101 +0300
@@ -404,14 +404,15 @@
if (oncelog && *oncelog && to)
{
+ uschar *m;
time_t then = 0;
- if (is_tainted(oncelog))
+ if ((m = is_tainted2(oncelog, 0, "Tainted '%s' (once file for %s transport)"
+ " not permitted", oncelog, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (once file for %s transport)"
- " not permitted", oncelog, tblock->name);
+ addr->message = m;
goto END_OFF;
}
@@ -515,13 +516,14 @@
if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec))
{
+ uschar *m;
int log_fd;
- if (is_tainted(logfile))
+ if ((m = is_tainted2(logfile, 0, "Tainted '%s' (logfile for %s transport)"
+ " not permitted", logfile, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (logfile for %s transport)"
- " not permitted", logfile, tblock->name);
+ addr->message = m;
goto END_OFF;
}
@@ -548,12 +550,13 @@
/* We are going to send a message. Ensure any requested file is available. */
if (file)
{
- if (is_tainted(file))
+ uschar *m;
+ if ((m = is_tainted2(file, 0, "Tainted '%s' (file for %s transport)"
+ " not permitted", file, tblock->name)))
{
addr->transport_return = DEFER;
addr->basic_errno = EACCES;
- addr->message = string_sprintf("Tainted '%s' (file for %s transport)"
- " not permitted", file, tblock->name);
+ addr->message = m;
return FALSE;
}
if (!(ff = Ufopen(file, "rb")) && !ob->file_optional)
diff -ruN a/src/transports/pipe.c b/src/transports/pipe.c
--- a/src/transports/pipe.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/transports/pipe.c 2023-09-14 18:48:55.202596199 +0300
@@ -599,13 +599,16 @@
tblock->name);
return FALSE;
}
-if (is_tainted(cmd))
+
+{ uschar *m;
+if ((m = is_tainted2(cmd, 0, "Tainted '%s' (command "
+ "for %s transport) not permitted", cmd, tblock->name)))
{
- addr->message = string_sprintf("Tainted '%s' (command "
- "for %s transport) not permitted", cmd, tblock->name);
addr->transport_return = PANIC;
+ addr->message = m;
return FALSE;
}
+}
/* When a pipe is set up by a filter file, there may be values for $thisaddress
and numerical the variables in existence. These are passed in
diff -ruN a/src/transports/smtp.c b/src/transports/smtp.c
--- a/src/transports/smtp.c 2021-04-30 15:08:21.000000000 +0300
+++ b/src/transports/smtp.c 2023-09-14 18:48:28.641946264 +0300
@@ -2015,7 +2015,7 @@
{
case OK: sx->conn_args.dane = TRUE;
ob->tls_tempfail_tryclear = FALSE; /* force TLS */
- ob->tls_sni = sx->first_addr->domain; /* force SNI */
+ ob->tls_sni = sx->conn_args.host->name; /* force SNI */
break;
case FAIL_FORCED: break;
default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
@@ -2097,7 +2097,7 @@
{
case OK: sx->conn_args.dane = TRUE;
ob->tls_tempfail_tryclear = FALSE; /* force TLS */
- ob->tls_sni = sx->first_addr->domain; /* force SNI */
+ ob->tls_sni = sx->conn_args.host->name; /* force SNI */
break;
case FAIL_FORCED: break;
default: set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
@@ -4715,11 +4715,8 @@
else
if (ob->hosts_randomize) s = expanded_hosts = string_copy(s);
- if (is_tainted(s))
+ if (is_tainted2(s, LOG_MAIN|LOG_PANIC, "Tainted host list '%s' from '%s' in transport %s", s, ob->hosts, tblock->name))
{
- log_write(0, LOG_MAIN|LOG_PANIC,
- "attempt to use tainted host list '%s' from '%s' in transport %s",
- s, ob->hosts, tblock->name);
/* Avoid leaking info to an attacker */
addrlist->message = US"internal configuration error";
addrlist->transport_return = PANIC;