Files
openwrt-packages/mail/exim/patches/100-localscan_dlopen.patch
Daniel Golle e8600462c7 exim: update to 4.97.1
IPv6 has accidentally been disabled in all Exim builds since the
package was introduced in OpenWrt due to a faulty `sed` script. This
has now been fixed, so beware that IPv6 is now enabled when updating
from previous releases.

Upstream changes since version 4.96.2 (bottom up):

JH/s1 Refuse to accept a line "dot, LF" as end-of-DATA unless operating in
      LF-only mode (as detected from the first header line).  Previously we did
      accept that in (normal) CRLF mode; this has been raised as a possible
      attack scenario (under the name "smtp smuggling", CVE-2023-51766).

JH/01 The hosts_connection_nolog main option now also controls "no MAIL in
      SMTP connection" log lines.

JH/02 Option default value updates:
        - queue_fast_ramp (main)        true (was false)
        - remote_max_parallel (main)    4 (was 2)

JH/03 Cache static regex pattern compilations, for use by ACLs.

JH/04 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
      Make the rewrite never match and keep the logging.  Trust the
      admin to be using verify=header-syntax (to actually reject the message).

JH/05 Follow symlinks for placing a watch on TLS creds files.  This means
      (under Linux) we watch the dir containing the final file; previously
      it would be the dir with the first symlink.  We still do not monitor
      the entire path.

JH/06 Check for bad chars in rDNS for sender_host_name.  The OpenBSD (at least)
      dn_expand() is happy to pass them through.

JH/07 OpenSSL Fix auto-reload of changed server OCSP proof.  Previously, if
      the file with the proof had an unchanged name, the new proof(s) were
      loaded on top of the old ones (and nover used; the old ones were stapled).

JH/08 Bug 2915: Fix use-after-free for $regex<n> variables. Previously when
      more than one message arrived in a single connection a reference from
      the earlier message could be re-used.  Often a sigsegv resulted.
      These variables were introduced in Exim 4.87.
      Debug help from Graeme Fowler.

JH/09 Fix ${filter } for conditions that modify $value.  Previously the
      modified version would be used in construction the result, and a memory
      error would occur.

JH/10 GnuTLS: fix for (IOT?) clients offering no TLS extensions at all.
      Find and fix by Jasen Betts.

JH/11 OpenSSL: fix for ancient clients needing TLS support for versions earlier
      than TLSv1,2,  Previously, more-recent versions of OpenSSL were permitting
      the systemwide configuration to override the Exim config.

HS/01 Bug 2728: Introduce EDITME option "DMARC_API" to work around incompatible
      API changes in libopendmarc.

JH/12 Bug 2930: Fix daemon startup.  When started from any process apart from
      pid 1, in the normal "background daemon" mode, having to drop process-
      group leadership also lost track of needing to create listener sockets.

JH/13 Bug 2929: Fix using $recipients after ${run...}.  A change made for 4.96
      resulted in the variable appearing empty.  Find and fix by Ruben Jenster.

JH/14 Bug 2933: Fix regex substring match variables for null matches. Since 4.96
      a capture group which obtained no text (eg. "(abc)*" matching zero
      occurrences) could cause a segfault if the corresponding $<n> was
      expanded.

JH/15 Fix argument parsing for ${run } expansion. Previously, when an argument
      included a close-brace character (eg. it itself used an expansion) an
      error occurred.

JH/16 Move running the smtp connect ACL to before, for TLS-on-connect ports,
      starting TLS.  Previously it was after, meaning that attackers on such
      ports had to be screened using the host_reject_connection main config
      option. The new sequence aligns better with the STARTTLS behaviour, and
      permits defences against crypto-processing load attacks, even though it
      is strictly an incompatible change.
      Also, avoid sending any SMTP fail response for either the connect ACL
      or host_reject_connection, for TLS-on-connect ports.

JH/17 Permit the ACL "encrypted" condition to be used in a HELO/EHLO ACL,
      Previously this was not permitted, but it makes reasonable sense.
      While there, restore a restriction on using it from a connect ACL; given
      the change JH/16 it could only return false (and before 4.91 was not
      permitted).

JH/18 Fix a fencepost error in logging.  Previously (since 4.92) when a log line
      was exactly sized compared to the log buffer, a crash occurred with the
      misleading message "bad memory reference; pool not found".
      Found and traced by Jasen Betts.

JH/19 Bug 2911: Fix a recursion in DNS lookups.  Previously, if the main option
      dns_again_means_nonexist included an element causing a DNS lookup which
      itself returned DNS_AGAIN, unbounded recursion occurred.  Possible results
      included (though probably not limited to) a process crash from stack
      memory limit, or from excessive open files.  Replace this with a paniclog
      whine (as this is likely a configuration error), and returning
      DNS_NOMATCH.

