651 changes: 651 additions & 0 deletions src/src/dnsbl.c

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions src/src/drtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ extern lookup_module_info pgsql_lookup_module_info;
#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
extern lookup_module_info redis_lookup_module_info;
#endif
#if defined(EXPERIMENTAL_LMDB)
#if defined(LOOKUP_LMDB)
extern lookup_module_info lmdb_lookup_module_info;
#endif
#if defined(SUPPORT_SPF)
Expand Down Expand Up @@ -698,7 +698,7 @@ addlookupmodule(NULL, &pgsql_lookup_module_info);
addlookupmodule(NULL, &redis_lookup_module_info);
#endif

#ifdef EXPERIMENTAL_LMDB
#ifdef LOOKUP_LMDB
addlookupmodule(NULL, &lmdb_lookup_module_info);
#endif

Expand Down Expand Up @@ -764,10 +764,10 @@ else
}

/* FreeBSD nsdispatch() can trigger dlerror() errors about
* _nss_cache_cycle_prevention_function; we need to clear the dlerror()
* state before calling dlsym(), so that any error afterwards only
* comes from dlsym().
*/
_nss_cache_cycle_prevention_function; we need to clear the dlerror()
state before calling dlsym(), so that any error afterwards only comes
from dlsym(). */

errormsg = dlerror();

info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
Expand Down
14 changes: 0 additions & 14 deletions src/src/dummies.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
selector = selector; /* Keep picky compilers happy */
flags = flags;
}


Expand Down Expand Up @@ -103,7 +101,6 @@ extern int sigalrm_seen;
void
sigalrm_handler(int sig)
{
sig = sig; /* Keep picky compilers happy */
sigalrm_seen = TRUE;
}

Expand All @@ -116,19 +113,12 @@ sigalrm_seen = TRUE;
int
header_checkname(void *h, char *name, int len)
{
h = h; /* Keep picky compilers happy */
name = name;
len = len;
return 0;
}

void
directory_make(char *parent, char *name, int mode, int panic)
{
parent = parent; /* Keep picky compilers happy */
name = name;
mode = mode;
panic = panic;
}

void
Expand All @@ -140,10 +130,6 @@ host_build_sender_fullhost(void) { }
char *
host_ntoa(int type, const void *arg, char *buffer, int *portptr)
{
type = type; /* Keep picky compilers happy */
arg = arg;
buffer = buffer;
portptr = portptr;
return NULL;
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/src/enq.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ if (!(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
/* See if there is a record for this host or queue run; if there is, we cannot
proceed with the connection unless the record is very old. */

serial_record = dbfn_read(dbm_file, key);
serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize));
if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
{
if (serial_record->count >= lim)
Expand Down Expand Up @@ -102,7 +102,7 @@ dbdata_serialize *serial_record;
DEBUG(D_transport) debug_printf("end serialized: %s\n", key);

if ( !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
|| !(serial_record = dbfn_read(dbm_file, key))
|| !(serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize)))
)
return;
if (--serial_record->count > 0)
Expand Down
647 changes: 397 additions & 250 deletions src/src/exim.c

Large diffs are not rendered by default.

70 changes: 69 additions & 1 deletion src/src/exim.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ making unique names. */
# include <limits.h>
#endif

#ifdef EXIM_HAVE_INOTIFY
# include <sys/inotify.h>
#endif
#ifdef EXIM_HAVE_KEVENT
# include <sys/event.h>
#endif

/* C99 integer types, figure out how to undo this if needed for older systems */

#include <inttypes.h>
Expand Down Expand Up @@ -128,6 +135,51 @@ making unique names. */
# endif
#endif

/* RFC 5321 specifies that the maximum length of a local-part is 64 octets
and the maximum length of a domain is 255 octets, but then also defines
the maximum length of a forward/reverse path as 256 not 64+1+255.
For an IP address, the maximum is 45 without a scope and we don't work
with scoped addresses, so go with that. (IPv6 with mapped IPv4).
A hostname maximum length is in practice the same as the domainname, for
the same core reasons (maximum length of a DNS name), but the semantics
are different and seeing "DOMAIN" in source is confusing when talking about
hostnames; so we define a second macro. We'll use RFC 2181 as the reference
for this one.
There is no known (to me) specification on the maximum length of a human name
in email addresses and we should be careful about imposing such a limit on
received email, but in terms of limiting what untrusted callers specify, or
local generation, having a limit makes sense. Err on the side of generosity.
For a display mail address, we have a human name, an email in brackets,
possibly some (Comments), so it needs to be at least 512+3 and some more to
avoid extraneous errors.
Since the sane SMTP line length limit is 998, constraining such parameters to
be 1024 seems generous and unlikely to spuriously reject legitimate
invocations.
The driver name is a name of a router/transport/authenticator etc in the
configuration file. We also use this for some other short strings, such
as queue names.
Also TLS ciphersuite name (no real known limit since the protocols use
integers, but max seen in reality is 45 octets).
RFC 1413 gives us the 512 limit on IDENT protocol userids.
*/

#define EXIM_EMAILADDR_MAX 256
#define EXIM_LOCALPART_MAX 64
#define EXIM_DOMAINNAME_MAX 255
#define EXIM_IPADDR_MAX 45
#define EXIM_HOSTNAME_MAX 255
#define EXIM_HUMANNAME_MAX 256
#define EXIM_DISPLAYMAIL_MAX 1024
#define EXIM_DRIVERNAME_MAX 64
#define EXIM_CIPHERNAME_MAX 64
#define EXIM_IDENTUSER_MAX 512


#include <sys/types.h>
#include <sys/file.h>
#include <dirent.h>
Expand Down Expand Up @@ -493,7 +545,7 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
#ifdef SUPPORT_SPF
# include "spf.h"
#endif
#ifdef EXPERIMENTAL_SRS
#ifdef EXPERIMENTAL_SRS_ALT
# include "srs.h"
#endif
#ifndef DISABLE_DKIM
Expand Down Expand Up @@ -599,5 +651,21 @@ default to EDQUOT if it exists, otherwise ENOSPC. */
# define EXIM_GROUPLIST_SIZE NGROUPS_MAX
#endif

/* Linux has TCP_CORK, FreeBSD has TCP_NOPUSH; they do pretty much the same */

#ifdef TCP_CORK
# define EXIM_TCP_CORK TCP_CORK
#elif defined(TCP_NOPUSH)
# define EXIM_TCP_CORK TCP_NOPUSH
#endif

/* LibreSSL seems to not push out the SMTP response to QUIT with our usual
handling which is trying to get the client to FIN first so that the server does
not get the TIME_WAIT */

#if !defined(DISABLE_TLS) && defined(USE_OPENSSL) && defined(LIBRESSL_VERSION_NUMBER)
# define SERVERSIDE_CLOSE_NOWAIT
#endif

#endif
/* End of exim.h */
12 changes: 11 additions & 1 deletion src/src/exim_dbmbuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void *
store_get_3(int size, BOOL tainted, const char *filename, int linenumber)
{ return NULL; }
void **
store_reset_3(void **ptr, int pool, const char *filename, int linenumber)
store_reset_3(void **ptr, const char *filename, int linenumber)
{ return NULL; }
void
store_release_above_3(void *ptr, const char *func, int linenumber)
Expand All @@ -70,6 +70,16 @@ struct global_flags f;
unsigned int log_selector[1];
uschar * queue_name;
BOOL split_spool_directory;


/* These introduced by the taintwarn handling */
rmark
store_mark_3(const char *func, int linenumber)
{ return NULL; }
#ifdef ALLOW_INSECURE_TAINTED_DATA
BOOL allow_insecure_tainted_data;
#endif

/******************************************************************************/


Expand Down
46 changes: 38 additions & 8 deletions src/src/exim_dbutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ struct global_flags f;
unsigned int log_selector[1];
uschar * queue_name;
BOOL split_spool_directory;


/* These introduced by the taintwarn handling */
#ifdef ALLOW_INSECURE_TAINTED_DATA
BOOL allow_insecure_tainted_data;
#endif

/******************************************************************************/


Expand Down Expand Up @@ -106,7 +113,6 @@ SIGNAL_BOOL sigalrm_seen;
void
sigalrm_handler(int sig)
{
sig = sig; /* Keep picky compilers happy */
sigalrm_seen = 1;
}

Expand Down Expand Up @@ -177,8 +183,6 @@ va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
selector = selector; /* Keep picky compilers happy */
flags = flags;
}


Expand Down Expand Up @@ -391,7 +395,7 @@ pick out the timestamps, etc., do the copying centrally here.
Arguments:
dbblock a pointer to an open database block
key the key of the record to be read
length where to put the length (or NULL if length not wanted)
length where to put the length (or NULL if length not wanted). Includes overhead.
Returns: a pointer to the retrieved record, or
NULL if the record is not found
Expand Down Expand Up @@ -419,7 +423,7 @@ we should store the taint status along with the data. */

yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum);
if (length) *length = EXIM_DATUM_SIZE(result_datum);

