View | Details | Raw Unified
Collapse All | Expand All

(-) src/EDITME (+15 lines)
 Lines 505-510    Link Here 
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
# 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.
LFLAGS=-rdynamic -ldl
#------------------------------------------------------------------------------
# The default distribution of Exim contains only the plain text form of the
# The default distribution of Exim contains only the plain text form of the
# documentation. Other forms are available separately. If you want to install
# documentation. Other forms are available separately. If you want to install
# the documentation in "info" format, first fetch the Texinfo documentation
# the documentation in "info" format, first fetch the Texinfo documentation
(-) src/config.h.defaults (+2 lines)
 Lines 20-25    Link Here 
#define AUTH_PLAINTEXT
#define AUTH_PLAINTEXT
#define AUTH_SPA
#define AUTH_SPA
#define DLOPEN_LOCAL_SCAN
#define BIN_DIRECTORY
#define BIN_DIRECTORY
#define CONFIGURE_FILE
#define CONFIGURE_FILE
(-) src/globals.c (+4 lines)
 Lines 109-114    Link Here 
uschar *tls_verify_hosts       = NULL;
uschar *tls_verify_hosts       = NULL;
#endif
#endif
#ifdef DLOPEN_LOCAL_SCAN
uschar *local_scan_path        = NULL;
#endif
/* Input-reading functions for messages, so we can use special ones for
/* Input-reading functions for messages, so we can use special ones for
incoming TCP/IP. The defaults use stdin. We never need these for any
incoming TCP/IP. The defaults use stdin. We never need these for any
(-) src/globals.h (+3 lines)
 Lines 73-78    Link Here 
extern uschar *tls_verify_hosts;       /* Mandatory client verification */
extern uschar *tls_verify_hosts;       /* Mandatory client verification */
#endif
#endif
#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
/* Input-reading functions for messages, so we can use special ones for
incoming TCP/IP. */
incoming TCP/IP. */
(-) src/local_scan.c (-47 / +118 lines)
 Lines 5-64    Link Here 
/* Copyright (c) University of Cambridge 1995 - 2004 */
/* Copyright (c) University of Cambridge 1995 - 2004 */
/* See the file NOTICE for conditions of use and distribution. */
/* See the file NOTICE for conditions of use and distribution. */
#include "exim.h"
/******************************************************************************
#ifdef DLOPEN_LOCAL_SCAN
This file contains a template local_scan() function that just returns ACCEPT.
#include <dlfcn.h>
If you want to implement your own version, you should copy this file to, say
static int (*local_scan_fn)(int fd, uschar **return_text) = NULL;
Local/local_scan.c, and edit the copy. To use your version instead of the
static int load_local_scan_library(void);
default, you must set
#endif
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.
*/
int
int
local_scan(int fd, uschar **return_text)
local_scan(int fd, uschar **return_text)
{
{
fd = fd;                      /* Keep picky compilers happy */
fd = fd;                      /* Keep picky compilers happy */
return_text = return_text;
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 */
/* End of local_scan.c */
(-) src/readconf.c (+3 lines)
 Lines 223-228    Link Here 
  { "local_from_prefix",        opt_stringptr,   &local_from_prefix },
  { "local_from_prefix",        opt_stringptr,   &local_from_prefix },
  { "local_from_suffix",        opt_stringptr,   &local_from_suffix },
  { "local_from_suffix",        opt_stringptr,   &local_from_suffix },
  { "local_interfaces",         opt_stringptr,   &local_interfaces },
  { "local_interfaces",         opt_stringptr,   &local_interfaces },
#ifdef DLOPEN_LOCAL_SCAN
  { "local_scan_path",          opt_stringptr,   &local_scan_path },
#endif
  { "local_scan_timeout",       opt_time,        &local_scan_timeout },
  { "local_scan_timeout",       opt_time,        &local_scan_timeout },
  { "local_sender_retain",      opt_bool,        &local_sender_retain },
  { "local_sender_retain",      opt_bool,        &local_sender_retain },
  { "localhost_number",         opt_stringptr,   &host_number_string },
  { "localhost_number",         opt_stringptr,   &host_number_string },