diff -urN exim-4.94.org/src/config.h.defaults exim-4.94/src/config.h.defaults --- exim-4.94.org/src/config.h.defaults 2020-05-30 22:35:38.000000000 +0200 +++ exim-4.94/src/config.h.defaults 2020-11-27 08:10:34.967732017 +0100 @@ -33,6 +33,8 @@ #define AUTH_VARS 3 +#define DLOPEN_LOCAL_SCAN + #define BIN_DIRECTORY #define CONFIGURE_FILE diff -urN exim-4.94.org/src/EDITME exim-4.94/src/EDITME --- exim-4.94.org/src/EDITME 2020-11-27 08:10:27.727507700 +0100 +++ exim-4.94/src/EDITME 2020-11-27 08:10:34.967732017 +0100 @@ -878,6 +878,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 -urN exim-4.94.org/src/globals.c exim-4.94/src/globals.c --- exim-4.94.org/src/globals.c 2020-11-27 08:10:27.714173954 +0100 +++ exim-4.94/src/globals.c 2020-11-27 08:10:34.967732017 +0100 @@ -117,6 +117,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; diff -urN exim-4.94.org/src/globals.h exim-4.94/src/globals.h --- exim-4.94.org/src/globals.h 2020-11-27 08:10:27.714173954 +0100 +++ exim-4.94/src/globals.h 2020-11-27 08:10:34.967732017 +0100 @@ -148,6 +148,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 -urN exim-4.94.org/src/local_scan.c exim-4.94/src/local_scan.c --- exim-4.94.org/src/local_scan.c 2020-05-30 22:35:38.000000000 +0200 +++ exim-4.94/src/local_scan.c 2020-11-27 08:10:34.967732017 +0100 @@ -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,130 @@ #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 +#include +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 -urN exim-4.94.org/src/local_scan.h exim-4.94/src/local_scan.h --- exim-4.94.org/src/local_scan.h 2020-05-30 22:35:38.000000000 +0200 +++ exim-4.94/src/local_scan.h 2020-11-27 08:10:34.967732017 +0100 @@ -27,6 +27,7 @@ #include #include +#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 -urN exim-4.94.org/src/readconf.c exim-4.94/src/readconf.c --- exim-4.94.org/src/readconf.c 2020-11-27 08:10:27.704173644 +0100 +++ exim-4.94/src/readconf.c 2020-11-27 08:10:34.967732017 +0100 @@ -205,6 +205,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 -urN exim-4.94.org/src/string.c exim-4.94/src/string.c --- exim-4.94.org/src/string.c 2020-11-27 08:10:27.704173644 +0100 +++ exim-4.94/src/string.c 2020-11-27 08:10:34.971065453 +0100 @@ -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