EXIM_DATUM_FREE(result_datum); /* Some DBM libs require freeing */
return yield;
Expand Down Expand Up @@ -518,7 +522,6 @@ dbfn_scan(open_db *dbblock, BOOL start, EXIM_CURSOR **cursor)
{
EXIM_DATUM key_datum, value_datum;
uschar *yield;
value_datum = value_datum; /* dummy; not all db libraries use this */

/* Some dbm require an initialization */

Expand Down Expand Up @@ -555,6 +558,8 @@ EXIM_CURSOR *cursor;
uschar **argv = USS cargv;
uschar keybuffer[1024];

store_init();

/* Check the arguments, and open the database */

dbdata_type = check_args(argc, argv, US"dumpdb", US"");
Expand Down Expand Up @@ -620,6 +625,7 @@ for (uschar * key = dbfn_scan(dbm, TRUE, &cursor);
t = wait->text;
name[MESSAGE_ID_LENGTH] = 0;

/* Leave corrupt records alone */
if (wait->count > WAIT_NAME_MAX)
{
fprintf(stderr,
Expand Down Expand Up @@ -768,6 +774,7 @@ uschar buffer[256];
uschar name[256];
rmark reset_point;

store_init();
name[0] = 0; /* No name set */

/* Sort out the database type, verify what we are working on and then process
Expand Down Expand Up @@ -1137,6 +1144,8 @@ uschar **argv = USS cargv;
uschar buffer[256];
uschar *key;

store_init();

/* Scan the options */

for (i = 1; i < argc; i++)
Expand Down Expand Up @@ -1222,7 +1231,7 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point))
/* A continuation record may have been deleted or renamed already, so
non-existence is not serious. */

if (value == NULL) continue;
if (!value) continue;

/* Delete if too old */

Expand All @@ -1243,12 +1252,33 @@ for (; keychain && (reset_point = store_mark()); store_reset(reset_point))

/* Leave corrupt records alone */

if (wait->time_stamp > time(NULL))
{
printf("**** Data for '%s' corrupted\n time in future: %s\n",
key, print_time(((dbdata_generic *)value)->time_stamp));
continue;
}
if (wait->count > WAIT_NAME_MAX)
{
printf("**** Data for %s corrupted\n count=%d=0x%x max=%d\n",
printf("**** Data for '%s' corrupted\n count=%d=0x%x max=%d\n",
key, wait->count, wait->count, WAIT_NAME_MAX);
continue;
}
if (wait->sequence > WAIT_CONT_MAX)
{
printf("**** Data for '%s' corrupted\n sequence=%d=0x%x max=%d\n",
key, wait->sequence, wait->sequence, WAIT_CONT_MAX);
continue;
}

/* Record over 1 year old; just remove it */

if (wait->time_stamp < time(NULL) - 365*24*60*60)
{
dbfn_delete(dbm, key);
printf("deleted %s (too old)\n", key);
continue;
}

/* Loop for renamed continuation records. For each message id,
check to see if the message exists, and if not, remove its entry
Expand Down
3 changes: 1 addition & 2 deletions src/src/exim_lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ the other stuff in os.c, so force the other macros to omit it. */
static void
sigalrm_handler(int sig)
{
sig = sig; /* Keep picky compilers happy */
sigalrm_seen = TRUE;
}

Expand Down Expand Up @@ -584,7 +583,7 @@ else
if (restore_times)
{
struct stat strestore;
#ifdef EXIM_HAVE_OPENAT
#ifdef EXIM_HAVE_FUTIMENS
int fd = open(filename, O_RDWR); /* use fd for both get & restore */
struct timespec tt[2];

Expand Down
395 changes: 208 additions & 187 deletions src/src/expand.c

Large diffs are not rendered by default.

47 changes: 22 additions & 25 deletions src/src/filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ typedef struct condition_block {
/* Miscellaneous other declarations */

static uschar **error_pointer;
static uschar *log_filename;
static const uschar *log_filename;
static int filter_options;
static int line_number;
static int expect_endif;
Expand Down Expand Up @@ -1668,7 +1668,7 @@ Returns: FF_DELIVERED success, a significant action was taken
static int
interpret_commands(filter_cmd *commands, address_item **generated)
{
uschar *s;
const uschar *s;
int mode;
address_item *addr;
BOOL condition_value;
Expand All @@ -1677,7 +1677,7 @@ while (commands)
{
int ff_ret;
uschar *fmsg, *ff_name;
uschar *expargs[MAILARGS_STRING_COUNT];
const uschar *expargs[MAILARGS_STRING_COUNT];

int i, n[2];

Expand Down Expand Up @@ -1709,7 +1709,7 @@ while (commands)
case add_command:
for (i = 0; i < 2; i++)
{
uschar *ss = expargs[i];
const uschar *ss = expargs[i];
uschar *end;

if (i == 1 && (*ss++ != 'n' || ss[1] != 0))
Expand Down Expand Up @@ -1806,9 +1806,8 @@ while (commands)
af_ignore_error flag if necessary, and the errors address, which can be
set in a system filter and to the local address in user filters. */

addr = deliver_make_addr(expargs[0], TRUE); /* TRUE => copy s */
addr->prop.errors_address = (s == NULL)?
s : string_copy(s); /* Default is NULL */
addr = deliver_make_addr(US expargs[0], TRUE); /* TRUE => copy s, so deconst ok */
addr->prop.errors_address = !s ? NULL : string_copy(s); /* Default is NULL */
if (commands->noerror) addr->prop.ignore_error = TRUE;
addr->next = *generated;
*generated = addr;
Expand Down Expand Up @@ -1848,7 +1847,7 @@ while (commands)
af_pfr and af_file flags, the af_ignore_error flag if necessary, and the
mode value. */

addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
setflag(addr, af_pfr);
setflag(addr, af_file);
if (commands->noerror) addr->prop.ignore_error = TRUE;
Expand Down Expand Up @@ -1878,7 +1877,7 @@ while (commands)
each command argument is expanded in the transport after the command
has been split up into separate arguments. */

addr = deliver_make_addr(s, TRUE); /* TRUE => copy s */
addr = deliver_make_addr(US s, TRUE); /* TRUE => copy s, so deconst ok */
setflag(addr, af_pfr);
setflag(addr, af_expand_pipe);
if (commands->noerror) addr->prop.ignore_error = TRUE;
Expand Down Expand Up @@ -1952,7 +1951,7 @@ while (commands)
(long int)geteuid());
if (log_fd < 0)
{
if (log_filename == NULL)
if (!log_filename)
{
*error_pointer = US"attempt to obey \"logwrite\" command "
"without a previous \"logfile\"";
Expand All @@ -1961,7 +1960,7 @@ while (commands)
log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
if (log_fd < 0)
{
*error_pointer = string_open_failed(errno, "filter log file \"%s\"",
*error_pointer = string_open_failed("filter log file \"%s\"",
log_filename);
return FF_ERROR;
}
Expand All @@ -1975,9 +1974,8 @@ while (commands)
}
}
else
{
DEBUG(D_filter) debug_printf_indent("skipping logwrite (verifying or testing)\n");
}
DEBUG(D_filter)
debug_printf_indent("skipping logwrite (verifying or testing)\n");
break;

/* Header addition and removal is available only in the system filter. The
Expand Down Expand Up @@ -2008,18 +2006,16 @@ while (commands)
else if (subtype == FALSE)
{
int sep = 0;
uschar *ss;
const uschar *list = s;
uschar buffer[128];
while ((ss = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
!= NULL)
const uschar * list = s;

for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
header_remove(0, ss);
}

/* This setting lasts only while the filter is running; on exit, the
variable is reset to the previous value. */

else headers_charset = s;
else headers_charset = s; /*XXX loses track of const */
}
break;

Expand All @@ -2043,7 +2039,7 @@ while (commands)
ff_ret = FF_FREEZE;

DEFERFREEZEFAIL:
fmsg = expargs[0];
fmsg = expargs[0]; /*XXX loses track of const */
if (Ustrlen(fmsg) > 1024) Ustrcpy(fmsg + 1000, US" ... (truncated)");
fmsg = US string_printing(fmsg);
*error_pointer = fmsg;
Expand Down Expand Up @@ -2126,7 +2122,7 @@ while (commands)
for (i = 0; i < MAILARGS_STRING_COUNT; i++)
{
uschar *p;
uschar *s = expargs[i];
const uschar *s = expargs[i];

if (s == NULL) continue;

Expand Down Expand Up @@ -2180,7 +2176,7 @@ while (commands)

/* The string is OK */

commands->args[i].u = s;
commands->args[i].u = s; /*XXX loses track of const */
}

/* Proceed with mail or vacation command */
Expand Down Expand Up @@ -2368,8 +2364,9 @@ Returns: TRUE if the message is deemed to be personal
BOOL
filter_personal(string_item *aliases, BOOL scan_cc)
{
uschar *self, *self_from, *self_to;
uschar *psself = NULL, *psself_from = NULL, *psself_to = NULL;
const uschar *self, *self_from, *self_to;
uschar *psself = NULL;
const uschar *psself_from = NULL, *psself_to = NULL;
rmark reset_point = store_mark();
BOOL yield;
header_line *h;
Expand Down
2 changes: 1 addition & 1 deletion src/src/filtertest.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ if (!dot_ended && !feof(stdin))
if (s > message_body_end + message_body_visible) s = message_body_end;
message_size++;
}
READ_END: ch = ch; /* Some compilers don't like null statements */
READ_END: ;
}
if (s == message_body_end || s[-1] != '\n') body_linecount++;
}
Expand Down
194 changes: 135 additions & 59 deletions src/src/functions.h

Large diffs are not rendered by default.

114 changes: 54 additions & 60 deletions src/src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ int sqlite_lock_timeout = 5;
BOOL move_frozen_messages = FALSE;
#endif

#ifdef ALLOW_INSECURE_TAINTED_DATA
BOOL allow_insecure_tainted_data = FALSE;
#endif

/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. Note that these are
Expand All @@ -120,9 +124,11 @@ uschar *dsn_advertise_hosts = NULL;
#ifndef DISABLE_TLS
BOOL gnutls_compat_mode = FALSE;
BOOL gnutls_allow_auto_pkcs11 = FALSE;
uschar *hosts_require_alpn = NULL;
uschar *openssl_options = NULL;
const pcre *regex_STARTTLS = NULL;
uschar *tls_advertise_hosts = US"*";
uschar *tls_alpn = US"smtp:esmtp";
uschar *tls_certificate = NULL;
uschar *tls_crl = NULL;
/* This default matches NSS DH_MAX_P_BITS value at current time (2012), because
Expand All @@ -137,12 +143,14 @@ uschar *tls_ocsp_file = NULL;
uschar *tls_privatekey = NULL;
BOOL tls_remember_esmtp = FALSE;
uschar *tls_require_ciphers = NULL;
# ifdef EXPERIMENTAL_TLS_RESUME
# ifndef DISABLE_TLS_RESUME
uschar *tls_resumption_hosts = NULL;
# endif
uschar *tls_try_verify_hosts = NULL;
uschar *tls_verify_certificates= US"system";
uschar *tls_verify_hosts = NULL;
int tls_watch_fd = -1;
time_t tls_watch_trigger_time = (time_t)0;
#else /*DISABLE_TLS*/
uschar *tls_advertise_hosts = NULL;
#endif
Expand All @@ -168,7 +176,7 @@ uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
int (*lwr_receive_ungetc)(int) = stdin_ungetc;
int (*receive_getc)(unsigned) = stdin_getc;
uschar * (*receive_getbuf)(unsigned *) = NULL;
void (*receive_get_cache)(void)= NULL;
void (*receive_get_cache)(unsigned) = NULL;
int (*receive_ungetc)(int) = stdin_ungetc;
int (*receive_feof)(void) = stdin_feof;
int (*receive_ferror)(void) = stdin_ferror;
Expand Down Expand Up @@ -221,6 +229,7 @@ struct global_flags f =
.authentication_local = FALSE,

.background_daemon = TRUE,
.bdat_readers_wanted = FALSE,

.chunking_offered = FALSE,
.config_changed = FALSE,
Expand Down Expand Up @@ -307,6 +316,7 @@ struct global_flags f =
#endif
.smtp_in_pipelining_advertised = FALSE,
.smtp_in_pipelining_used = FALSE,
.smtp_in_quit = FALSE,
.spool_file_wireformat = FALSE,
.submission_mode = FALSE,
.suppress_local_fixups = FALSE,
Expand Down Expand Up @@ -382,7 +392,7 @@ BOOL prod_requires_admin = TRUE;
BOOL proxy_session = FALSE;
#endif

#ifdef EXPERIMENTAL_QUEUE_RAMP
#ifndef DISABLE_QUEUE_RAMP
BOOL queue_fast_ramp = FALSE;
#endif
BOOL queue_list_requires_admin = TRUE;
Expand All @@ -407,7 +417,7 @@ BOOL spf_result_guessed = FALSE;
#endif
BOOL split_spool_directory = FALSE;
BOOL spool_wireformat = FALSE;
#ifdef EXPERIMENTAL_SRS
#ifdef EXPERIMENTAL_SRS_ALT
BOOL srs_usehash = TRUE;
BOOL srs_usetimestamp = TRUE;
#endif
Expand Down Expand Up @@ -596,7 +606,7 @@ address_item address_defaults = {
.extra_headers = NULL,
.remove_headers = NULL,
.variables = NULL,
#ifdef EXPERIMENTAL_SRS
#ifdef EXPERIMENTAL_SRS_ALT
.srs_sender = NULL,
#endif
.ignore_error = FALSE,
Expand Down Expand Up @@ -703,6 +713,10 @@ unsigned chunking_data_left = 0;
chunking_state_t chunking_state= CHUNKING_NOT_OFFERED;
const pcre *regex_CHUNKING = NULL;

#ifdef EXPERIMENTAL_ESMTP_LIMITS
const pcre *regex_LIMITS = NULL;
#endif

uschar *client_authenticator = NULL;
uschar *client_authenticated_id = NULL;
uschar *client_authenticated_sender = NULL;
Expand All @@ -729,10 +743,17 @@ uid_t config_uid = 0;

int connection_max_messages= -1;
uschar *continue_proxy_cipher = NULL;
BOOL continue_proxy_dane = FALSE;
uschar *continue_proxy_sni = NULL;
uschar *continue_hostname = NULL;
uschar *continue_host_address = NULL;
int continue_sequence = 1;
uschar *continue_transport = NULL;
#ifdef EXPERIMENTAL_ESMTP_LIMITS
unsigned continue_limit_mail = 0;
unsigned continue_limit_rcpt = 0;
unsigned continue_limit_rcptdom= 0;
#endif

uschar *csa_status = NULL;
cut_t cutthrough = {
Expand Down Expand Up @@ -975,6 +996,7 @@ uschar *host_reject_connection = NULL;
tree_node *hostlist_anchor = NULL;
int hostlist_count = 0;
uschar *hosts_treat_as_local = NULL;
uschar *hosts_require_helo = US"*";
uschar *hosts_connection_nolog = NULL;

int ignore_bounce_errors_after = 10*7*24*60*60; /* 10 weeks */
Expand All @@ -992,6 +1014,9 @@ uschar *keep_environment = NULL;
int keep_malformed = 4*24*60*60; /* 4 days */

uschar *eldap_dn = NULL;
#ifdef EXPERIMENTAL_ESMTP_LIMITS
uschar *limits_advertise_hosts = US"*";
#endif
int load_average = -2;
uschar *local_from_prefix = NULL;
uschar *local_from_suffix = NULL;
Expand Down Expand Up @@ -1025,12 +1050,16 @@ int log_default[] = { /* for initializing log_selector */
Li_outgoing_interface, /* see d_log_interface in deliver.c */
Li_msg_id,
Li_queue_run,
Li_queue_time_exclusive,
Li_rejected_header,
Li_retry_defer,
Li_sender_verify_fail,
Li_size_reject,
Li_skip_delivery,
Li_smtp_confirmation,
#ifdef ALLOW_INSECURE_TAINTED_DATA
Li_tainted,
#endif
Li_tls_certificate_verified,
Li_tls_cipher,
-1
Expand Down Expand Up @@ -1073,11 +1102,13 @@ bit_table log_options[] = { /* must be in alphabetical order,
BIT_TABLE(L, outgoing_port),
BIT_TABLE(L, pid),
BIT_TABLE(L, pipelining),
BIT_TABLE(L, protocol_detail),
#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
BIT_TABLE(L, proxy),
#endif
BIT_TABLE(L, queue_run),
BIT_TABLE(L, queue_time),
BIT_TABLE(L, queue_time_exclusive),
BIT_TABLE(L, queue_time_overall),
BIT_TABLE(L, receive_time),
BIT_TABLE(L, received_recipients),
Expand All @@ -1098,6 +1129,9 @@ bit_table log_options[] = { /* must be in alphabetical order,
BIT_TABLE(L, smtp_protocol_error),
BIT_TABLE(L, smtp_syntax_error),
BIT_TABLE(L, subject),
#ifdef ALLOW_INSECURE_TAINTED_DATA
BIT_TABLE(L, tainted),
#endif
BIT_TABLE(L, tls_certificate_verified),
BIT_TABLE(L, tls_cipher),
BIT_TABLE(L, tls_peerdn),
Expand Down Expand Up @@ -1198,6 +1232,7 @@ uschar *proxy_external_address = NULL;
int proxy_external_port = 0;
uschar *proxy_local_address = NULL;
int proxy_local_port = 0;
int proxy_protocol_timeout = 3;
#endif

uschar *prvscheck_address = NULL;
Expand Down Expand Up @@ -1263,14 +1298,14 @@ uschar *received_header_text = US
int received_headers_max = 30;
uschar *received_protocol = NULL;
struct timeval received_time = { 0, 0 };
struct timeval received_time_taken = { 0, 0 };
struct timeval received_time_complete = { 0, 0 };
uschar *recipient_data = NULL;
uschar *recipient_unqualified_hosts = NULL;
uschar *recipient_verify_failure = NULL;
int recipients_count = 0;
recipient_item *recipients_list = NULL;
int recipients_list_max = 0;
int recipients_max = 0;
int recipients_max = 50000;
const pcre *regex_AUTH = NULL;
const pcre *regex_check_dns_names = NULL;
const pcre *regex_From = NULL;
Expand Down Expand Up @@ -1439,12 +1474,13 @@ int smtp_accept_count = 0;
int smtp_accept_max = 20;
int smtp_accept_max_nonmail= 10;
uschar *smtp_accept_max_nonmail_hosts = US"*";
int smtp_accept_max_per_connection = 1000;
uschar *smtp_accept_max_per_connection = US"1000";
uschar *smtp_accept_max_per_host = NULL;
int smtp_accept_queue = 0;
int smtp_accept_queue_per_connection = 10;
int smtp_accept_reserve = 0;
uschar *smtp_active_hostname = NULL;
int smtp_backlog_monitor = 0;
uschar *smtp_banner = US"$smtp_active_hostname ESMTP "
"Exim $version_number $tod_full"
"\0<---------------Space to patch smtp_banner->";
Expand All @@ -1457,13 +1493,17 @@ int smtp_connect_backlog = 20;
double smtp_delay_mail = 0.0;
double smtp_delay_rcpt = 0.0;
FILE *smtp_in = NULL;
int smtp_listen_backlog = 0;
int smtp_load_reserve = -1;
int smtp_mailcmd_count = 0;
int smtp_mailcmd_max = -1;
FILE *smtp_out = NULL;
uschar *smtp_etrn_command = NULL;
int smtp_max_synprot_errors= 3;
int smtp_max_unknown_commands = 3;
uschar *smtp_notquit_reason = NULL;
unsigned smtp_peer_options = 0;
unsigned smtp_peer_options_wrap= 0;
uschar *smtp_ratelimit_hosts = NULL;
uschar *smtp_ratelimit_mail = NULL;
uschar *smtp_ratelimit_rcpt = NULL;
Expand All @@ -1479,8 +1519,6 @@ int smtp_rlr_base = 0;
double smtp_rlr_factor = 0.0;
int smtp_rlr_limit = 0;
int smtp_rlr_threshold = INT_MAX;
unsigned smtp_peer_options = 0;
unsigned smtp_peer_options_wrap= 0;
#ifdef SUPPORT_I18N
uschar *smtputf8_advertise_hosts = US"*"; /* overridden under test-harness */
#endif
Expand Down Expand Up @@ -1508,7 +1546,7 @@ uschar *spf_smtp_comment_template
FILE *spool_data_file = NULL;
uschar *spool_directory = US SPOOL_DIRECTORY
"\0<--------------Space to patch spool_directory->";
#ifdef EXPERIMENTAL_SRS
#ifdef EXPERIMENTAL_SRS_ALT
uschar *srs_config = NULL;
uschar *srs_db_address = NULL;
uschar *srs_db_key = NULL;
Expand All @@ -1521,14 +1559,14 @@ uschar *srs_recipient = NULL;
uschar *srs_secrets = NULL;
uschar *srs_status = NULL;
#endif
#ifdef EXPERIMENTAL_SRS_NATIVE
#ifdef SUPPORT_SRS
uschar *srs_recipient = NULL;
#endif
int string_datestamp_offset= -1;
int string_datestamp_length= 0;
int string_datestamp_type = -1;
uschar *submission_domain = NULL;
uschar *submission_name = NULL;
const uschar *submission_domain = NULL;
const uschar *submission_name = NULL;
int syslog_facility = LOG_MAIL;
uschar *syslog_processname = US"exim";
uschar *system_filter = NULL;
Expand Down Expand Up @@ -1556,60 +1594,16 @@ struct timeval timestamp_startup;
transport_instance *transports = NULL;

transport_instance transport_defaults = {
.next = NULL,
.name = NULL,
.info = NULL,
.options_block = NULL,
.driver_name = NULL,
.setup = NULL,
/* All non-mentioned elements zero/NULL/FALSE */
.batch_max = 1,
.batch_id = NULL,
.home_dir = NULL,
.current_dir = NULL,
.expand_multi_domain = NULL,
.multi_domain = TRUE,
.overrides_hosts = FALSE,
.max_addresses = 100,
.connection_max_messages = 500,
.deliver_as_creator = FALSE,
.disable_logging = FALSE,
.initgroups = FALSE,
.uid_set = FALSE,
.gid_set = FALSE,
.uid = (uid_t)(-1),
.gid = (gid_t)(-1),
.expand_uid = NULL,
.expand_gid = NULL,
.warn_message = NULL,
.shadow = NULL,
.shadow_condition = NULL,
.filter_command = NULL,
.add_headers = NULL,
.remove_headers = NULL,
.return_path = NULL,
.debug_string = NULL,
.max_parallel = NULL,
.message_size_limit = NULL,
.headers_rewrite = NULL,
.rewrite_rules = NULL,
.rewrite_existflags = 0,
.filter_timeout = 300,
.body_only = FALSE,
.delivery_date_add = FALSE,
.envelope_to_add = FALSE,
.headers_only = FALSE,
.rcpt_include_affixes = FALSE,
.return_path_add = FALSE,
.return_output = FALSE,
.return_fail_output = FALSE,
.log_output = FALSE,
.log_fail_output = FALSE,
.log_defer_output = FALSE,
.retry_use_local_part = TRUE_UNSET, /* retry_use_local_part: BOOL, but set neither
1 nor 0 so can detect unset */
#ifndef DISABLE_EVENT
.event_action = NULL
#endif
};

int transport_count;
Expand Down Expand Up @@ -1660,7 +1654,7 @@ uschar *uucp_from_sender = US"$1";
uschar *verify_mode = NULL;
uschar *version_copyright =
US"Copyright (c) University of Cambridge, 1995 - 2018\n"
"(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2018";
"(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2020";
uschar *version_date = US"?";
uschar *version_cnumber = US"????";
uschar *version_string = US"?";
Expand Down
53 changes: 42 additions & 11 deletions src/src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ extern int sqlite_lock_timeout; /* Internal lock waiting timeout */
extern BOOL move_frozen_messages; /* Get them out of the normal directory */
#endif

#ifdef ALLOW_INSECURE_TAINTED_DATA
extern BOOL allow_insecure_tainted_data;
#endif

/* These variables are outside the #ifdef because it keeps the code less
cluttered in several places (e.g. during logging) if we can always refer to
them. Also, the tls_ variables are now always visible. */
Expand Down Expand Up @@ -107,7 +111,7 @@ typedef struct {
OCSP_FAILED, /* verify failed */
OCSP_VFIED /* verified */
} ocsp; /* Stapled OCSP status */
#ifdef EXPERIMENTAL_TLS_RESUME
#ifndef DISABLE_TLS_RESUME
unsigned resumption; /* Session resumption */
BOOL host_resumable:1;
BOOL ticket_received:1;
Expand All @@ -121,8 +125,10 @@ extern tls_support tls_out;
#ifndef DISABLE_TLS
extern BOOL gnutls_compat_mode; /* Less security, more compatibility */
extern BOOL gnutls_allow_auto_pkcs11; /* Let GnuTLS autoload PKCS11 modules */
extern uschar *hosts_require_alpn; /* Mandatory ALPN successful nogitiation */
extern uschar *openssl_options; /* OpenSSL compatibility options */
extern const pcre *regex_STARTTLS; /* For recognizing STARTTLS settings */
extern uschar *tls_alpn; /* ALPN names acceptable */
extern uschar *tls_certificate; /* Certificate file */
extern uschar *tls_crl; /* CRL File */
extern int tls_dh_max_bits; /* don't accept higher lib suggestions */
Expand All @@ -134,12 +140,14 @@ extern uschar *tls_ocsp_file; /* OCSP stapling proof file */
extern uschar *tls_privatekey; /* Private key file */
extern BOOL tls_remember_esmtp; /* For YAEB */
extern uschar *tls_require_ciphers; /* So some can be avoided */
# ifdef EXPERIMENTAL_TLS_RESUME
# ifndef DISABLE_TLS_RESUME
extern uschar *tls_resumption_hosts; /* TLS session resumption */
# endif
extern uschar *tls_try_verify_hosts; /* Optional client verification */
extern uschar *tls_verify_certificates;/* Path for certificates to check */
extern uschar *tls_verify_hosts; /* Mandatory client verification */
extern int tls_watch_fd; /* for inotify of creds files */
extern time_t tls_watch_trigger_time; /* non-0: triggered */
#endif
extern uschar *tls_advertise_hosts; /* host for which TLS is advertised */

Expand All @@ -156,7 +164,7 @@ extern uschar * (*lwr_receive_getbuf)(unsigned *);
extern int (*lwr_receive_ungetc)(int);
extern int (*receive_getc)(unsigned);
extern uschar * (*receive_getbuf)(unsigned *);
extern void (*receive_get_cache)(void);
extern void (*receive_get_cache)(unsigned);
extern int (*receive_ungetc)(int);
extern int (*receive_feof)(void);
extern int (*receive_ferror)(void);
Expand All @@ -183,6 +191,7 @@ extern struct global_flags {
BOOL authentication_local :1; /* TRUE if non-smtp (implicit authentication) */

BOOL background_daemon :1; /* Set FALSE to keep in foreground */
BOOL bdat_readers_wanted :1; /* BDAT-handling to be pushed on readfunc stack */

BOOL chunking_offered :1;
BOOL config_changed :1; /* True if -C used */
Expand Down Expand Up @@ -269,6 +278,7 @@ extern struct global_flags {
#endif
BOOL smtp_in_pipelining_advertised :1; /* server advertised PIPELINING */
BOOL smtp_in_pipelining_used :1; /* server noted client using PIPELINING */
BOOL smtp_in_quit :1; /* server noted QUIT command */
BOOL spool_file_wireformat :1; /* current -D file has CRLF rather than NL */
BOOL submission_mode :1; /* Can be forced from ACL */
BOOL suppress_local_fixups :1; /* Can be forced from ACL */
Expand Down Expand Up @@ -425,10 +435,18 @@ extern uschar *config_main_filename; /* File name actually used */
extern uschar *config_main_directory; /* Directory where the main config file was found */
extern uid_t config_uid; /* Additional owner */
extern uschar *continue_proxy_cipher; /* TLS cipher for proxied continued delivery */
extern BOOL continue_proxy_dane; /* proxied conn is DANE */
extern uschar *continue_proxy_sni; /* proxied conn SNI */
extern uschar *continue_hostname; /* Host for continued delivery */
extern uschar *continue_host_address; /* IP address for ditto */
extern int continue_sequence; /* Sequence num for continued delivery */
extern uschar *continue_transport; /* Transport for continued delivery */
#ifdef EXPERIMENTAL_ESMTP_LIMITS
extern unsigned continue_limit_mail; /* Peer advertised limit */
extern unsigned continue_limit_rcpt;
extern unsigned continue_limit_rcptdom;
#endif


extern uschar *csa_status; /* Client SMTP Authorization result */

Expand Down Expand Up @@ -543,6 +561,7 @@ extern int dns_dane_ok; /* Ok to use DANE when checking TLS authe
extern int dns_retrans; /* Retransmission time setting */
extern int dns_retry; /* Number of retries */
extern int dns_dnssec_ok; /* When constructing DNS query, set DO flag */
extern const uschar * dns_rc_names[]; /* Mostly for debug output */
extern uschar *dns_trust_aa; /* DNSSEC trust AA as AD */
extern int dns_use_edns0; /* Coerce EDNS0 support on/off in resolver. */
extern uschar *dnslist_domain; /* DNS (black) list domain */
Expand Down Expand Up @@ -627,6 +646,7 @@ extern uschar *host_lookup_order; /* Order of host lookup types */
extern uschar *host_lookup_msg; /* Text for why it failed */
extern int host_number; /* For sharing spools */
extern uschar *host_number_string; /* For expanding */
extern uschar *hosts_require_helo; /* check for HELO/EHLO before MAIL */
extern uschar *host_reject_connection; /* Reject these hosts */
extern tree_node *hostlist_anchor; /* Tree of defined host lists */
extern int hostlist_count; /* Number defined */
Expand All @@ -646,6 +666,9 @@ extern uschar *keep_environment; /* Whitelist for environment variables */
extern int keep_malformed; /* Time to keep malformed messages */

extern uschar *eldap_dn; /* Where LDAP DNs are left */
#ifdef EXPERIMENTAL_ESMTP_LIMITS
extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */
#endif
extern int load_average; /* Most recently read load average */
extern BOOL local_from_check; /* For adding Sender: (global value) */
extern uschar *local_from_prefix; /* Permitted prefixes */
Expand Down Expand Up @@ -782,6 +805,7 @@ extern uschar *proxy_external_address; /* IP of remote interface of proxy */
extern int proxy_external_port; /* Port on remote interface of proxy */
extern uschar *proxy_local_address; /* IP of local interface of proxy */
extern int proxy_local_port; /* Port on local interface of proxy */
extern int proxy_protocol_timeout; /* Timeout for proxy negotiation */
extern BOOL proxy_session; /* TRUE if receiving mail from valid proxy */
#endif

Expand All @@ -792,7 +816,7 @@ extern uschar *prvscheck_result; /* Set during prvscheck expansion item */
extern const uschar *qualify_domain_recipient; /* Domain to qualify recipients with */
extern uschar *qualify_domain_sender; /* Domain to qualify senders with */
extern uschar *queue_domains; /* Queue these domains */
#ifdef EXPERIMENTAL_QUEUE_RAMP
#ifndef DISABLE_QUEUE_RAMP
extern BOOL queue_fast_ramp; /* 2-phase queue-run overlap */
#endif
extern BOOL queue_list_requires_admin; /* TRUE if -bp requires admin */
Expand Down Expand Up @@ -834,8 +858,8 @@ extern int received_count; /* Count of Received: headers */
extern uschar *received_for; /* For "for" field */
extern uschar *received_header_text; /* Definition of Received: header */
extern int received_headers_max; /* Max count of Received: headers */
extern struct timeval received_time; /* Time the message was received */
extern struct timeval received_time_taken; /* Interval the message took to be received */
extern struct timeval received_time; /* Time the message started to be received */
extern struct timeval received_time_complete; /* Time the message completed reception */
extern uschar *recipient_data; /* lookup data for recipients */
extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
extern uschar *recipient_verify_failure; /* What went wrong */
Expand All @@ -847,6 +871,9 @@ extern const pcre *regex_check_dns_names; /* For DNS name checking */
extern const pcre *regex_From; /* For recognizing "From_" lines */
extern const pcre *regex_CHUNKING; /* For recognizing CHUNKING (RFC 3030) */
extern const pcre *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */
#ifdef EXPERIMENTAL_ESMTP_LIMITS
extern const pcre *regex_LIMITS; /* For recognizing LIMITS */
#endif
extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */
extern const pcre *regex_SIZE; /* For recognizing SIZE settings */
#ifndef DISABLE_PIPE_CONNECT
Expand Down Expand Up @@ -919,12 +946,13 @@ extern BOOL smtp_accept_keepalive; /* Set keepalive on incoming */
extern int smtp_accept_max; /* Max SMTP connections */
extern int smtp_accept_max_nonmail;/* Max non-mail commands in one con */
extern uschar *smtp_accept_max_nonmail_hosts; /* Limit non-mail cmds from these hosts */
extern int smtp_accept_max_per_connection; /* Max msgs per connection */
extern uschar *smtp_accept_max_per_connection; /* Max msgs per connection */
extern uschar *smtp_accept_max_per_host; /* Max SMTP cons from one IP addr */
extern int smtp_accept_queue; /* Queue after so many connections */
extern int smtp_accept_queue_per_connection; /* Queue after so many msgs */
extern int smtp_accept_reserve; /* Reserve these SMTP connections */
extern uschar *smtp_active_hostname; /* Hostname for this message */
extern int smtp_backlog_monitor; /* listen backlog level to log */
extern uschar *smtp_banner; /* Banner string (to be expanded) */
extern BOOL smtp_check_spool_space; /* TRUE to check SMTP SIZE value */
extern int smtp_ch_index; /* Index in smtp_connection_had */
Expand All @@ -939,10 +967,13 @@ extern BOOL smtp_enforce_sync; /* Enforce sync rules */
extern uschar *smtp_etrn_command; /* Command to run */
extern BOOL smtp_etrn_serialize; /* Only one at once */
extern FILE *smtp_in; /* Incoming SMTP input file */
extern int smtp_listen_backlog; /* Current listener socket backlog, if monitored */
extern int smtp_load_reserve; /* Only from reserved if load > this */
extern int smtp_mailcmd_count; /* Count of MAIL commands */
extern int smtp_mailcmd_max; /* Limit for MAIL commands */
extern int smtp_max_synprot_errors;/* Max syntax/protocol errors */
extern int smtp_max_unknown_commands; /* As it says */
extern uschar *smtp_names[]; /* decode for command codes */
extern uschar *smtp_notquit_reason; /* Global for disconnect reason */
extern FILE *smtp_out; /* Incoming SMTP output file */
extern uschar *smtp_ratelimit_hosts; /* Rate limit these hosts */
Expand Down Expand Up @@ -989,7 +1020,7 @@ extern BOOL split_spool_directory; /* TRUE to use multiple subdirs */
extern FILE *spool_data_file; /* handle for -D file */
extern uschar *spool_directory; /* Name of spool directory */
extern BOOL spool_wireformat; /* can write wireformat -D files */
#ifdef EXPERIMENTAL_SRS
#ifdef EXPERIMENTAL_SRS_ALT
extern uschar *srs_config; /* SRS config secret:max age:hash length:use timestamp:use hash */
extern uschar *srs_db_address; /* SRS db address */
extern uschar *srs_db_key; /* SRS db key */
Expand All @@ -1004,7 +1035,7 @@ extern uschar *srs_status; /* SRS staus */
extern BOOL srs_usehash; /* SRS use hash flag */
extern BOOL srs_usetimestamp; /* SRS use timestamp flag */
#endif
#ifdef EXPERIMENTAL_SRS_NATIVE
#ifdef SUPPORT_SRS
extern uschar *srs_recipient; /* SRS recipient */
#endif
extern BOOL strict_acl_vars; /* ACL variables have to be set before being used */
Expand All @@ -1013,8 +1044,8 @@ extern int string_datestamp_length;/* After insertion by string_format */
extern int string_datestamp_type; /* After insertion by string_format */
extern BOOL strip_excess_angle_brackets; /* Surrounding route-addrs */
extern BOOL strip_trailing_dot; /* Remove dots at ends of domains */
extern uschar *submission_domain; /* Domain for submission mode */
extern uschar *submission_name; /* User name set from ACL */
extern const uschar *submission_domain;/* Domain for submission mode */
extern const uschar *submission_name; /* User name set from ACL */
extern BOOL syslog_duplication; /* FALSE => no duplicate logging */
extern int syslog_facility; /* As defined by Syslog.h */
extern BOOL syslog_pid; /* TRUE if PID on syslogs */
Expand Down
9 changes: 6 additions & 3 deletions src/src/header.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,15 @@ header_add_backend(BOOL after, uschar *name, BOOL topnot, int type,
header_line *h, *new = NULL;
header_line **hptr;

uschar *p, *q;
uschar * buf = store_get(HEADER_ADD_BUFFER_SIZE, FALSE);
gstring gs = { .size = HEADER_ADD_BUFFER_SIZE, .ptr = 0, .s = buf };
uschar * p, * q, * buf;
gstring gs;

if (!header_last) return NULL;

gs.s = buf = store_get(HEADER_ADD_BUFFER_SIZE, FALSE);
gs.size = HEADER_ADD_BUFFER_SIZE;
gs.ptr = 0;

if (!string_vformat(&gs, SVFMT_REBUFFER, format, ap))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "string too long in header_add: "
"%.100s ...", string_from_gstring(&gs));
Expand Down
187 changes: 106 additions & 81 deletions src/src/host.c

Large diffs are not rendered by default.

8 changes: 2 additions & 6 deletions src/src/ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,6 @@ if (af == AF_INET6)
return sizeof(sin->v6);
}
else
#else /* HAVE_IPv6 */
af = af; /* Avoid compiler warning */
#endif /* HAVE_IPV6 */

/* Setup code when using IPv4 socket. The wildcard address is "". */
Expand Down Expand Up @@ -209,8 +207,6 @@ if (af == AF_INET6)
s_len = sizeof(s_in6);
}
else
#else /* HAVE_IPV6 */
af = af; /* Avoid compiler warning */
#endif /* HAVE_IPV6 */

/* For an IPv4 address, use an IPv4 sockaddr structure, even on a system with
Expand Down Expand Up @@ -467,8 +463,8 @@ for (host_item * h = &shost; h; h = h->next)
for (int port = portlo; port <= porthi; port++)
if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
{
if (fd != fd6) close(fd6);
if (fd != fd4) close(fd4);
if (fd6 >= 0 && fd != fd6) close(fd6);
if (fd4 >= 0 && fd != fd4) close(fd4);
if (connhost)
{
h->port = port;
Expand Down
2 changes: 0 additions & 2 deletions src/src/local_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ The return values of this function are:
int
local_scan(int fd, uschar **return_text)
{
fd = fd; /* Keep picky compilers happy */
return_text = return_text;
return LOCAL_SCAN_ACCEPT;
}

Expand Down
443 changes: 257 additions & 186 deletions src/src/log.c

Large diffs are not rendered by default.

88 changes: 44 additions & 44 deletions src/src/lookups/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,51 +24,51 @@ lookups.a: $(OBJ)
.c.so:; @echo "$(CC) -shared $*.c"
$(FE)$(CC) $(LOOKUP_$*_INCLUDE) $(LOOKUP_$*_LIBS) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@

lf_check_file.o: $(PHDRS) lf_check_file.c lf_functions.h
lf_quote.o: $(PHDRS) lf_quote.c lf_functions.h
lf_sqlperform.o: $(PHDRS) lf_sqlperform.c lf_functions.h
lf_check_file.o: $(HDRS) lf_check_file.c lf_functions.h
lf_quote.o: $(HDRS) lf_quote.c lf_functions.h
lf_sqlperform.o: $(HDRS) lf_sqlperform.c lf_functions.h

cdb.o: $(PHDRS) cdb.c
dbmdb.o: $(PHDRS) dbmdb.c
dnsdb.o: $(PHDRS) dnsdb.c
dsearch.o: $(PHDRS) dsearch.c
ibase.o: $(PHDRS) ibase.c
ldap.o: $(PHDRS) ldap.c
lmdb.o: $(PHDRS) lmdb.c
json.o: $(PHDRS) json.c
lsearch.o: $(PHDRS) lsearch.c
mysql.o: $(PHDRS) mysql.c
nis.o: $(PHDRS) nis.c
nisplus.o: $(PHDRS) nisplus.c
oracle.o: $(PHDRS) oracle.c
passwd.o: $(PHDRS) passwd.c
pgsql.o: $(PHDRS) pgsql.c
readsock.o: $(PHDRS) readsock.c
redis.o: $(PHDRS) redis.c
spf.o: $(PHDRS) spf.c
sqlite.o: $(PHDRS) sqlite.c
testdb.o: $(PHDRS) testdb.c
whoson.o: $(PHDRS) whoson.c
cdb.o: $(HDRS) cdb.c
dbmdb.o: $(HDRS) dbmdb.c
dnsdb.o: $(HDRS) dnsdb.c
dsearch.o: $(HDRS) dsearch.c
ibase.o: $(HDRS) ibase.c
ldap.o: $(HDRS) ldap.c
lmdb.o: $(HDRS) lmdb.c
json.o: $(HDRS) json.c
lsearch.o: $(HDRS) lsearch.c
mysql.o: $(HDRS) mysql.c
nis.o: $(HDRS) nis.c
nisplus.o: $(HDRS) nisplus.c
oracle.o: $(HDRS) oracle.c
passwd.o: $(HDRS) passwd.c
pgsql.o: $(HDRS) pgsql.c
readsock.o: $(HDRS) readsock.c
redis.o: $(HDRS) redis.c
spf.o: $(HDRS) spf.c
sqlite.o: $(HDRS) sqlite.c
testdb.o: $(HDRS) testdb.c
whoson.o: $(HDRS) whoson.c

cdb.so: $(PHDRS) cdb.c
dbmdb.so: $(PHDRS) dbmdb.c
dnsdb.so: $(PHDRS) dnsdb.c
dsearch.so: $(PHDRS) dsearch.c
ibase.so: $(PHDRS) ibase.c
json.so: $(PHDRS) json.c
ldap.so: $(PHDRS) ldap.c
lmdb.so: $(PHDRS) lmdb.c
lsearch.so: $(PHDRS) lsearch.c
mysql.so: $(PHDRS) mysql.c
nis.so: $(PHDRS) nis.c
nisplus.so: $(PHDRS) nisplus.c
oracle.so: $(PHDRS) oracle.c
passwd.so: $(PHDRS) passwd.c
pgsql.so: $(PHDRS) pgsql.c
redis.so: $(PHDRS) redis.c
spf.so: $(PHDRS) spf.c
sqlite.so: $(PHDRS) sqlite.c
testdb.so: $(PHDRS) testdb.c
whoson.so: $(PHDRS) whoson.c
cdb.so: $(HDRS) cdb.c
dbmdb.so: $(HDRS) dbmdb.c
dnsdb.so: $(HDRS) dnsdb.c
dsearch.so: $(HDRS) dsearch.c
ibase.so: $(HDRS) ibase.c
json.so: $(HDRS) json.c
ldap.so: $(HDRS) ldap.c
lmdb.so: $(HDRS) lmdb.c
lsearch.so: $(HDRS) lsearch.c
mysql.so: $(HDRS) mysql.c
nis.so: $(HDRS) nis.c
nisplus.so: $(HDRS) nisplus.c
oracle.so: $(HDRS) oracle.c
passwd.so: $(HDRS) passwd.c
pgsql.so: $(HDRS) pgsql.c
redis.so: $(HDRS) redis.c
spf.so: $(HDRS) spf.c
sqlite.so: $(HDRS) sqlite.c
testdb.so: $(HDRS) testdb.c
whoson.so: $(HDRS) whoson.c

# End
21 changes: 4 additions & 17 deletions src/src/lookups/cdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,19 +157,14 @@ void * mapbuf;

if ((fileno = Uopen(filename, O_RDONLY, 0)) < 0)
{
int save_errno = errno;
*errmsg = string_open_failed(errno, "%s for cdb lookup", filename);
errno = save_errno;
*errmsg = string_open_failed("%s for cdb lookup", filename);
return NULL;
}

if (fstat(fileno, &statbuf) != 0)
{
int save_errno = errno;
*errmsg = string_open_failed(errno,
"fstat(%s) failed - cannot do cdb lookup",
*errmsg = string_open_failed("fstat(%s) failed - cannot do cdb lookup",
filename);
errno = save_errno;
return NULL;
}

Expand All @@ -178,11 +173,7 @@ CDB_HASH_TABLE bytes long */

if (statbuf.st_size < CDB_HASH_TABLE)
{
int save_errno = errno;
*errmsg = string_open_failed(errno,
"%s too short for cdb lookup",
filename);
errno = save_errno;
*errmsg = string_open_failed("%s too short for cdb lookup", filename);
return NULL;
}

Expand Down Expand Up @@ -231,8 +222,7 @@ if (cdb_bread(fileno, cdbp->cdb_offsets, CDB_HASH_TABLE) == -1)
/* read of hash table failed, oh dear, oh..... time to give up I think....
call the close routine (deallocs the memory), and return NULL */

*errmsg = string_open_failed(errno,
"cannot read header from %s for cdb lookup",
*errmsg = string_open_failed("cannot read header from %s for cdb lookup",
filename);
cdb_close(cdbp);
return NULL;
Expand Down Expand Up @@ -281,9 +271,6 @@ hash_offset,
hash_offlen,
hash_slotnm;

/* Keep picky compilers happy */
do_cache = do_cache;

key_hash = cdb_hash(keystring, key_len);

hash_offset_entry = CDB_HASH_ENTRY * (key_hash & CDB_HASH_MASK);
Expand Down
11 changes: 1 addition & 10 deletions src/src/lookups/dbmdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,7 @@ EXIM_DB *yield = NULL;
if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
if (!yield)
{
int save_errno = errno;
*errmsg = string_open_failed(errno, "%s as a %s file", filename, EXIM_DBTYPE);
errno = save_errno;
}
*errmsg = string_open_failed("%s as a %s file", filename, EXIM_DBTYPE);
return yield;
}

Expand All @@ -52,7 +48,6 @@ dbmdb_check(void *handle, const uschar *filename, int modemask, uid_t *owners,
gid_t *owngroups, uschar **errmsg)
{
int rc;
handle = handle; /* Keep picky compilers happy */

#if defined(USE_DB) || defined(USE_TDB) || defined(USE_GDBM)
rc = lf_check_file(-1, filename, S_IFREG, modemask, owners, owngroups,
Expand Down Expand Up @@ -98,10 +93,6 @@ dbmdb_find(void * handle, const uschar * filename, const uschar * keystring,
EXIM_DB *d = (EXIM_DB *)handle;
EXIM_DATUM key, data;

filename = filename; /* Keep picky compilers happy */
errmsg = errmsg;
do_cache = do_cache;

EXIM_DATUM_INIT(key); /* Some DBM libraries require datums to */
EXIM_DATUM_INIT(data); /* be cleared before use. */
EXIM_DATUM_DATA(key) = CS keystring;
Expand Down
42 changes: 25 additions & 17 deletions src/src/lookups/dnsdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ static int type_values[] = {
static void *
dnsdb_open(const uschar * filename, uschar **errmsg)
{
filename = filename; /* Keep picky compilers happy */
errmsg = errmsg; /* Ditto */
return (void *)(-1); /* Any non-0 value */
}

Expand Down Expand Up @@ -155,11 +153,6 @@ store as possible later, so we preallocate the result here */

gstring * yield = string_get(256);

handle = handle; /* Keep picky compilers happy */
filename = filename;
length = length;
do_cache = do_cache;

/* If the string starts with '>' we change the output separator.
If it's followed by ';' or ',' we set the TXT output separator. */

Expand Down Expand Up @@ -197,7 +190,8 @@ for (;;)
else
{
*errmsg = US"unsupported dnsdb defer behaviour";
return DEFER;
rc = DEFER;
goto out;
}
}
else if (strncmpic(keystring, US"dnssec_", 7) == 0)
Expand All @@ -212,7 +206,8 @@ for (;;)
else
{
*errmsg = US"unsupported dnsdb dnssec behaviour";
return DEFER;
rc = DEFER;
goto out;
}
}
else if (strncmpic(keystring, US"retrans_", 8) == 0)
Expand All @@ -221,7 +216,8 @@ for (;;)
if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0)
{
*errmsg = US"unsupported dnsdb timeout value";
return DEFER;
rc = DEFER;
goto out;
}
dns_retrans = timeout_sec;
while (*keystring != ',') keystring++;
Expand All @@ -232,7 +228,8 @@ for (;;)
if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0)
{
*errmsg = US"unsupported dnsdb retry count";
return DEFER;
rc = DEFER;
goto out;
}
dns_retry = retries;
}
Expand All @@ -243,7 +240,8 @@ for (;;)
if (*keystring++ != ',')
{
*errmsg = US"dnsdb modifier syntax error";
return DEFER;
rc = DEFER;
goto out;
}
while (isspace(*keystring)) keystring++;
}
Expand Down Expand Up @@ -271,7 +269,8 @@ if ((equals = Ustrchr(keystring, '=')) != NULL)
if (i >= nelem(type_names))
{
*errmsg = US"unsupported DNS record type";
return DEFER;
rc = DEFER;
goto out;
}

keystring = equals + 1;
Expand Down Expand Up @@ -366,7 +365,8 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
dns_retrans = save_retrans;
dns_retry = save_retry;
dns_init(FALSE, FALSE, FALSE); /* clr dnssec bit */
return DEFER; /* always defer */
rc = DEFER; /* always defer */
goto out;
}
if (defer_mode == PASS) failrc = DEFER; /* defer only if all do */
continue; /* treat defer as fail */
Expand Down Expand Up @@ -556,10 +556,18 @@ dns_retrans = save_retrans;
dns_retry = save_retry;
dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */

if (!yield || !yield->ptr) return failrc;
if (!yield || !yield->ptr)
rc = failrc;
else
{
*result = string_from_gstring(yield);
rc = OK;
}

out:

*result = string_from_gstring(yield);
return OK;
store_free_dns_answer(dnsa);
return rc;
}


Expand Down
15 changes: 4 additions & 11 deletions src/src/lookups/dsearch.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ dsearch_open(const uschar * dirname, uschar ** errmsg)
DIR * dp = exim_opendir(dirname);
if (!dp)
{
int save_errno = errno;
*errmsg = string_open_failed(errno, "%s for directory search", dirname);
errno = save_errno;
*errmsg = string_open_failed("%s for directory search", dirname);
return NULL;
}
closedir(dp);
Expand Down Expand Up @@ -86,10 +84,6 @@ int save_errno;
uschar * filename;
unsigned flags = 0;

handle = handle; /* Keep picky compilers happy */
length = length;
do_cache = do_cache;

if (Ustrchr(keystring, '/') != 0)
{
*errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
Expand Down Expand Up @@ -125,8 +119,7 @@ if ( Ulstat(filename, &statbuf) >= 0
&& S_ISDIR(statbuf.st_mode)
&& ( flags & FILTER_DIR
|| keystring[0] != '.'
|| keystring[1] != '.'
|| keystring[1] && keystring[2]
|| keystring[1] && keystring[1] != '.'
) ) ) )
{
/* Since the filename exists in the filesystem, we can return a
Expand All @@ -135,10 +128,10 @@ if ( Ulstat(filename, &statbuf) >= 0
return OK;
}

if (errno == ENOENT) return FAIL;
if (errno == ENOENT || errno == 0) return FAIL;

save_errno = errno;
*errmsg = string_sprintf("%s: lstat failed", filename);
*errmsg = string_sprintf("%s: lstat: %s", filename, strerror(errno));
errno = save_errno;
return DEFER;
}
Expand Down
6 changes: 1 addition & 5 deletions src/src/lookups/ibase.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,10 @@ ibase_find(void * handle, const uschar * filename, uschar * query, int length,
int sep = 0;
uschar *server;
uschar *list = ibase_servers;
uschar buffer[512];

/* Keep picky compilers happy */
do_cache = do_cache;

DEBUG(D_lookup) debug_printf_indent("Interbase query: %s\n", query);

while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
while ((server = string_nextinlist(&list, &sep, NULL, 0)))
{
BOOL defer_break = FALSE;
int rc = perform_ibase_search(query, server, result, errmsg, &defer_break);
Expand Down
10 changes: 1 addition & 9 deletions src/src/lookups/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,7 @@ FILE * f;
json_set_alloc_funcs(json_malloc, json_free);

if (!(f = Ufopen(filename, "rb")))
{
int save_errno = errno;
*errmsg = string_open_failed(errno, "%s for json search", filename);
errno = save_errno;
return NULL;
}
*errmsg = string_open_failed("%s for json search", filename);
return f;
}

Expand Down Expand Up @@ -89,9 +84,6 @@ json_error_t jerr;
uschar * key;
int sep = 0;

length = length; /* Keep picky compilers happy */
do_cache = do_cache; /* Keep picky compilers happy */

rewind(f);
if (!(j = json_loadf(f, 0, &jerr)))
{
Expand Down
33 changes: 10 additions & 23 deletions src/src/lookups/ldap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1091,9 +1091,7 @@ const uschar *p;
uschar *user = NULL;
uschar *password = NULL;
uschar *local_servers = NULL;
uschar *server;
const uschar *list;
uschar buffer[512];

while (isspace(*url)) url++;

Expand Down Expand Up @@ -1251,13 +1249,13 @@ if (!eldap_default_servers && !local_servers || p[3] != '/')
&defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
referrals);

/* Loop through the default servers until OK or FAIL. Use local_servers list
* if defined in the lookup, otherwise use the global default list */
list = !local_servers ? eldap_default_servers : local_servers;
while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
/* Loop through the servers until OK or FAIL. Use local_servers list
if defined in the lookup, otherwise use the global default list */

list = local_servers ? local_servers : eldap_default_servers;
for (uschar * server; server = string_nextinlist(&list, &sep, NULL, 0); )
{
int rc;
int port = 0;
int rc, port = 0;
uschar *colon = Ustrchr(server, ':');
if (colon)
{
Expand Down Expand Up @@ -1288,8 +1286,6 @@ eldap_find(void * handle, const uschar * filename, const uschar * ldap_url,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
/* Keep picky compilers happy */
do_cache = do_cache;
return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
}

Expand All @@ -1298,8 +1294,6 @@ eldapm_find(void * handle, const uschar * filename, const uschar * ldap_url,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
/* Keep picky compilers happy */
do_cache = do_cache;
return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
}

Expand All @@ -1308,17 +1302,13 @@ eldapdn_find(void * handle, const uschar * filename, const uschar * ldap_url,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
/* Keep picky compilers happy */
do_cache = do_cache;
return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
}

int
eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url,
int length, uschar ** result, uschar ** errmsg, uint * do_cache)
{
/* Keep picky compilers happy */
do_cache = do_cache;
return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg));
}

Expand Down Expand Up @@ -1348,16 +1338,13 @@ Make sure that eldap_dn does not refer to reclaimed or worse, freed store */
static void
eldap_tidy(void)
{
LDAP_CONNECTION *lcp = NULL;
eldap_dn = NULL;

while ((lcp = ldap_connections) != NULL)
for (LDAP_CONNECTION *lcp; lcp = ldap_connections; ldap_connections = lcp->next)
{
DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", lcp->host,
lcp->port);
if(lcp->bound == TRUE)
ldap_unbind(lcp->ld);
ldap_connections = lcp->next;
DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n",
lcp->host, lcp->port);
if(lcp->bound) ldap_unbind(lcp->ld);
}
}

Expand Down
14 changes: 9 additions & 5 deletions src/src/lookups/lf_sqlperform.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,13 @@ if (Ustrncmp(query, "servers", 7) == 0)
}
}