JH/20 Bug 2954: (OpenSSL) Fix setting of explicit EC curve/group.  Previously
      this always failed, probably leading to the usual downgrade to in-clear
      connections.

JH/21 Fix TLSA lookups.  Previously dns_again_means_nonexist would affect
      SERVFAIL results, which breaks the downgrade resistance of DANE.  Change
      to not checking that list for these lookups.

JH/22 Bug 2434: Add connection-elapsed "D=" element to more connection
      closure log lines.

JH/23 Fix crash in string expansions. Previously, if an empty variable was
      immediately followed by an expansion operator, a null-indirection read
      was done, killing the process.

JH/24 Bug 2997: When built with EXPERIMENTAL_DSN_INFO, bounce messages can
      include an SMTP response string which is longer than that supported
      by the delivering transport.  Alleviate by wrapping such lines before
      column 80.

JH/25 Bug 2827: Restrict size of References: header in bounce messages to 998
      chars (RFC limit).  Previously a limit of 12 items was made, which with
      a not-impossible References: in the message being bounced could still
      be over-large and get stopped in the transport.

JH/26 For a ${readsocket } in TLS mode, send a TLS Close Alert before the TCP
      close.  Previously a bare socket close was done.

JH/27 Fix ${srs_encode ..}.  Previously it would give a bad result for one day
      every 1024 days.

JH/28 Bug 2996: Fix a crash in the smtp transport.  When finding that the
      message being considered for delivery was already being handled by
      another process, and having an SMTP connection already open, the function
      to close it tried to use an uninitialized variable.  This would afftect
      high-volume sites more, especially when running mailing-list-style loads.
      Pollution of logs was the major effect, as the other process delivered
      the message.  Found and partly investigated by Graeme Fowler.

JH/29 Change format of the internal ID used for message identification. The old
      version only supported 31 bits for a PID element; the new 64 (on systems
      which can use Base-62 encoding, which is all currently supported ones
      but not Darwin (MacOS) or Cygwin, which have case-insensitive filesystems
      and must use Base-36).  The new ID is 23 characters rather than 16, and is
      visible in various places - notably logs, message headers, and spool file
      names.  Various of the ancillary utilities also have to know the format.
        As well as the expanded PID portion, the sub-second part of the time
      recorded in the ID is expanded to support finer precision.  Theoretically
      this permits a receive rate from a single comms channel of better than the
      previous 2000/sec.
        The major timestamp part of the ID is not changed; at 6 characters it is
      usable until about year 3700.
        Updating from previously releases is fully supported: old-format spool
      files are still usable, and the utilities support both formats.  New
      message will use the new format.  The one hints-DB file type which uses
      message-IDs (the transport wait- DB) will be discarded if an old-format ID
      is seen; new ones will be built with only new-format IDs.
      Optionally, a utility can be used to convert spool files from old to new,
      but this is only an efficiency measure not a requirement for operation
        Downgrading from new to old requires running a provided utility, having
      first stopped all operations.  This will convert any spool files from new
      back to old (losing time-precision and PID information) and remove any
      wait- hints databases.

JH/30 Bug 3006: Fix handling of JSON strings having embedded commas. Previously
      we treated them as item separators when parsing for a list item, but they
      need to be protected by the doublequotes.  While there, add handling for
      backslashes.

JH/31 Bug 2998: Fix ${utf8clean:...} to disallow UTF-16 surrogate codepoints.
      Found and fixed by Jasen Betts. No testcase for this as my usual text
      editor insists on emitting only valid UTF-8.

JH/32 Fix "tls_dhparam = none" under GnuTLS.  At least with 3.7.9 this gave
      a null-indirection SIGSEGV for the receive process.

JH/33 Fix free for live variable $value created by a ${run ...} expansion during
      -bh use.  Internal checking would spot this and take a panic.

JH/34 Bug 3013: Fix use of $recipients within arguments for ${run...}.
      In 4.96 this would expand to empty.

JH/35 Bug 3014: GnuTLS: fix expiry date for an auto-generated server
      certificate.  Find and fix by Andreas Metzler.

JH/36 Add ARC info to DMARC hostory records.

JH/37 Bug 3016: Avoid sending DSN when message was accepted under fakereject
      or fakedefer.  Previously the sender could discover that the message
      had in fact been accepted.

JH/38 Taint-track intermediate values from the peer in multi-stage authentation
      sequences.  Previously the input was not noted as being tainted; notably
      this resulted in behaviour of LOGIN vs. PLAIN being inconsistent under
      bad coding of authenticators.

