Import Debian changes 4.92-8+deb10u3
[hcoop/debian/exim4.git] / debian / patches / 90_localscan_dlopen.dpatch
CommitLineData
01e60269 1Description: Allow one to use and switch between different local_scan functions
de45f55a
AM
2 without recompiling exim.
3 http://marc.merlins.org/linux/exim/files/sa-exim-current/ Original patch from
4 David Woodhouse, modified first by Derrick 'dman' Hudson and then by Marc
5 MERLIN for SA-Exim and minor/major API version tracking
6Author: David Woodhouse, Derrick 'dman' Hudson, Marc MERLIN
7Origin: other, http://marc.merlins.org/linux/exim/files/sa-exim-current/
8Forwarded: no
01e60269 9Last-Update: 2018-12-12
de45f55a
AM
10
11--- a/src/EDITME
12+++ b/src/EDITME
01e60269 13@@ -824,6 +824,21 @@ HEADERS_CHARSET="ISO-8859-1"
de45f55a
AM
14
15
16 #------------------------------------------------------------------------------
17+# On systems which support dynamic loading of shared libraries, Exim can
18+# load a local_scan function specified in its config file instead of having
19+# to be recompiled with the desired local_scan function. For a full
20+# description of the API to this function, see the Exim specification.
21+
22+DLOPEN_LOCAL_SCAN=yes
23+
24+# If you set DLOPEN_LOCAL_SCAN, then you need to include -rdynamic in the
25+# linker flags. Without it, the loaded .so won't be able to access any
26+# functions from exim.
27+
28+LDFLAGS += -rdynamic
29+CFLAGS += -fvisibility=hidden
30+
31+#------------------------------------------------------------------------------
32 # The default distribution of Exim contains only the plain text form of the
33 # documentation. Other forms are available separately. If you want to install
34 # the documentation in "info" format, first fetch the Texinfo documentation
35--- a/src/config.h.defaults
36+++ b/src/config.h.defaults
01e60269 37@@ -32,6 +32,8 @@ Do not put spaces between # and the 'def
de45f55a
AM
38
39 #define AUTH_VARS 3
40
41+#define DLOPEN_LOCAL_SCAN
42+
43 #define BIN_DIRECTORY
44
45 #define CONFIGURE_FILE
46--- a/src/globals.c
47+++ b/src/globals.c
01e60269 48@@ -141,6 +141,10 @@ int dsn_ret = 0;
0baa7b9d 49 const pcre *regex_DSN = NULL;
de45f55a 50 uschar *dsn_advertise_hosts = NULL;
de45f55a
AM
51
52+#ifdef DLOPEN_LOCAL_SCAN
53+uschar *local_scan_path = NULL;
54+#endif
55+
56 #ifdef SUPPORT_TLS
57 BOOL gnutls_compat_mode = FALSE;
58 BOOL gnutls_allow_auto_pkcs11 = FALSE;
59--- a/src/globals.h
60+++ b/src/globals.h
01e60269 61@@ -138,6 +138,9 @@ extern int dsn_ret; /
0baa7b9d 62 extern const pcre *regex_DSN; /* For recognizing DSN settings */
de45f55a 63 extern uschar *dsn_advertise_hosts; /* host for which TLS is advertised */
de45f55a
AM
64
65+#ifdef DLOPEN_LOCAL_SCAN
66+extern uschar *local_scan_path; /* Path to local_scan() library */
67+#endif
68 /* Input-reading functions for messages, so we can use special ones for
69 incoming TCP/IP. */
70
71--- a/src/local_scan.c
72+++ b/src/local_scan.c
01e60269 73@@ -5,61 +5,131 @@
de45f55a
AM
74 /* Copyright (c) University of Cambridge 1995 - 2009 */
75 /* See the file NOTICE for conditions of use and distribution. */
76
77+#include "exim.h"
78
79-/******************************************************************************
80-This file contains a template local_scan() function that just returns ACCEPT.
81-If you want to implement your own version, you should copy this file to, say
82-Local/local_scan.c, and edit the copy. To use your version instead of the
83-default, you must set
84-
01e60269 85-HAVE_LOCAL_SCAN=yes
de45f55a
AM
86-LOCAL_SCAN_SOURCE=Local/local_scan.c
87-
88-in your Local/Makefile. This makes it easy to copy your version for use with
89-subsequent Exim releases.
90-
91-For a full description of the API to this function, see the Exim specification.
92-******************************************************************************/
93-
94-
95-/* This is the only Exim header that you should include. The effect of
96-including any other Exim header is not defined, and may change from release to
97-release. Use only the documented interface! */
98-
99-#include "local_scan.h"
100-
101-
102-/* This is a "do-nothing" version of a local_scan() function. The arguments
103-are:
104-
105- fd The file descriptor of the open -D file, which contains the
106- body of the message. The file is open for reading and
107- writing, but modifying it is dangerous and not recommended.
108-
109- return_text A pointer to an unsigned char* variable which you can set in
110- order to return a text string. It is initialized to NULL.
111-
112-The return values of this function are:
113-
114- LOCAL_SCAN_ACCEPT
115- The message is to be accepted. The return_text argument is
116- saved in $local_scan_data.
117-
118- LOCAL_SCAN_REJECT
119- The message is to be rejected. The returned text is used
120- in the rejection message.
121-
122- LOCAL_SCAN_TEMPREJECT
123- This specifies a temporary rejection. The returned text
124- is used in the rejection message.
125-*/
126+#ifdef DLOPEN_LOCAL_SCAN
127+#include <dlfcn.h>
128+static int (*local_scan_fn)(int fd, uschar **return_text) = NULL;
129+static int load_local_scan_library(void);
130+#endif
131
132 int
133 local_scan(int fd, uschar **return_text)
134 {
135 fd = fd; /* Keep picky compilers happy */
136 return_text = return_text;
137-return LOCAL_SCAN_ACCEPT;
138+#ifdef DLOPEN_LOCAL_SCAN
139+/* local_scan_path is defined AND not the empty string */
140+if (local_scan_path && *local_scan_path)
141+ {
142+ if (!local_scan_fn)
143+ {
144+ if (!load_local_scan_library())
145+ {
146+ char *base_msg , *error_msg , *final_msg ;
147+ int final_length = -1 ;
148+
149+ base_msg=US"Local configuration error - local_scan() library failure\n";
150+ error_msg = dlerror() ;
151+
152+ final_length = strlen(base_msg) + strlen(error_msg) + 1 ;
153+ final_msg = (char*)malloc( final_length*sizeof(char) ) ;
154+ *final_msg = '\0' ;
155+
156+ strcat( final_msg , base_msg ) ;
157+ strcat( final_msg , error_msg ) ;
158+
159+ *return_text = final_msg ;
160+ return LOCAL_SCAN_TEMPREJECT;
161+ }
162+ }
163+ return local_scan_fn(fd, return_text);
164+ }
165+else
166+#endif
167+ return LOCAL_SCAN_ACCEPT;
168+}
169+
170+#ifdef DLOPEN_LOCAL_SCAN
171+
172+static int load_local_scan_library(void)
173+{
174+/* No point in keeping local_scan_lib since we'll never dlclose() anyway */
175+void *local_scan_lib = NULL;
176+int (*local_scan_version_fn)(void);
177+int vers_maj;
178+int vers_min;
179+
180+local_scan_lib = dlopen(local_scan_path, RTLD_NOW);
181+if (!local_scan_lib)
182+ {
183+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library open failed - "
184+ "message temporarily rejected");
185+ return FALSE;
186+ }
187+
188+local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_major");
189+if (!local_scan_version_fn)
190+ {
191+ dlclose(local_scan_lib);
192+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
193+ "local_scan_version_major() function - message temporarily rejected");
194+ return FALSE;
195+ }
196+
197+/* The major number is increased when the ABI is changed in a non
198+ backward compatible way. */
199+vers_maj = local_scan_version_fn();
200+
201+local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_minor");
202+if (!local_scan_version_fn)
203+ {
204+ dlclose(local_scan_lib);
205+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
206+ "local_scan_version_minor() function - message temporarily rejected");
207+ return FALSE;
208+ }
209+
210+/* The minor number is increased each time a new feature is added (in a
211+ way that doesn't break backward compatibility) -- Marc */
212+vers_min = local_scan_version_fn();
213+
214+
215+if (vers_maj != LOCAL_SCAN_ABI_VERSION_MAJOR)
216+ {
217+ dlclose(local_scan_lib);
218+ local_scan_lib = NULL;
219+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible major"
220+ "version number, you need to recompile your module for this version"
221+ "of exim (The module was compiled for version %d.%d and this exim provides"
222+ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
223+ LOCAL_SCAN_ABI_VERSION_MINOR);
224+ return FALSE;
225+ }
226+else if (vers_min > LOCAL_SCAN_ABI_VERSION_MINOR)
227+ {
228+ dlclose(local_scan_lib);
229+ local_scan_lib = NULL;
230+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible minor"
231+ "version number, you need to recompile your module for this version"
232+ "of exim (The module was compiled for version %d.%d and this exim provides"
233+ "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
234+ LOCAL_SCAN_ABI_VERSION_MINOR);
235+ return FALSE;
236+ }
237+
238+local_scan_fn = dlsym(local_scan_lib, "local_scan");
239+if (!local_scan_fn)
240+ {
241+ dlclose(local_scan_lib);
242+ log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
243+ "local_scan() function - message temporarily rejected");
244+ return FALSE;
245+ }
246+
247+return TRUE;
248 }
249
250+#endif /* DLOPEN_LOCAL_SCAN */
251+
252 /* End of local_scan.c */
253--- a/src/local_scan.h
254+++ b/src/local_scan.h
255@@ -17,6 +17,7 @@ settings, and the store functions. */
256
257 #include <stdarg.h>
258 #include <sys/types.h>
259+#pragma GCC visibility push(default)
260 #include "config.h"
261 #include "mytypes.h"
262 #include "store.h"
0baa7b9d
SB
263@@ -192,4 +193,6 @@ extern uschar *string_copy(const uschar
264 extern uschar *string_copyn(const uschar *, int);
de45f55a
AM
265 extern uschar *string_sprintf(const char *, ...) ALMOST_PRINTF(1,2);
266
267+#pragma GCC visibility pop
268+
269 /* End of local_scan.h */
270--- a/src/readconf.c
271+++ b/src/readconf.c
01e60269 272@@ -199,6 +199,9 @@ static optionlist optionlist_config[] =
de45f55a
AM
273 { "local_from_prefix", opt_stringptr, &local_from_prefix },
274 { "local_from_suffix", opt_stringptr, &local_from_suffix },
275 { "local_interfaces", opt_stringptr, &local_interfaces },
276+#ifdef DLOPEN_LOCAL_SCAN
277+ { "local_scan_path", opt_stringptr, &local_scan_path },
278+#endif
01e60269 279 #ifdef HAVE_LOCAL_SCAN
de45f55a 280 { "local_scan_timeout", opt_time, &local_scan_timeout },
01e60269 281 #endif