if (is_tainted(server))
{
*errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
{ uschar *m;
if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
{
*errmsg = m;
return DEFER;
}
}

rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
Expand Down Expand Up @@ -158,11 +160,13 @@ else
server = ele;
}

if (is_tainted(server))
{ uschar *m;
if ((m = is_tainted2(server, 0, "Tainted %s server '%s'", name, server)))
{
*errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
*errmsg = m;
return DEFER;
}
}

rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
if (rc != DEFER || defer_break) return rc;
Expand Down
4 changes: 2 additions & 2 deletions src/src/lookups/lmdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "../exim.h"

#ifdef EXPERIMENTAL_LMDB
#ifdef LOOKUP_LMDB

#include <lmdb.h>

Expand Down Expand Up @@ -158,4 +158,4 @@ static lookup_info lmdb_lookup_info = {
static lookup_info *_lookup_list[] = { &lmdb_lookup_info };
lookup_module_info lmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };

#endif /* EXPERIMENTAL_LMDB */
#endif /* LOOKUP_LMDB */
129 changes: 64 additions & 65 deletions src/src/lookups/lsearch.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,9 @@ enum {
static void *
lsearch_open(const uschar * filename, uschar ** errmsg)
{
FILE *f = Ufopen(filename, "rb");
if (f == NULL)
{
int save_errno = errno;
*errmsg = string_open_failed(errno, "%s for linear search", filename);
errno = save_errno;
return NULL;
}
FILE * f = Ufopen(filename, "rb");
if (!f)
*errmsg = string_open_failed("%s for linear search", filename);
return f;
}

Expand Down Expand Up @@ -74,32 +69,38 @@ but people do occasionally do weird things. */
static int
internal_lsearch_find(void * handle, const uschar * filename,
const uschar * keystring, int length, uschar ** result, uschar ** errmsg,
int type)
int type, const uschar * opts)
{
FILE *f = (FILE *)handle;
BOOL last_was_eol = TRUE;
BOOL this_is_eol = TRUE;
FILE *f = handle;
BOOL ret_full = FALSE;
int old_pool = store_pool;
rmark reset_point = NULL;
uschar buffer[4096];

if (opts)
{
int sep = ',';
uschar * ele;

while ((ele = string_nextinlist(&opts, &sep, NULL, 0)))
if (Ustrcmp(ele, "ret=full") == 0)
{ ret_full = TRUE; break; }
}

/* Wildcard searches may use up some store, because of expansions. We don't
want them to fill up our search store. What we do is set the pool to the main
pool and get a point to reset to later. Wildcard searches could also issue
lookups, but internal_search_find will take care of that, and the cache will be
safely stored in the search pool again. */

if(type == LSEARCH_WILD || type == LSEARCH_NWILD)
if (type == LSEARCH_WILD || type == LSEARCH_NWILD)
{
store_pool = POOL_MAIN;
reset_point = store_mark();
}

filename = filename; /* Keep picky compilers happy */
errmsg = errmsg;

rewind(f);
for (last_was_eol = TRUE;
for (BOOL this_is_eol, last_was_eol = TRUE;
Ufgets(buffer, sizeof(buffer), f) != NULL;
last_was_eol = this_is_eol)
{
Expand Down Expand Up @@ -145,21 +146,22 @@ for (last_was_eol = TRUE;
if (*s == '\"')
{
uschar *t = s++;
while (*s != 0 && *s != '\"')
while (*s && *s != '\"')
{
if (*s == '\\') *t++ = string_interpret_escape(CUSS &s);
else *t++ = *s;
*t++ = *s == '\\' ? string_interpret_escape(CUSS &s) : *s;
s++;
}
if (*s != 0) s++; /* Past terminating " */
linekeylength = t - buffer;
if (*s) s++; /* Past terminating " */
if (ret_full)
memmove(t, s, Ustrlen(s)+1); /* copy the rest of line also */
}

/* Otherwise it is terminated by a colon or white space */

else
{
while (*s != 0 && *s != ':' && !isspace(*s)) s++;
while (*s && *s != ':' && !isspace(*s)) s++;
linekeylength = s - buffer;
}

Expand All @@ -170,9 +172,9 @@ for (last_was_eol = TRUE;
/* A plain lsearch treats each key as a literal */

case LSEARCH_PLAIN:
if (linekeylength != length || strncmpic(buffer, keystring, length) != 0)
continue;
break; /* Key matched */
if (linekeylength != length || strncmpic(buffer, keystring, length) != 0)
continue;
break; /* Key matched */

/* A wild lsearch treats each key as a possible wildcarded string; no
expansion is done for nwildlsearch. */
Expand All @@ -189,55 +191,55 @@ for (last_was_eol = TRUE;
UCHAR_MAX+1, /* Single-item list */
NULL, /* No anchor */
NULL, /* No caching */
MCL_STRING + ((type == LSEARCH_WILD)? 0:MCL_NOEXPAND),
MCL_STRING + (type == LSEARCH_WILD ? 0 : MCL_NOEXPAND),
TRUE, /* Caseless */
NULL);
buffer[linekeylength] = save;
if (rc == FAIL) continue;
if (rc == DEFER) return DEFER;
}

/* The key has matched. If the search involved a regular expression, it
might have caused numerical variables to be set. However, their values will
be in the wrong storage pool for external use. Copying them to the standard
pool is not feasible because of the caching of lookup results - a repeated
lookup will not match the regular expression again. Therefore, we flatten
all numeric variables at this point. */
/* The key has matched. If the search involved a regular expression, it
might have caused numerical variables to be set. However, their values will
be in the wrong storage pool for external use. Copying them to the standard
pool is not feasible because of the caching of lookup results - a repeated
lookup will not match the regular expression again. Therefore, we drop
all numeric variables at this point. */

expand_nmax = -1;
break;
expand_nmax = -1;
break;

/* Compare an ip address against a list of network/ip addresses. We have to
allow for the "*" case specially. */

case LSEARCH_IP:
if (linekeylength == 1 && buffer[0] == '*')
{
if (length != 1 || keystring[0] != '*') continue;
}
else if (length == 1 && keystring[0] == '*') continue;
else
{
int maskoffset;
int save = buffer[linekeylength];
buffer[linekeylength] = 0;
if (string_is_ip_address(buffer, &maskoffset) == 0 ||
!host_is_in_net(keystring, buffer, maskoffset)) continue;
buffer[linekeylength] = save;
}
break; /* Key matched */
if (linekeylength == 1 && buffer[0] == '*')
{
if (length != 1 || keystring[0] != '*') continue;
}
else if (length == 1 && keystring[0] == '*') continue;
else
{
int maskoffset;
int save = buffer[linekeylength];
buffer[linekeylength] = 0;
if (string_is_ip_address(buffer, &maskoffset) == 0 ||
!host_is_in_net(keystring, buffer, maskoffset)) continue;
buffer[linekeylength] = save;
}
break; /* Key matched */
}

/* The key has matched. Skip spaces after the key, and allow an optional
colon after the spaces. This is an odd specification, but it's for
compatibility. */

while (isspace((uschar)*s)) s++;
if (*s == ':')
{
s++;
while (isspace((uschar)*s)) s++;
}
if (!ret_full)
if (Uskip_whitespace(&s) == ':')
{
s++;
Uskip_whitespace(&s);
}

/* Reset dynamic store, if we need to, and revert to the search pool */

Expand All @@ -256,7 +258,9 @@ for (last_was_eol = TRUE;

this_is_comment = FALSE;
yield = string_get(100);
if (*s != 0)
if (ret_full)
yield = string_cat(yield, buffer);
else if (*s)
yield = string_cat(yield, s);

/* Now handle continuations */
Expand Down Expand Up @@ -324,9 +328,8 @@ lsearch_find(void * handle, const uschar * filename, const uschar * keystring,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
errmsg, LSEARCH_PLAIN);
errmsg, LSEARCH_PLAIN, opts);
}


Expand All @@ -342,9 +345,8 @@ wildlsearch_find(void * handle, const uschar * filename, const uschar * keystrin
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
errmsg, LSEARCH_WILD);
errmsg, LSEARCH_WILD, opts);
}


