You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
8.4 KiB

  1. --- a/src/config.h.defaults
  2. +++ b/src/config.h.defaults
  3. @@ -33,6 +33,8 @@ Do not put spaces between # and the 'def
  4. #define AUTH_VARS 3
  5. +#define DLOPEN_LOCAL_SCAN
  6. +
  7. #define BIN_DIRECTORY
  8. #define CONFIGURE_FILE
  9. --- a/src/EDITME
  10. +++ b/src/EDITME
  11. @@ -877,6 +877,24 @@ HEADERS_CHARSET="ISO-8859-1"
  12. #------------------------------------------------------------------------------
  13. +# On systems which support dynamic loading of shared libraries, Exim can
  14. +# load a local_scan function specified in its config file instead of having
  15. +# to be recompiled with the desired local_scan function. For a full
  16. +# description of the API to this function, see the Exim specification.
  17. +
  18. +#DLOPEN_LOCAL_SCAN=yes
  19. +
  20. +# If you set DLOPEN_LOCAL_SCAN, then you need to include -rdynamic in the
  21. +# linker flags. Without it, the loaded .so won't be able to access any
  22. +# functions from exim.
  23. +
  24. +LFLAGS = -rdynamic
  25. +ifeq ($(OSTYPE),Linux)
  26. +LFLAGS += -ldl
  27. +endif
  28. +
  29. +
  30. +#------------------------------------------------------------------------------
  31. # The default distribution of Exim contains only the plain text form of the
  32. # documentation. Other forms are available separately. If you want to install
  33. # the documentation in "info" format, first fetch the Texinfo documentation
  34. --- a/src/globals.c
  35. +++ b/src/globals.c
  36. @@ -42,6 +42,10 @@ int optionlist_auths_size = nelem(op
  37. uschar *no_aliases = NULL;
  38. +#ifdef DLOPEN_LOCAL_SCAN
  39. +uschar *local_scan_path = NULL;
  40. +#endif
  41. +
  42. /* For comments on these variables, see globals.h. I'm too idle to
  43. duplicate them here... */
  44. --- a/src/globals.h
  45. +++ b/src/globals.h
  46. @@ -162,6 +162,9 @@ extern int (*receive_feof)(void);
  47. extern int (*receive_ferror)(void);
  48. extern BOOL (*receive_smtp_buffered)(void);
  49. +#ifdef DLOPEN_LOCAL_SCAN
  50. +extern uschar *local_scan_path; /* Path to local_scan() library */
  51. +#endif
  52. /* For clearing, saving, restoring address expansion variables. We have to have
  53. the size of this vector set explicitly, because it is referenced from more than
  54. --- a/src/local_scan.c
  55. +++ b/src/local_scan.c
  56. @@ -5,61 +5,133 @@
  57. /* Copyright (c) University of Cambridge 1995 - 2009 */
  58. /* See the file NOTICE for conditions of use and distribution. */
  59. -
  60. -/******************************************************************************
  61. -This file contains a template local_scan() function that just returns ACCEPT.
  62. -If you want to implement your own version, you should copy this file to, say
  63. -Local/local_scan.c, and edit the copy. To use your version instead of the
  64. -default, you must set
  65. -
  66. -HAVE_LOCAL_SCAN=yes
  67. -LOCAL_SCAN_SOURCE=Local/local_scan.c
  68. -
  69. -in your Local/Makefile. This makes it easy to copy your version for use with
  70. -subsequent Exim releases.
  71. -
  72. -For a full description of the API to this function, see the Exim specification.
  73. -******************************************************************************/
  74. -
  75. -
  76. -/* This is the only Exim header that you should include. The effect of
  77. -including any other Exim header is not defined, and may change from release to
  78. -release. Use only the documented interface! */
  79. -
  80. #include "local_scan.h"
  81. -
  82. -/* This is a "do-nothing" version of a local_scan() function. The arguments
  83. -are:
  84. -
  85. - fd The file descriptor of the open -D file, which contains the
  86. - body of the message. The file is open for reading and
  87. - writing, but modifying it is dangerous and not recommended.
  88. -
  89. - return_text A pointer to an unsigned char* variable which you can set in
  90. - order to return a text string. It is initialized to NULL.
  91. -
  92. -The return values of this function are:
  93. -
  94. - LOCAL_SCAN_ACCEPT
  95. - The message is to be accepted. The return_text argument is
  96. - saved in $local_scan_data.
  97. -
  98. - LOCAL_SCAN_REJECT
  99. - The message is to be rejected. The returned text is used
  100. - in the rejection message.
  101. -
  102. - LOCAL_SCAN_TEMPREJECT
  103. - This specifies a temporary rejection. The returned text
  104. - is used in the rejection message.
  105. -*/
  106. +#ifdef DLOPEN_LOCAL_SCAN
  107. +#include <stdlib.h>
  108. +#include <dlfcn.h>
  109. +static int (*local_scan_fn)(int fd, uschar **return_text) = NULL;
  110. +static int load_local_scan_library(void);
  111. +extern uschar *local_scan_path; /* Path to local_scan() library */
  112. +#endif
  113. int
  114. local_scan(int fd, uschar **return_text)
  115. {
  116. fd = fd; /* Keep picky compilers happy */
  117. return_text = return_text;
  118. -return LOCAL_SCAN_ACCEPT;
  119. +#ifdef DLOPEN_LOCAL_SCAN
  120. +/* local_scan_path is defined AND not the empty string */
  121. +if (local_scan_path && *local_scan_path)
  122. + {
  123. + if (!local_scan_fn)
  124. + {
  125. + if (!load_local_scan_library())
  126. + {
  127. + char *base_msg , *error_msg , *final_msg ;
  128. + int final_length = -1 ;
  129. +
  130. + base_msg=US"Local configuration error - local_scan() library failure\n";
  131. + error_msg = dlerror() ;
  132. +
  133. + final_length = strlen(base_msg) + strlen(error_msg) + 1 ;
  134. + final_msg = (char*)malloc( final_length*sizeof(char) ) ;
  135. + *final_msg = '\0' ;
  136. +
  137. + strcat( final_msg , base_msg ) ;
  138. + strcat( final_msg , error_msg ) ;
  139. +
  140. + *return_text = final_msg ;
  141. + return LOCAL_SCAN_TEMPREJECT;
  142. + }
  143. + }
  144. + return local_scan_fn(fd, return_text);
  145. + }
  146. +else
  147. +#endif
  148. + return LOCAL_SCAN_ACCEPT;
  149. }
  150. +#ifdef DLOPEN_LOCAL_SCAN
  151. +
  152. +static int load_local_scan_library(void)
  153. +{
  154. +/* No point in keeping local_scan_lib since we'll never dlclose() anyway */
  155. +void *local_scan_lib = NULL;
  156. +int (*local_scan_version_fn)(void);
  157. +int vers_maj;
  158. +int vers_min;
  159. +
  160. +local_scan_lib = dlopen(local_scan_path, RTLD_NOW);
  161. +if (!local_scan_lib)
  162. + {
  163. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library open failed - "
  164. + "message temporarily rejected");
  165. + return FALSE;
  166. + }
  167. +
  168. +local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_major");
  169. +if (!local_scan_version_fn)
  170. + {
  171. + dlclose(local_scan_lib);
  172. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
  173. + "local_scan_version_major() function - message temporarily rejected");
  174. + return FALSE;
  175. + }
  176. +
  177. +/* The major number is increased when the ABI is changed in a non
  178. + backward compatible way. */
  179. +vers_maj = local_scan_version_fn();
  180. +
  181. +local_scan_version_fn = dlsym(local_scan_lib, "local_scan_version_minor");
  182. +if (!local_scan_version_fn)
  183. + {
  184. + dlclose(local_scan_lib);
  185. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
  186. + "local_scan_version_minor() function - message temporarily rejected");
  187. + return FALSE;
  188. + }
  189. +
  190. +/* The minor number is increased each time a new feature is added (in a
  191. + way that doesn't break backward compatibility) -- Marc */
  192. +vers_min = local_scan_version_fn();
  193. +
  194. +
  195. +if (vers_maj != LOCAL_SCAN_ABI_VERSION_MAJOR)
  196. + {
  197. + dlclose(local_scan_lib);
  198. + local_scan_lib = NULL;
  199. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible major"
  200. + "version number, you need to recompile your module for this version"
  201. + "of exim (The module was compiled for version %d.%d and this exim provides"
  202. + "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
  203. + LOCAL_SCAN_ABI_VERSION_MINOR);
  204. + return FALSE;
  205. + }
  206. +else if (vers_min > LOCAL_SCAN_ABI_VERSION_MINOR)
  207. + {
  208. + dlclose(local_scan_lib);
  209. + local_scan_lib = NULL;
  210. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() has an incompatible minor"
  211. + "version number, you need to recompile your module for this version"
  212. + "of exim (The module was compiled for version %d.%d and this exim provides"
  213. + "ABI version %d.%d)", vers_maj, vers_min, LOCAL_SCAN_ABI_VERSION_MAJOR,
  214. + LOCAL_SCAN_ABI_VERSION_MINOR);
  215. + return FALSE;
  216. + }
  217. +
  218. +local_scan_fn = dlsym(local_scan_lib, "local_scan");
  219. +if (!local_scan_fn)
  220. + {
  221. + dlclose(local_scan_lib);
  222. + log_write(0, LOG_MAIN|LOG_REJECT, "local_scan() library doesn't contain "
  223. + "local_scan() function - message temporarily rejected");
  224. + return FALSE;
  225. + }
  226. +
  227. +return TRUE;
  228. +}
  229. +
  230. +#endif /* DLOPEN_LOCAL_SCAN */
  231. +
  232. /* End of local_scan.c */
  233. --- a/src/readconf.c
  234. +++ b/src/readconf.c
  235. @@ -205,6 +205,9 @@ static optionlist optionlist_config[] =
  236. { "local_from_prefix", opt_stringptr, {&local_from_prefix} },
  237. { "local_from_suffix", opt_stringptr, {&local_from_suffix} },
  238. { "local_interfaces", opt_stringptr, {&local_interfaces} },
  239. +#ifdef DLOPEN_LOCAL_SCAN
  240. + { "local_scan_path", opt_stringptr, {&local_scan_path} },
  241. +#endif
  242. #ifdef HAVE_LOCAL_SCAN
  243. { "local_scan_timeout", opt_time, {&local_scan_timeout} },
  244. #endif