JH/39 Bug 3023: Fix crash induced by some combinations of zero-length strings
      and ${tr...}.  Found and diagnosed by Heiko Schlichting.

JH/40 Bug 2999: Fix a possible OOB write in the external authenticator, which
      CVE-2023-42115

JH/41 Bug 3000: Fix a possible OOB write in the SPA authenticator, which could
      be triggered by externally-controlled input.  Found by Trend Micro.
      CVE-2023-42116

JH/42 Bug 3001: Fix a possible OOB read in the SPA authenticator, which could
      be triggered by externally-controlled input.  Found by Trend Micro.
      CVE-2023-42114

JH/43 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
      Make the rewrite never match and keep the logging.  Trust the
      admin to be using verify=header-syntax (to actually reject the message).

JH/44 Bug 3033: Harden dnsdb lookups against crafted DNS responses.
      CVE-2023-42219
      could be triggered by externally-supplied input.  Found by Trend Micro.
      CVE-2023-42115

JH/41 Bug 3000: Fix a possible OOB write in the SPA authenticator, which could
      be triggered by externally-controlled input.  Found by Trend Micro.
      CVE-2023-42116

JH/42 Bug 3001: Fix a possible OOB read in the SPA authenticator, which could
      be triggered by externally-controlled input.  Found by Trend Micro.
      CVE-2023-42114

JH/43 Bug 2903: avoid exit on an attempt to rewrite a malformed address.
      Make the rewrite never match and keep the logging.  Trust the
      admin to be using verify=header-syntax (to actually reject the message).

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2024-04-08 02:30:07 +01:00

306 lines
10 KiB
Diff

Description: Allow one to use and switch between different local_scan functions
without recompiling exim.
http://marc.merlins.org/linux/exim/files/sa-exim-current/ Original patch from
David Woodhouse, modified first by Derrick 'dman' Hudson and then by Marc
MERLIN for SA-Exim and minor/major API version tracking
Author: David Woodhouse, Derrick 'dman' Hudson, Marc MERLIN
Origin: other, http://marc.merlins.org/linux/exim/files/sa-exim-current/
Forwarded: https://bugs.exim.org/show_bug.cgi?id=2671
Last-Update: 2021-07-28
--- a/src/EDITME
+++ b/src/EDITME
@@ -904,6 +904,21 @@ HEADERS_CHARSET="ISO-8859-1"
#------------------------------------------------------------------------------
+# 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
--- a/src/config.h.defaults
+++ b/src/config.h.defaults
@@ -33,6 +33,8 @@ Do not put spaces between # and the 'def
#define AUTH_VARS 4
+#define DLOPEN_LOCAL_SCAN
+
#define BIN_DIRECTORY
#define CONFIGURE_FILE
--- a/src/globals.c
+++ b/src/globals.c
@@ -118,6 +118,10 @@ int dsn_ret = 0;
const pcre2_code *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;
--- a/src/globals.h
+++ b/src/globals.h
@@ -157,6 +157,9 @@ extern int dsn_ret; /
extern const pcre2_code *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. */
--- a/src/local_scan.c
+++ b/src/local_scan.c
@@ -8,58 +8,133 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
-/******************************************************************************
-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! */
#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)
{
-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 */
--- a/src/local_scan.h
+++ b/src/local_scan.h
@@ -28,6 +28,7 @@ settings, and the store functions. */
#include <stdarg.h>
#include <sys/types.h>
+#pragma GCC visibility push(default)
#include "config.h"
#include "mytypes.h"
#include "store.h"
@@ -177,6 +178,9 @@ extern header_line *header_list; /
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 */
@@ -247,4 +251,6 @@ extern pid_t child_open_exim2_functio
extern pid_t child_open_function(uschar **, uschar **, int, int *, int *, BOOL, const uschar *);
#endif
+#pragma GCC visibility pop
+
/* End of local_scan.h */
--- a/src/readconf.c
+++ b/src/readconf.c
@@ -216,6 +216,9 @@ static optionlist optionlist_config[] =
{ "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
--- a/src/string.c
+++ b/src/string.c
@@ -453,6 +453,7 @@ return ss;
#if (defined(HAVE_LOCAL_SCAN) || defined(EXPAND_DLFUNC)) \
&& !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
+#pragma GCC visibility push(default)
/*************************************************
* Copy and save string *
*************************************************/
@@ -498,6 +499,7 @@ string_copyn_function(const uschar * s,
{
return string_copyn(s, n);
}
+#pragma GCC visibility pop
#endif