Expand All @@ -360,9 +362,8 @@ nwildlsearch_find(void * handle, const uschar * filename, const uschar * keystri
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
errmsg, LSEARCH_NWILD);
errmsg, LSEARCH_NWILD, opts);
}


Expand All @@ -379,12 +380,10 @@ iplsearch_find(void * handle, uschar const * filename, const uschar * keystring,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
do_cache = do_cache; /* Keep picky compilers happy */

if ((length == 1 && keystring[0] == '*') ||
string_is_ip_address(keystring, NULL) != 0)
return internal_lsearch_find(handle, filename, keystring, length, result,
errmsg, LSEARCH_IP);
errmsg, LSEARCH_IP, opts);

*errmsg = string_sprintf("\"%s\" is not a valid iplsearch key (an IP "
"address, with optional CIDR mask, is wanted): "
Expand Down
3 changes: 1 addition & 2 deletions src/src/lookups/oracle.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,13 +510,12 @@ oracle_find(void * handle, const uschar * filename, uschar * query, int length,
int sep = 0;
uschar *server;
uschar *list = oracle_servers;
uschar buffer[512];

do_cache = do_cache; /* Placate picky compilers */

DEBUG(D_lookup) debug_printf_indent("ORACLE query: %s\n", query);

while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
while ((server = string_nextinlist(&list, &sep, NULL, 0)))
{
BOOL defer_break;
int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
Expand Down
8 changes: 0 additions & 8 deletions src/src/lookups/passwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
static void *
passwd_open(const uschar * filename, uschar ** errmsg)
{
filename = filename; /* Keep picky compilers happy */
errmsg = errmsg;
return (void *)(-1); /* Just return something non-null */
}

Expand All @@ -40,12 +38,6 @@ passwd_find(void * handle, const uschar * filename, const uschar * keystring,
{
struct passwd *pw;

handle = handle; /* Keep picky compilers happy */
filename = filename;
length = length;
errmsg = errmsg;
do_cache = do_cache;

if (!route_finduser(keystring, &pw, NULL)) return FAIL;
*result = string_sprintf("*:%d:%d:%s:%s:%s", (int)pw->pw_uid, (int)pw->pw_gid,
pw->pw_gecos, pw->pw_dir, pw->pw_shell);
Expand Down
32 changes: 19 additions & 13 deletions src/src/lookups/readsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ static int
internal_readsock_open(client_conn_ctx * cctx, const uschar * sspec,
int timeout, BOOL do_tls, uschar ** errmsg)
{
int sep = ',';
uschar * ele;
const uschar * server_name;
host_item host;

Expand Down Expand Up @@ -182,11 +180,12 @@ struct {
} lf = {.do_shutdown = TRUE};
uschar * eol = NULL;
int timeout = 5;
FILE * fp;
gstring * yield;
int ret = DEFER;

DEBUG(D_lookup) debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n", filename, keystring, length, opts);
DEBUG(D_lookup)
debug_printf_indent("readsock: file=\"%s\" key=\"%s\" len=%d opts=\"%s\"\n",
filename, keystring, length, opts);

/* Parse options */

Expand All @@ -200,7 +199,7 @@ if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); )
lf.do_tls = TRUE;
#endif
else if (Ustrncmp(s, "eol=", 4) == 0)
eol = s + 4;
eol = string_unprinting(s + 4);
else if (Ustrcmp(s, "cache=yes") == 0)
lf.cache = TRUE;
else if (Ustrcmp(s, "send=no") == 0)
Expand Down Expand Up @@ -248,16 +247,23 @@ that reads a file can be used. If we're using a stdio buffered read,
and might need later write ops on the socket, the stdio must be in
writable mode or the underlying socket goes non-writable. */

if (!cctx->tls_ctx)
fp = fdopen(cctx->sock, lf.do_shutdown ? "rb" : "wb");

sigalrm_seen = FALSE;
ALARM(timeout);
yield =
#ifndef DISABLE_TLS
cctx->tls_ctx ? cat_file_tls(cctx->tls_ctx, NULL, eol) :
#ifdef DISABLE_TLS
if (TRUE)
#else
if (!cctx->tls_ctx)
#endif
cat_file(fp, NULL, eol);
{
FILE * fp = fdopen(cctx->sock, lf.do_shutdown ? "rb" : "wb");
ALARM(timeout);
yield = cat_file(fp, NULL, eol);
}
else
{
ALARM(timeout);
yield = cat_file_tls(cctx->tls_ctx, NULL, eol);
}

ALARM_CLR(0);

if (sigalrm_seen)
Expand Down
13 changes: 10 additions & 3 deletions src/src/lookups/sqlite.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,23 @@ sqlite_open(const uschar * filename, uschar ** errmsg)
sqlite3 *db = NULL;
int ret;

if (!filename || !*filename) filename = sqlite_dbfile;
if (*filename != '/')
if (!filename || !*filename)
{
DEBUG(D_lookup) debug_printf_indent("Using sqlite_dbfile: %s\n", sqlite_dbfile);
filename = sqlite_dbfile;
}
if (!filename || *filename != '/')
*errmsg = US"absolute file name expected for \"sqlite\" lookup";
else if ((ret = sqlite3_open(CCS filename, &db)) != 0)
{
*errmsg = (void *)sqlite3_errmsg(db);
sqlite3_close(db);
db = NULL;
DEBUG(D_lookup) debug_printf_indent("Error opening database: %s\n", *errmsg);
}

sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout);
if (db)
sqlite3_busy_timeout(db, 1000 * sqlite_lock_timeout);
return db;
}

Expand Down
6 changes: 0 additions & 6 deletions src/src/lookups/testdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ the find function. */
static void *
testdb_open(const uschar * filename, uschar ** errmsg)
{
filename = filename; /* Keep picky compilers happy */
errmsg = errmsg;
return (void *)(1); /* Just return something non-null */
}

Expand All @@ -42,10 +40,6 @@ testdb_find(void * handle, const uschar * filename, const uschar * query,
int length, uschar ** result, uschar ** errmsg, uint * do_cache,
const uschar * opts)
{
handle = handle; /* Keep picky compilers happy */
filename = filename;
length = length;

if (Ustrcmp(query, "fail") == 0)
{
*errmsg = US"testdb lookup forced FAIL";
Expand Down
7 changes: 0 additions & 7 deletions src/src/lookups/whoson.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
static void *
whoson_open(const uschar * filename, uschar ** errmsg)
{
filename = filename; /* Keep picky compilers happy */
errmsg = errmsg;
return (void *)(1); /* Just return something non-null */
}

Expand All @@ -40,11 +38,6 @@ whoson_find(void * handle, const uschar * filename, uschar * query, int length,
uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts)
{
uschar buffer[80];
handle = handle; /* Keep picky compilers happy */
filename = filename;
length = length;
errmsg = errmsg;
do_cache = do_cache;

switch (wso_query(CS query, CS buffer, sizeof(buffer)))
{
Expand Down
49 changes: 39 additions & 10 deletions src/src/macro_predef.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ options_from_list(optionlist * opts, unsigned nopt,
const uschar * section, uschar * group)
{
const uschar * s;
uschar buf[64];
uschar buf[EXIM_DRIVERNAME_MAX];

/* The 'previously-defined-substring' rule for macros in config file
lines is done thus for these builtin macros: we know that the table
Expand Down Expand Up @@ -174,21 +174,18 @@ due to conflicts with other common macros. */
#ifdef SUPPORT_SOCKS
builtin_macro_create(US"_HAVE_SOCKS");
#endif
#if defined(SUPPORT_SRS)
builtin_macro_create(US"_HAVE_NATIVE_SRS"); /* beware clash with _HAVE_SRS */
#endif
#ifdef TCP_FASTOPEN
builtin_macro_create(US"_HAVE_TCP_FASTOPEN");
#endif
#ifdef EXPERIMENTAL_LMDB
builtin_macro_create(US"_HAVE_LMDB");
#endif
#ifdef SUPPORT_SPF
builtin_macro_create(US"_HAVE_SPF");
#endif
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
#if defined(EXPERIMENTAL_SRS_ALT) || defined(SUPPORT_SRS)
builtin_macro_create(US"_HAVE_SRS");
#endif
#if defined(EXPERIMENTAL_SRS_NATIVE)
builtin_macro_create(US"_HAVE_NATIVE_SRS"); /* beware clash with _HAVE_SRS */
#endif
#ifdef EXPERIMENTAL_ARC
builtin_macro_create(US"_HAVE_ARC");
#endif
Expand All @@ -204,7 +201,7 @@ due to conflicts with other common macros. */
#ifdef EXPERIMENTAL_DSN_INFO
builtin_macro_create(US"_HAVE_DSN_INFO");
#endif
#ifdef EXPERIMENTAL_TLS_RESUME
#ifndef DISABLE_TLS_RESUME
builtin_macro_create(US"_HAVE_TLS_RESUME");
#endif

Expand All @@ -226,6 +223,10 @@ due to conflicts with other common macros. */
#ifdef LOOKUP_IBASE
builtin_macro_create(US"_HAVE_LOOKUP_IBASE");
#endif
#ifdef LOOKUP_LMDB
builtin_macro_create(US"_HAVE_LMDB");
builtin_macro_create(US"_HAVE_LOOKUP_LMDB");
#endif
#ifdef LOOKUP_LDAP
builtin_macro_create(US"_HAVE_LOOKUP_JSON");
#endif
Expand Down Expand Up @@ -278,11 +279,38 @@ due to conflicts with other common macros. */
# endif
#endif

features_acl();
features_crypto();

#ifdef WITH_CONTENT_SCAN
features_malware();
#endif
}

features_crypto();
static void
exp_features(void)
{
#ifdef EXPERIMENTAL_ARC
builtin_macro_create(US"_EXP_ARC");
#endif
#ifdef EXPERIMENTAL_BRIGHTMAIL
builtin_macro_create(US"_EXP_BMI");
#endif
#ifdef EXPERIMENTAL_DCC
builtin_macro_create(US"_EXP_DCC");
#endif
#ifdef EXPERIMENTAL_DSN_INFO
builtin_macro_create(US"_EXP_DSNI");
#endif
#ifdef EXPERIMENTAL_ESMTP_LIMITS
builtin_macro_create(US"_EXP_LIMITS");
#endif
#ifdef EXPERIMENTAL_QUEUEFILE
builtin_macro_create(US"_EXP_QUEUEFILE");
#endif
#if defined(EXPERIMENTAL_SRS_ALT)
builtin_macro_create(US"_EXP_SRS");
#endif
}


Expand Down Expand Up @@ -313,6 +341,7 @@ main(void)
{
printf("#include \"exim.h\"\n");
features();
exp_features();
options();
params();

Expand Down
1 change: 1 addition & 0 deletions src/src/macro_predef.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ extern void builtin_macro_create(const uschar *);
extern void builtin_macro_create_var(const uschar *, const uschar *);
extern void options_from_list(optionlist *, unsigned, const uschar *, uschar *);

extern void features_acl(void);
extern void features_malware(void);
extern void features_crypto(void);
extern void options_main(void);
Expand Down
105 changes: 57 additions & 48 deletions src/src/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ manipulate them. */


/* For almost all calls to convert things to printing characters, we want to
allow tabs. A macro just makes life a bit easier. */
allow tabs & spaces. A macro just makes life a bit easier. */

#define string_printing(s) string_printing2((s), TRUE)
#define string_printing(s) string_printing2((s), 0)
#define SP_TAB BIT(0)
#define SP_SPACE BIT(1)


/* We need a special return code for "no recipients and failed to send an error
Expand Down Expand Up @@ -148,10 +150,13 @@ enough to hold all the headers from a normal kind of message. */
/* The size of the circular buffer that remembers recent SMTP commands */

#define SMTP_HBUFF_SIZE 20
#define SMTP_HBUFF_PREV(n) ((n) ? (n)-1 : SMTP_HBUFF_SIZE-1)

/* The initial size of a big buffer for use in various places. It gets put
into big_buffer_size and in some circumstances increased. It should be at least
as long as the maximum path length. */
as long as the maximum path length PLUS room for string additions.
Let's go with "at least twice as large as maximum path length".
*/

#ifdef AUTH_HEIMDAL_GSSAPI
/* RFC 4121 section 5.2, SHOULD support 64K input buffers */
Expand All @@ -160,10 +165,12 @@ as long as the maximum path length. */
# define __BIG_BUFFER_SIZE 16384
#endif

#if defined PATH_MAX && PATH_MAX > __BIG_BUFFER_SIZE
# define BIG_BUFFER_SIZE PATH_MAX
#elif defined MAXPATHLEN && MAXPATHLEN > __BIG_BUFFER_SIZE
# define BIG_BUFFER_SIZE MAXPATHLEN
#ifndef PATH_MAX
/* exim.h will have ensured this exists before including us. */
# error headers confusion, PATH_MAX missing in macros.h
#endif
#if (PATH_MAX*2) > __BIG_BUFFER_SIZE
# define BIG_BUFFER_SIZE (PATH_MAX*2)
#else
# define BIG_BUFFER_SIZE __BIG_BUFFER_SIZE
#endif
Expand All @@ -177,29 +184,16 @@ written on the spool, it gets read into big_buffer. */

#define LOCAL_SCAN_MAX_RETURN (BIG_BUFFER_SIZE - 24)

/* A limit to the length of an address. RFC 2821 limits the local part to 64
and the domain to 255, so this should be adequate, taking into account quotings
etc. */

#define ADDRESS_MAXLENGTH 512

/* The length of the base names of spool files, which consist of an internal
message id with a trailing "-H" or "-D" added. */

#define SPOOL_NAME_LENGTH (MESSAGE_ID_LENGTH+2)

/* The maximum number of message ids to store in a waiting database
record. */
record, and the max number of continuation records allowed. */

#define WAIT_NAME_MAX 50

/* Wait this long before determining that a Proxy Protocol configured
host isn't speaking the protocol, and so is disallowed. Can be moved to
runtime configuration if per site settings become needed. */
#ifdef SUPPORT_PROXY
#define PROXY_NEGOTIATION_TIMEOUT_SEC 3
#define PROXY_NEGOTIATION_TIMEOUT_USEC 0
#endif
#define WAIT_CONT_MAX 1000

/* Fixed option values for all PCRE functions */

Expand Down Expand Up @@ -302,6 +296,7 @@ Use rc_names[] for debug strings. */
#define CANCELLED 13 /* Authentication cancelled */
#define FAIL_SEND 14 /* send() failed in authenticator */
#define FAIL_DROP 15 /* Fail and drop connection (used in ACL) */
#define DANE 16 /* Deferred for domain mismatch (used in transport) */

/* Returns from the deliver_message() function */

Expand All @@ -310,7 +305,7 @@ Use rc_names[] for debug strings. */
#define DELIVER_MUA_FAILED 2 /* Failure when mua_wrapper is set */
#define DELIVER_NOT_ATTEMPTED 3 /* Not tried (no msg or is locked */

/* Returns from DNS lookup functions. */
/* Returns from DNS lookup functions. Use dns_rc_names[] for debug strings */

enum { DNS_SUCCEED, DNS_NOMATCH, DNS_NODATA, DNS_AGAIN, DNS_FAIL };

Expand Down Expand Up @@ -480,8 +475,10 @@ enum logbit {
Li_outgoing_port,
Li_pid,
Li_pipelining,
Li_protocol_detail,
Li_proxy,
Li_queue_time,
Li_queue_time_exclusive,
Li_queue_time_overall,
Li_receive_time,
Li_received_sender,
Expand All @@ -494,6 +491,9 @@ enum logbit {
Li_smtp_mailauth,
Li_smtp_no_mail,
Li_subject,
#ifdef ALLOW_INSECURE_TAINTED_DATA
Li_tainted,
#endif
Li_tls_certificate_verified,
Li_tls_cipher,
Li_tls_peerdn,
Expand Down Expand Up @@ -560,19 +560,20 @@ table exim_errstrings[] in log.c */
#define ERRNO_AUTHPROB (-48) /* Authenticator "other" failure */
#define ERRNO_UTF8_FWD (-49) /* target not supporting SMTPUTF8 */
#define ERRNO_HOST_IS_LOCAL (-50) /* Transport refuses to talk to localhost */
#define ERRNO_TAINT (-51) /* Transport refuses to talk use tainted filename */

/* These must be last, so all retry deferments can easily be identified */

#define ERRNO_RETRY_BASE (-51) /* Base to test against */
#define ERRNO_RRETRY (-51) /* Not time for routing */
#define ERRNO_RETRY_BASE (-52) /* Base to test against */
#define ERRNO_RRETRY (-52) /* Not time for routing */

#define ERRNO_WARN_BASE (-52) /* Base to test against */
#define ERRNO_LRETRY (-52) /* Not time for local delivery */
#define ERRNO_HRETRY (-53) /* Not time for any remote host */
#define ERRNO_LOCAL_ONLY (-54) /* Local-only delivery */
#define ERRNO_QUEUE_DOMAIN (-55) /* Domain in queue_domains */
#define ERRNO_TRETRY (-56) /* Transport concurrency limit */
#define ERRNO_EVENT (-57) /* Event processing request alternate response */
#define ERRNO_WARN_BASE (-53) /* Base to test against */
#define ERRNO_LRETRY (-53) /* Not time for local delivery */
#define ERRNO_HRETRY (-54) /* Not time for any remote host */
#define ERRNO_LOCAL_ONLY (-55) /* Local-only delivery */
#define ERRNO_QUEUE_DOMAIN (-56) /* Domain in queue_domains */
#define ERRNO_TRETRY (-57) /* Transport concurrency limit */
#define ERRNO_EVENT (-58) /* Event processing request alternate response */



Expand Down Expand Up @@ -736,6 +737,7 @@ enum { v_none, v_sender, v_recipient, v_expn };
#define vopt_callout_recippmaster 0x0100 /* use postmaster to verify recip */
#define vopt_callout_hold 0x0200 /* lazy close connection */
#define vopt_success_on_redirect 0x0400
#define vopt_quota 0x0800 /* quota check, to local/appendfile */

/* Values for fields in callout cache records */

Expand Down Expand Up @@ -866,22 +868,23 @@ enum {

/* Options for transport_write_message */

#define topt_add_return_path 0x001
#define topt_add_delivery_date 0x002
#define topt_add_envelope_to 0x004
#define topt_use_crlf 0x008 /* Terminate lines with CRLF */
#define topt_end_dot 0x010 /* Send terminating dot line */
#define topt_no_headers 0x020 /* Omit headers */
#define topt_no_body 0x040 /* Omit body */
#define topt_escape_headers 0x080 /* Apply escape check to headers */
#define topt_use_bdat 0x100 /* prepend chunks with RFC3030 BDAT header */
#define topt_output_string 0x200 /* create string rather than write to fd */
#define topt_continuation 0x400 /* do not reset buffer */
#define topt_not_socket 0x800 /* cannot do socket-only syscalls */
#define topt_add_return_path 0x0001
#define topt_add_delivery_date 0x0002
#define topt_add_envelope_to 0x0004
#define topt_escape_headers 0x0008 /* Apply escape check to headers */
#define topt_use_crlf 0x0010 /* Terminate lines with CRLF */
#define topt_no_headers 0x0020 /* Omit headers */
#define topt_no_body 0x0040 /* Omit body */
#define topt_end_dot 0x0080 /* Send terminating dot line */
#define topt_no_flush 0x0100 /* more data expected after message (eg QUIT) */
#define topt_use_bdat 0x0200 /* prepend chunks with RFC3030 BDAT header */
#define topt_output_string 0x0400 /* create string rather than write to fd */
#define topt_continuation 0x0800 /* do not reset buffer */
#define topt_not_socket 0x1000 /* cannot do socket-only syscalls */

/* Options for smtp_write_command */

enum {
enum {
SCMD_FLUSH = 0, /* write to kernel */
SCMD_MORE, /* write to kernel, but likely more soon */
SCMD_BUFFER /* stash in application cmd output buffer */
Expand Down Expand Up @@ -973,7 +976,9 @@ enum { ACL_WHERE_RCPT, /* Some controls are for RCPT only */
#define ACL_BIT_MIME BIT(ACL_WHERE_MIME)
#define ACL_BIT_DKIM BIT(ACL_WHERE_DKIM)
#define ACL_BIT_DATA BIT(ACL_WHERE_DATA)
#ifndef DISABLE_PRDR
#ifdef DISABLE_PRDR
# define ACL_BIT_PRDR 0
#else
# define ACL_BIT_PRDR BIT(ACL_WHERE_PRDR)
#endif
#define ACL_BIT_NOTSMTP BIT(ACL_WHERE_NOTSMTP)
Expand All @@ -991,6 +996,10 @@ enum { ACL_WHERE_RCPT, /* Some controls are for RCPT only */
#define ACL_BIT_DELIVERY BIT(ACL_WHERE_DELIVERY)
#define ACL_BIT_UNKNOWN BIT(ACL_WHERE_UNKNOWN)

#define ACL_BITS_HAVEDATA (ACL_BIT_MIME | ACL_BIT_DKIM | ACL_BIT_DATA \
| ACL_BIT_PRDR \
| ACL_BIT_NOTSMTP | ACL_BIT_QUIT | ACL_BIT_NOTQUIT)


/* Situations for spool_write_header() */

Expand Down Expand Up @@ -1067,8 +1076,8 @@ should not be one active. */

#define AUTHS_REGEX US"\\n250[\\s\\-]AUTH\\s+([\\-\\w \\t]+)(?:\\n|$)"

#define EARLY_PIPE_FEATURE_NAME "X_PIPE_CONNECT"
#define EARLY_PIPE_FEATURE_LEN 14
#define EARLY_PIPE_FEATURE_NAME "PIPE_CONNECT"
#define EARLY_PIPE_FEATURE_LEN 12


/* Flags for auth_client_item() */
Expand Down
154 changes: 91 additions & 63 deletions src/src/malware.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ features_malware(void)
{
const uschar * s;
uschar * t;
uschar buf[64];
uschar buf[EXIM_DRIVERNAME_MAX];

spf(buf, sizeof(buf), US"_HAVE_MALWARE_");

Expand All @@ -132,7 +132,6 @@ static const uschar * malware_regex_default = US ".+";
static const pcre * malware_default_re = NULL;



#ifndef DISABLE_MAL_CLAM
/* The maximum number of clamd servers that are supported in the configuration */
# define MAX_CLAMD_SERVERS 32
Expand Down Expand Up @@ -220,6 +219,7 @@ extern uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
/* Some (currently avast only) use backslash escaped whitespace,
this function undoes these escapes */

#ifndef DISABLE_MAL_AVAST
static inline void
unescape(uschar *p)
{
Expand All @@ -228,6 +228,7 @@ for (; *p; ++p)
if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
for (p0 = p; *p0; ++p0) *p0 = p0[1];
}
#endif

/* --- malware_*_defer --- */
static inline int
Expand All @@ -250,13 +251,6 @@ m_panic_defer(struct scan * scanent, const uschar * hostport,
return malware_panic_defer(string_sprintf("%s %s : %s",
scanent->name, hostport ? hostport : CUS"", str));
}
static inline int
m_log_defer(struct scan * scanent, const uschar * hostport,
const uschar * str)
{
return malware_log_defer(string_sprintf("%s %s : %s",
scanent->name, hostport ? hostport : CUS"", str));
}
/* --- m_*_defer_3 */
static inline int
m_panic_defer_3(struct scan * scanent, const uschar * hostport,
Expand All @@ -277,8 +271,19 @@ static inline int
m_tcpsocket(const uschar * hostname, unsigned int port,
host_item * host, uschar ** errstr, const blob * fastopen_blob)
{
return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
host, errstr, fastopen_blob);
#ifdef EXIM_TFO_FREEBSD
/* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
and, getting no response, wait for a long time. Impose a 5s max. */
if (fd >= 0)
{
struct timeval tv = {.tv_sec = 5};
fd_set fds;
FD_ZERO(&fds); FD_SET(fd, &fds); (void) select(fd+1, NULL, &fds, NULL, &tv);
}
#endif
return fd;
}
#endif

Expand Down Expand Up @@ -386,13 +391,15 @@ return p - buffer;
}

/* return TRUE iff size as requested */
#ifndef DISABLE_MAL_DRWEB
static BOOL
recv_len(int sock, void * buf, int size, time_t tmo)
{
return fd_ready(sock, tmo)
? recv(sock, buf, size, 0) == size
: FALSE;
}
#endif



Expand Down Expand Up @@ -1446,9 +1453,7 @@ badseek: err = errno;
uschar av_buffer[1024];
uschar *hostname = US"";
host_item connhost;
uschar *clamav_fbuf;
int clam_fd, result;
off_t fsize;
unsigned int fsize_uint;
BOOL use_scan_command = FALSE;
clamd_address * cv[MAX_CLAMD_SERVERS];
Expand Down Expand Up @@ -1555,16 +1560,17 @@ badseek: err = errno;
{ cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
else
{
cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
cmd_str.len = Ustrlen(cmd_str.data);
int n;
cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &n);
cmd_str.len = n; /* .len is a size_t */
}

/* We have some network servers specified */
if (num_servers)
{
/* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
* only supports AF_INET, but we should probably be looking to the
* future and rewriting this to be protocol-independent anyway. */
only supports AF_INET, but we should probably be looking to the
future and rewriting this to be protocol-independent anyway. */

while (num_servers > 0)
{
Expand All @@ -1575,16 +1581,17 @@ badseek: err = errno;
cd->hostspec, cd->tcp_port);

/* Lookup the host. This is to ensure that we connect to the same IP
* on both connections (as one host could resolve to multiple ips) */
on both connections (as one host could resolve to multiple ips) */
for (;;)
{
/*XXX we trust that the cmd_str is ideempotent */
/*XXX we trust that the cmd_str is idempotent */
if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
&connhost, &errstr, &cmd_str)) >= 0)
&connhost, &errstr,
use_scan_command ? &cmd_str : NULL)) >= 0)
{
/* Connection successfully established with a server */
hostname = cd->hostspec;
cmd_str.len = 0;
if (use_scan_command) cmd_str.len = 0;
break;
}
if (cd->retry <= 0) break;
Expand Down Expand Up @@ -1618,20 +1625,28 @@ badseek: err = errno;
}

/* have socket in variable "sock"; command to use is semi-independent of
* the socket protocol. We use SCAN if is local (either Unix/local
* domain socket, or explicitly told local) else we stream the data.
* How we stream the data depends upon how we were built. */
the socket protocol. We use SCAN if is local (either Unix/local
domain socket, or explicitly told local) else we stream the data.
How we stream the data depends upon how we were built. */

if (!use_scan_command)
{
struct stat st;
#if defined(EXIM_TCP_CORK) && !defined(OS_SENDFILE)
BOOL corked = TRUE;
#endif
/* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
chunks, <n> a 4-byte number (network order), terminated by a zero-length
chunk. */
chunk. We only send one chunk. */

DEBUG(D_acl) debug_printf_indent(
"Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
scanner_name);

#if defined(EXIM_TCP_CORK)
(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
US &on, sizeof(on));
#endif
/* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
if (cmd_str.len)
if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
Expand All @@ -1640,7 +1655,6 @@ badseek: err = errno;
strerror(errno)),
malware_daemon_ctx.sock);

/* calc file size */
if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
{
int err = errno;
Expand All @@ -1649,66 +1663,79 @@ badseek: err = errno;
eml_filename, strerror(err)),
malware_daemon_ctx.sock);
}
if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
if (fstat(clam_fd, &st) < 0)
{
int err;
b_seek: err = errno;
int err = errno;
(void)close(clam_fd);
return m_panic_defer_3(scanent, NULL,
string_sprintf("can't seek spool file %s: %s",
string_sprintf("can't stat spool file %s: %s",
eml_filename, strerror(err)),
malware_daemon_ctx.sock);
}
fsize_uint = (unsigned int) fsize;
if ((off_t)fsize_uint != fsize)
fsize_uint = (unsigned int) st.st_size;
if ((off_t)fsize_uint != st.st_size)
{
(void)close(clam_fd);
return m_panic_defer_3(scanent, NULL,
string_sprintf("seeking spool file %s, size overflow",
eml_filename),
string_sprintf("stat spool file %s, size overflow", eml_filename),
malware_daemon_ctx.sock);
}
if (lseek(clam_fd, 0, SEEK_SET) < 0)
goto b_seek;

if (!(clamav_fbuf = store_malloc(fsize_uint)))
{
(void)close(clam_fd);
/* send file size */
send_size = htonl(fsize_uint);
if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
return m_panic_defer_3(scanent, NULL,
string_sprintf("unable to allocate memory %u for file (%s)",
fsize_uint, eml_filename),
string_sprintf("unable to send file size to socket (%s)", hostname),
malware_daemon_ctx.sock);
}

if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
/* send file body */
while (fsize_uint)
{
int err = errno;
store_free(clamav_fbuf); (void)close(clam_fd);
return m_panic_defer_3(scanent, NULL,
string_sprintf("can't read spool file %s: %s",
eml_filename, strerror(err)),
malware_daemon_ctx.sock);
#ifdef OS_SENDFILE
int n = os_sendfile(malware_daemon_ctx.sock, clam_fd, NULL, (size_t)fsize_uint);
if (n < 0)
return m_panic_defer_3(scanent, NULL,
string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
malware_daemon_ctx.sock);
fsize_uint -= n;
#else
int n = MIN(fsize_uint, big_buffer_size);
if ((n = read(clam_fd, big_buffer, n)) < 0)
return m_panic_defer_3(scanent, NULL,
string_sprintf("can't read spool file %s: %s",
eml_filename, strerror(errno)),
malware_daemon_ctx.sock);
if (send(malware_daemon_ctx.sock, big_buffer, (size_t)n, 0) < 0)
return m_panic_defer_3(scanent, NULL,
string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
malware_daemon_ctx.sock);
fsize_uint -= n;
# ifdef EXIM_TCP_CORK
if (corked)
{
corked = FALSE;
(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
US &off, sizeof(off));
}
# endif
#endif /*!OS_SENDFILE*/

}
(void)close(clam_fd);

/* send file body to socket */
send_size = htonl(fsize_uint);
send_final_zeroblock = 0;
if ((send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0) ||
(send(malware_daemon_ctx.sock, clamav_fbuf, fsize_uint, 0) < 0) ||
(send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
{
store_free(clamav_fbuf);
if (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)
return m_panic_defer_3(scanent, NULL,
string_sprintf("unable to send file body to socket (%s)", hostname),
string_sprintf("unable to send file terminator to socket (%s)", hostname),
malware_daemon_ctx.sock);
}
store_free(clamav_fbuf);
#ifdef OS_SENDFILE
(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
US &off, sizeof(off));
#endif
}
else
{ /* use scan command */
/* Send a SCAN command pointing to a filename; then in the then in the
* scan-method-neutral part, read the response back */
scan-method-neutral part, read the response back */

/* ================================================================= */

Expand All @@ -1733,10 +1760,10 @@ b_seek: err = errno;
malware_daemon_ctx.sock);

/* Do not shut down the socket for writing; a user report noted that
* clamd 0.70 does not react well to this. */
clamd 0.70 does not react well to this. */
}
/* Commands have been sent, no matter which scan method or connection
* type we're using; now just read the result, independent of method. */
type we're using; now just read the result, independent of method. */

/* Read the result */
memset(av_buffer, 0, sizeof(av_buffer));
Expand Down Expand Up @@ -1782,6 +1809,7 @@ b_seek: err = errno;
/* strip newline at the end (won't be present for zINSTREAM)
(also any trailing whitespace, which shouldn't exist, but we depend upon
this below, so double-check) */

p = av_buffer + Ustrlen(av_buffer) - 1;
if (*p == '\n') *p = '\0';

Expand All @@ -1792,7 +1820,7 @@ b_seek: err = errno;
if (*p) ++p;

/* colon in returned output? */
if(!(p = Ustrchr(av_buffer,':')))
if (!(p = Ustrchr(av_buffer,':')))
return m_panic_defer(scanent, CUS callout_address, string_sprintf(
"ClamAV returned malformed result (missing colon): %s",
av_buffer));
Expand Down
Loading