Corrections for inverted bcond import exim-4_86_2+fixes branch + fix CVE-2016-1531 when installed setuid root, allows local users to gain privileges via the perl_startup argument. + fix Bug 1805: store the initial working directory, expand $initial_cwd + fix Bug 1671: segfault after delivery (https://bugs.exim.org/show_bug.cgi?id=1671) + Don't issue env warning if env is empty - fix CVE-2016-9963: DKIM information leakage - conditionally disable DANE on SuSE versions with OpenSSL < 1.0 - disable i18n by default, utf8_downconvert seems to cause crashes OBS-URL: https://build.opensuse.org/request/show/490905 OBS-URL: https://build.opensuse.org/package/show/server:mail/exim?expand=0&rev=183
1426 lines
49 KiB
Diff
1426 lines
49 KiB
Diff
diff -ru a/daemon.c b/daemon.c
|
|
--- a/src/daemon.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/daemon.c 2017-04-24 09:33:17.356999655 +0200
|
|
@@ -735,6 +735,7 @@
|
|
/* Release any store used in this process, including the store used for holding
|
|
the incoming host address and an expanded active_hostname. */
|
|
|
|
+log_close_all();
|
|
store_reset(reset_point);
|
|
sender_host_address = NULL;
|
|
}
|
|
diff -ru a/deliver.c b/deliver.c
|
|
--- a/src/deliver.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/deliver.c 2017-04-24 09:33:17.356999655 +0200
|
|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
#include "exim.h"
|
|
+#include <assert.h>
|
|
|
|
|
|
/* Data block for keeping track of subprocesses for parallel remote
|
|
@@ -7904,17 +7905,36 @@
|
|
uschar *
|
|
deliver_get_sender_address (uschar * id)
|
|
{
|
|
+int rc;
|
|
+uschar * new_sender_address,
|
|
+ * save_sender_address;
|
|
+
|
|
if (!spool_open_datafile(id))
|
|
return NULL;
|
|
|
|
+/* Save and restore the global sender_address. I'm not sure if we should
|
|
+not save/restore all the other global variables too, because
|
|
+spool_read_header() may change all of them. But OTOH, when this
|
|
+deliver_get_sender_address() gets called, the current message is done
|
|
+already and nobody needs the globals anymore. (HS12, 2015-08-21) */
|
|
+
|
|
sprintf(CS spoolname, "%s-H", id);
|
|
-if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
|
|
+save_sender_address = sender_address;
|
|
+
|
|
+rc = spool_read_header(spoolname, TRUE, TRUE);
|
|
+
|
|
+new_sender_address = sender_address;
|
|
+sender_address = save_sender_address;
|
|
+
|
|
+if (rc != spool_read_OK)
|
|
return NULL;
|
|
|
|
+assert(new_sender_address);
|
|
+
|
|
(void)close(deliver_datafile);
|
|
deliver_datafile = -1;
|
|
|
|
-return sender_address;
|
|
+return new_sender_address;
|
|
}
|
|
|
|
/* vi: aw ai sw=2
|
|
diff -ru a/dns.c b/dns.c
|
|
--- a/src/dns.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/dns.c 2017-04-24 09:33:17.356999655 +0200
|
|
@@ -390,7 +390,8 @@
|
|
|
|
dnss->aptr += namelen;
|
|
GETSHORT(dnss->srr.type, dnss->aptr); /* Record type */
|
|
-dnss->aptr += 6; /* Don't want class or TTL */
|
|
+dnss->aptr += 2; /* Don't want class */
|
|
+GETLONG(dnss->srr.ttl, dnss->aptr); /* TTL */
|
|
GETSHORT(dnss->srr.size, dnss->aptr); /* Size of data portion */
|
|
dnss->srr.data = dnss->aptr; /* The record's data follows */
|
|
dnss->aptr += dnss->srr.size; /* Advance to next RR */
|
|
diff -ru a/exim.c b/exim.c
|
|
--- a/src/exim.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/exim.c 2017-04-24 09:33:17.360999706 +0200
|
|
@@ -3730,6 +3730,13 @@
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
+/* Store the initial cwd before we change directories */
|
|
+if ((initial_cwd = getcwd(NULL, 0)) == NULL)
|
|
+ {
|
|
+ perror("exim: can't get the current working directory");
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
readconf_main();
|
|
|
|
if (cleanup_environment() == FALSE)
|
|
@@ -4017,9 +4024,10 @@
|
|
{
|
|
int i;
|
|
uschar *p = big_buffer;
|
|
- char * dummy;
|
|
Ustrcpy(p, "cwd= (failed)");
|
|
- dummy = /* quieten compiler */ getcwd(CS p+4, big_buffer_size - 4);
|
|
+
|
|
+ Ustrncpy(p + 4, initial_cwd, big_buffer_size-5);
|
|
+
|
|
while (*p) p++;
|
|
(void)string_format(p, big_buffer_size - (p - big_buffer), " %d args:", argc);
|
|
while (*p) p++;
|
|
diff -ru a/expand.c b/expand.c
|
|
--- a/src/expand.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/expand.c 2017-04-24 09:33:17.360999706 +0200
|
|
@@ -533,6 +533,7 @@
|
|
{ "host_lookup_deferred",vtype_int, &host_lookup_deferred },
|
|
{ "host_lookup_failed", vtype_int, &host_lookup_failed },
|
|
{ "host_port", vtype_int, &deliver_host_port },
|
|
+ { "initial_cwd", vtype_stringptr, &initial_cwd },
|
|
{ "inode", vtype_ino, &deliver_inode },
|
|
{ "interface_address", vtype_stringptr, &interface_address },
|
|
{ "interface_port", vtype_int, &interface_port },
|
|
diff -ru a/functions.h b/functions.h
|
|
--- a/src/functions.h 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/functions.h 2017-04-24 09:33:17.360999706 +0200
|
|
@@ -375,7 +375,7 @@
|
|
extern int smtp_feof(void);
|
|
extern int smtp_ferror(void);
|
|
extern uschar *smtp_get_connection_info(void);
|
|
-extern BOOL smtp_get_interface(uschar *, int, address_item *, BOOL *,
|
|
+extern BOOL smtp_get_interface(uschar *, int, address_item *,
|
|
uschar **, uschar *);
|
|
extern BOOL smtp_get_port(uschar *, address_item *, int *, uschar *);
|
|
extern int smtp_getc(void);
|
|
diff -ru a/globals.c b/globals.c
|
|
--- a/src/globals.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/globals.c 2017-04-24 09:33:17.360999706 +0200
|
|
@@ -783,6 +783,7 @@
|
|
uschar *ignore_fromline_hosts = NULL;
|
|
BOOL inetd_wait_mode = FALSE;
|
|
int inetd_wait_timeout = -1;
|
|
+uschar *initial_cwd = NULL;
|
|
uschar *interface_address = NULL;
|
|
int interface_port = -1;
|
|
BOOL is_inetd = FALSE;
|
|
diff -ru a/globals.h b/globals.h
|
|
--- a/src/globals.h 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/globals.h 2017-04-24 09:33:17.360999706 +0200
|
|
@@ -508,6 +508,7 @@
|
|
extern uschar *ignore_fromline_hosts; /* Hosts permitted to send "From " */
|
|
extern BOOL inetd_wait_mode; /* Whether running in inetd wait mode */
|
|
extern int inetd_wait_timeout; /* Timeout for inetd wait mode */
|
|
+extern uschar *initial_cwd; /* The directory we where in at startup */
|
|
extern BOOL is_inetd; /* True for inetd calls */
|
|
extern uschar *iterate_item; /* Item from iterate list */
|
|
|
|
diff -ru a/lookupapi.h b/lookupapi.h
|
|
--- a/src/lookupapi.h 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookupapi.h 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -34,7 +34,7 @@
|
|
int, /* length of key or query */
|
|
uschar **, /* for returning answer */
|
|
uschar **, /* for error message */
|
|
- BOOL *); /* to request cache cleanup */
|
|
+ uint *); /* cache TTL, sconds */
|
|
void (*close)( /* close function */
|
|
void *); /* handle */
|
|
void (*tidy)(void); /* tidy function */
|
|
@@ -46,9 +46,10 @@
|
|
} lookup_info;
|
|
|
|
/* This magic number is used by the following lookup_module_info structure
|
|
- for checking API compatibility. It's equivalent to the string"LMM2" */
|
|
-#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4d32
|
|
+ for checking API compatibility. It used to be equivalent to the string"LMM3" */
|
|
+#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4933
|
|
/* Version 2 adds: version_report */
|
|
+/* Version 3 change: non/cache becomes TTL in seconds */
|
|
|
|
typedef struct lookup_module_info {
|
|
uint magic;
|
|
diff -ru a/lookups/cdb.c b/lookups/cdb.c
|
|
--- a/src/lookups/cdb.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/cdb.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -279,7 +279,7 @@
|
|
int key_len,
|
|
uschar **result,
|
|
uschar **errmsg,
|
|
- BOOL *do_cache)
|
|
+ uint *do_cache)
|
|
{
|
|
struct cdb_state * cdbp = handle;
|
|
uint32 item_key_len,
|
|
diff -ru a/lookups/dbmdb.c b/lookups/dbmdb.c
|
|
--- a/src/lookups/dbmdb.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/dbmdb.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -87,7 +87,7 @@
|
|
|
|
static int
|
|
dbmdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
EXIM_DB *d = (EXIM_DB *)handle;
|
|
EXIM_DATUM key, data;
|
|
@@ -120,7 +120,7 @@
|
|
|
|
int
|
|
static dbmnz_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
|
|
do_cache);
|
|
@@ -140,7 +140,7 @@
|
|
|
|
static int
|
|
dbmjz_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
uschar *key_item, *key_buffer, *key_p;
|
|
const uschar *key_elems = keystring;
|
|
diff -ru a/lookups/dnsdb.c b/lookups/dnsdb.c
|
|
--- a/src/lookups/dnsdb.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/dnsdb.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -131,7 +131,7 @@
|
|
|
|
static int
|
|
dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int rc;
|
|
int size = 256;
|
|
@@ -388,6 +388,9 @@
|
|
{
|
|
if (rr->type != searchtype) continue;
|
|
|
|
+ if (*do_cache > rr->ttl)
|
|
+ *do_cache = rr->ttl;
|
|
+
|
|
if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
|
|
{
|
|
dns_address *da;
|
|
diff -ru a/lookups/dsearch.c b/lookups/dsearch.c
|
|
--- a/src/lookups/dsearch.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/dsearch.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -67,7 +67,7 @@
|
|
|
|
int
|
|
static dsearch_find(void *handle, uschar *dirname, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
struct stat statbuf;
|
|
int save_errno;
|
|
diff -ru a/lookups/ibase.c b/lookups/ibase.c
|
|
--- a/src/lookups/ibase.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/ibase.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -451,7 +451,7 @@
|
|
|
|
static int
|
|
ibase_find(void *handle, uschar * filename, uschar * query, int length,
|
|
- uschar ** result, uschar ** errmsg, BOOL *do_cache)
|
|
+ uschar ** result, uschar ** errmsg, uint *do_cache)
|
|
{
|
|
int sep = 0;
|
|
uschar *server;
|
|
diff -ru a/lookups/ldap.c b/lookups/ldap.c
|
|
--- a/src/lookups/ldap.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/ldap.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -156,7 +156,7 @@
|
|
uschar *error2 = NULL; /* error message from the server */
|
|
uschar *matched = NULL; /* partially matched DN */
|
|
|
|
-int attr_count = 0;
|
|
+int attrs_requested = 0;
|
|
int error_yield = DEFER;
|
|
int msgid;
|
|
int rc, ldap_rc, ldap_parse_rc;
|
|
@@ -248,7 +248,7 @@
|
|
/* Count the attributes; we need this later to tell us how to format results */
|
|
|
|
for (attrp = USS ludp->lud_attrs; attrp != NULL && *attrp != NULL; attrp++)
|
|
- attr_count++;
|
|
+ attrs_requested++;
|
|
|
|
/* See if we can find a cached connection to this host. The port is not
|
|
relevant for ldapi. The host name pointer is set to NULL if no host was given
|
|
@@ -713,10 +713,15 @@
|
|
LDAP_RES_SEARCH_ENTRY)
|
|
{
|
|
LDAPMessage *e;
|
|
+ int valuecount; /* We can see an attr spread across several
|
|
+ entries. If B is derived from A and we request
|
|
+ A and the directory contains both, A and B,
|
|
+ then we get two entries, one for A and one for B.
|
|
+ Here we just count the values per entry */
|
|
|
|
DEBUG(D_lookup) debug_printf("ldap_result loop\n");
|
|
|
|
- for(e = ldap_first_entry(lcp->ld, result);
|
|
+ for(e = ldap_first_entry(lcp->ld, result), valuecount = 0;
|
|
e != NULL;
|
|
e = ldap_next_entry(lcp->ld, e))
|
|
{
|
|
@@ -774,6 +779,11 @@
|
|
attr != NULL;
|
|
attr = US ldap_next_attribute(lcp->ld, e, ber))
|
|
{
|
|
+
|
|
+ /* In case of attrs_requested == 1 we just count the values, in all other cases
|
|
+ (0, >1) we count the values per attribute */
|
|
+ if (attrs_requested != 1) valuecount = 0;
|
|
+
|
|
if (attr[0] != 0)
|
|
{
|
|
/* Get array of values for this attribute. */
|
|
@@ -781,7 +791,8 @@
|
|
if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr))
|
|
!= NULL)
|
|
{
|
|
- if (attr_count != 1)
|
|
+
|
|
+ if (attrs_requested != 1)
|
|
{
|
|
if (insert_space)
|
|
data = string_cat(data, &size, &ptr, US" ", 1);
|
|
@@ -795,6 +806,7 @@
|
|
{
|
|
uschar *value = *values;
|
|
int len = Ustrlen(value);
|
|
+ ++valuecount;
|
|
|
|
DEBUG(D_lookup) debug_printf("LDAP attr loop %s:%s\n", attr, value);
|
|
|
|
@@ -804,13 +816,13 @@
|
|
* attributeTypes B and C from A and then query for A.)
|
|
* In all other cases we detect the different attribute
|
|
* and append only every non first value. */
|
|
- if ((attr_count == 1 && data) || (values != firstval))
|
|
+ if (data && valuecount > 1)
|
|
data = string_cat(data, &size, &ptr, US",", 1);
|
|
|
|
/* For multiple attributes, the data is in quotes. We must escape
|
|
internal quotes, backslashes, newlines, and must double commas. */
|
|
|
|
- if (attr_count != 1)
|
|
+ if (attrs_requested != 1)
|
|
{
|
|
int j;
|
|
for (j = 0; j < len; j++)
|
|
@@ -851,7 +863,7 @@
|
|
|
|
/* Closing quote at the end of the data for a named attribute. */
|
|
|
|
- if (attr_count != 1)
|
|
+ if (attrs_requested != 1)
|
|
data = string_cat(data, &size, &ptr, US"\"", 1);
|
|
|
|
/* Free the values */
|
|
@@ -1339,7 +1351,7 @@
|
|
|
|
static int
|
|
eldap_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
/* Keep picky compilers happy */
|
|
do_cache = do_cache;
|
|
@@ -1348,7 +1360,7 @@
|
|
|
|
static int
|
|
eldapm_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
/* Keep picky compilers happy */
|
|
do_cache = do_cache;
|
|
@@ -1357,7 +1369,7 @@
|
|
|
|
static int
|
|
eldapdn_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
/* Keep picky compilers happy */
|
|
do_cache = do_cache;
|
|
@@ -1366,7 +1378,7 @@
|
|
|
|
int
|
|
eldapauth_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
/* Keep picky compilers happy */
|
|
do_cache = do_cache;
|
|
diff -ru a/lookups/lf_functions.h b/lookups/lf_functions.h
|
|
--- a/src/lookups/lf_functions.h 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/lf_functions.h 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -12,7 +12,7 @@
|
|
extern uschar *lf_quote(uschar *, uschar *, int, uschar *, int *, int *);
|
|
extern int lf_sqlperform(const uschar *, const uschar *, const uschar *,
|
|
const uschar *, uschar **,
|
|
- uschar **, BOOL *, int(*)(const uschar *, uschar *, uschar **,
|
|
- uschar **, BOOL *, BOOL *));
|
|
+ uschar **, uint *, int(*)(const uschar *, uschar *, uschar **,
|
|
+ uschar **, BOOL *, uint *));
|
|
|
|
/* End of lf_functions.h */
|
|
diff -ru a/lookups/lf_sqlperform.c b/lookups/lf_sqlperform.c
|
|
--- a/src/lookups/lf_sqlperform.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/lf_sqlperform.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -27,7 +27,7 @@
|
|
query the query
|
|
result where to pass back the result
|
|
errmsg where to pass back an error message
|
|
- do_cache to be set FALSE if data is changed
|
|
+ do_cache to be set zero if data is changed
|
|
func the lookup function to call
|
|
|
|
Returns: the return from the lookup function, or DEFER
|
|
@@ -36,8 +36,8 @@
|
|
int
|
|
lf_sqlperform(const uschar *name, const uschar *optionname,
|
|
const uschar *optserverlist, const uschar *query,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache,
|
|
- int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, BOOL *))
|
|
+ uschar **result, uschar **errmsg, uint *do_cache,
|
|
+ int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *))
|
|
{
|
|
int sep, rc;
|
|
uschar *server;
|
|
diff -ru a/lookups/lsearch.c b/lookups/lsearch.c
|
|
--- a/src/lookups/lsearch.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/lsearch.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -323,7 +323,7 @@
|
|
|
|
static int
|
|
lsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
do_cache = do_cache; /* Keep picky compilers happy */
|
|
return internal_lsearch_find(handle, filename, keystring, length, result,
|
|
@@ -340,7 +340,7 @@
|
|
|
|
static int
|
|
wildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
do_cache = do_cache; /* Keep picky compilers happy */
|
|
return internal_lsearch_find(handle, filename, keystring, length, result,
|
|
@@ -357,7 +357,7 @@
|
|
|
|
static int
|
|
nwildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
do_cache = do_cache; /* Keep picky compilers happy */
|
|
return internal_lsearch_find(handle, filename, keystring, length, result,
|
|
@@ -375,7 +375,7 @@
|
|
|
|
static int
|
|
iplsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
do_cache = do_cache; /* Keep picky compilers happy */
|
|
if ((length == 1 && keystring[0] == '*') ||
|
|
diff -ru a/lookups/mysql.c b/lookups/mysql.c
|
|
--- a/src/lookups/mysql.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/mysql.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -74,7 +74,7 @@
|
|
resultptr where to store the result
|
|
errmsg where to point an error message
|
|
defer_break TRUE if no more servers are to be tried after DEFER
|
|
- do_cache set false if data is changed
|
|
+ do_cache set zero if data is changed
|
|
|
|
The server string is of the form "host/dbname/user/password". The host can be
|
|
host:port. This string is in a nextinlist temporary buffer, so can be
|
|
@@ -85,7 +85,7 @@
|
|
|
|
static int
|
|
perform_mysql_search(const uschar *query, uschar *server, uschar **resultptr,
|
|
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
|
|
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
|
|
{
|
|
MYSQL *mysql_handle = NULL; /* Keep compilers happy */
|
|
MYSQL_RES *mysql_result = NULL;
|
|
@@ -225,7 +225,7 @@
|
|
was expected (this is all explained clearly in the MySQL manual). In this case,
|
|
we return the number of rows affected by the command. In this event, we do NOT
|
|
want to cache the result; also the whole cache for the handle must be cleaned
|
|
-up. Setting do_cache FALSE requests this. */
|
|
+up. Setting do_cache zero requests this. */
|
|
|
|
if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
|
|
{
|
|
@@ -233,7 +233,7 @@
|
|
{
|
|
DEBUG(D_lookup) debug_printf("MYSQL: query was not one that returns data\n");
|
|
result = string_sprintf("%d", mysql_affected_rows(mysql_handle));
|
|
- *do_cache = FALSE;
|
|
+ *do_cache = 0;
|
|
goto MYSQL_EXIT;
|
|
}
|
|
*errmsg = string_sprintf("MYSQL: lookup result failed: %s\n",
|
|
@@ -341,7 +341,7 @@
|
|
|
|
static int
|
|
mysql_find(void *handle, uschar *filename, const uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
return lf_sqlperform(US"MySQL", US"mysql_servers", mysql_servers, query,
|
|
result, errmsg, do_cache, perform_mysql_search);
|
|
diff -ru a/lookups/nis.c b/lookups/nis.c
|
|
--- a/src/lookups/nis.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/nis.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -42,7 +42,7 @@
|
|
|
|
static int
|
|
nis_find(void *handle, uschar *filename, uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int rc;
|
|
uschar *nis_data;
|
|
@@ -68,7 +68,7 @@
|
|
|
|
static int
|
|
nis0_find(void *handle, uschar *filename, uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int rc;
|
|
uschar *nis_data;
|
|
diff -ru a/lookups/nisplus.c b/lookups/nisplus.c
|
|
--- a/src/lookups/nisplus.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/nisplus.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -43,7 +43,7 @@
|
|
|
|
static int
|
|
nisplus_find(void *handle, uschar *filename, uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int i;
|
|
int ssize = 0;
|
|
diff -ru a/lookups/oracle.c b/lookups/oracle.c
|
|
--- a/src/lookups/oracle.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/oracle.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -517,7 +517,7 @@
|
|
|
|
static int
|
|
oracle_find(void *handle, uschar *filename, uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int sep = 0;
|
|
uschar *server;
|
|
diff -ru a/lookups/passwd.c b/lookups/passwd.c
|
|
--- a/src/lookups/passwd.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/passwd.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -34,7 +34,7 @@
|
|
|
|
static int
|
|
passwd_find(void *handle, uschar *filename, const uschar *keystring, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
struct passwd *pw;
|
|
|
|
diff -ru a/lookups/pgsql.c b/lookups/pgsql.c
|
|
--- a/src/lookups/pgsql.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/pgsql.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -119,7 +119,7 @@
|
|
|
|
static int
|
|
perform_pgsql_search(const uschar *query, uschar *server, uschar **resultptr,
|
|
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
|
|
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
|
|
{
|
|
PGconn *pg_conn = NULL;
|
|
PGresult *pg_result = NULL;
|
|
@@ -290,10 +290,10 @@
|
|
/* The command was successful but did not return any data since it was
|
|
* not SELECT but either an INSERT, UPDATE or DELETE statement. Tell the
|
|
* high level code to not cache this query, and clean the current cache for
|
|
- * this handle by setting *do_cache FALSE. */
|
|
+ * this handle by setting *do_cache zero. */
|
|
result = string_copy(US PQcmdTuples(pg_result));
|
|
offset = Ustrlen(result);
|
|
- *do_cache = FALSE;
|
|
+ *do_cache = 0;
|
|
DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data "
|
|
"but was successful. Rows affected: %s\n", result);
|
|
|
|
@@ -399,7 +399,7 @@
|
|
|
|
static int
|
|
pgsql_find(void *handle, uschar *filename, const uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
return lf_sqlperform(US"PostgreSQL", US"pgsql_servers", pgsql_servers, query,
|
|
result, errmsg, do_cache, perform_pgsql_search);
|
|
diff -ru a/lookups/README b/lookups/README
|
|
--- a/src/lookups/README 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/README 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -122,12 +122,15 @@
|
|
uschar **errmsg where to put an error message on failure;
|
|
this is initially set to "", and should be left
|
|
as that for a standard "entry not found" error
|
|
- BOOL *do_cache the lookup should set this to FALSE when it changes data.
|
|
- This is TRUE by default. When set to FALSE the cache tree
|
|
+ uint *do_cache the lookup should set this to 0 when it changes data.
|
|
+ This is MAXINT by default. When set to 0 the cache tree
|
|
of the current search handle will be cleaned and the
|
|
current result will NOT be cached. Currently the mysql
|
|
and pgsql lookups use this when UPDATE/INSERT queries are
|
|
executed.
|
|
+ If set to a nonzero number of seconds, the cached value
|
|
+ becomes unusable after this time. Currently the dnsdb
|
|
+ lookup uses this to support the TTL value.
|
|
|
|
Even though the key is zero-terminated, the length is passed because in the
|
|
common case it has been computed already and is often needed.
|
|
diff -ru a/lookups/redis.c b/lookups/redis.c
|
|
--- a/src/lookups/redis.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/redis.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -65,7 +65,7 @@
|
|
*/
|
|
static int
|
|
perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
|
|
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
|
|
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
|
|
{
|
|
redisContext *redis_handle = NULL; /* Keep compilers happy */
|
|
redisReply *redis_reply = NULL;
|
|
@@ -197,7 +197,7 @@
|
|
case REDIS_REPLY_ERROR:
|
|
*errmsg = string_sprintf("REDIS: lookup result failed: %s\n", redis_reply->str);
|
|
*defer_break = FALSE;
|
|
- *do_cache = FALSE;
|
|
+ *do_cache = 0;
|
|
goto REDIS_EXIT;
|
|
/* NOTREACHED */
|
|
|
|
@@ -205,7 +205,7 @@
|
|
case REDIS_REPLY_NIL:
|
|
DEBUG(D_lookup) debug_printf("REDIS: query was not one that returned any data\n");
|
|
result = string_sprintf("");
|
|
- *do_cache = FALSE;
|
|
+ *do_cache = 0;
|
|
goto REDIS_EXIT;
|
|
/* NOTREACHED */
|
|
|
|
@@ -304,7 +304,7 @@
|
|
|
|
static int
|
|
redis_find(void *handle __attribute__((unused)), uschar *filename __attribute__((unused)),
|
|
- uschar *command, int length, uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar *command, int length, uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
return lf_sqlperform(US"Redis", US"redis_servers", redis_servers, command,
|
|
result, errmsg, do_cache, perform_redis_search);
|
|
diff -ru a/lookups/spf.c b/lookups/spf.c
|
|
--- a/src/lookups/spf.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/spf.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -31,7 +31,9 @@
|
|
#include <spf2/spf_dns_resolv.h>
|
|
#include <spf2/spf_dns_cache.h>
|
|
|
|
-static void *spf_open(uschar *filename, uschar **errmsg) {
|
|
+static void *
|
|
+spf_open(uschar *filename, uschar **errmsg)
|
|
+{
|
|
SPF_server_t *spf_server = NULL;
|
|
spf_server = SPF_server_new(SPF_DNS_CACHE, 0);
|
|
if (spf_server == NULL) {
|
|
@@ -41,13 +43,17 @@
|
|
return (void *) spf_server;
|
|
}
|
|
|
|
-static void spf_close(void *handle) {
|
|
+static void
|
|
+spf_close(void *handle)
|
|
+{
|
|
SPF_server_t *spf_server = handle;
|
|
if (spf_server) SPF_server_free(spf_server);
|
|
}
|
|
|
|
-static int spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache) {
|
|
+static int
|
|
+spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
+{
|
|
SPF_server_t *spf_server = handle;
|
|
SPF_request_t *spf_request = NULL;
|
|
SPF_response_t *spf_response = NULL;
|
|
diff -ru a/lookups/sqlite.c b/lookups/sqlite.c
|
|
--- a/src/lookups/sqlite.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/sqlite.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -81,7 +81,7 @@
|
|
|
|
static int
|
|
sqlite_find(void *handle, uschar *filename, const uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
int ret;
|
|
struct strbuf res = { NULL, 0, 0 };
|
|
@@ -93,7 +93,7 @@
|
|
return FAIL;
|
|
}
|
|
|
|
-if (res.string == NULL) *do_cache = FALSE;
|
|
+if (res.string == NULL) *do_cache = 0;
|
|
|
|
*result = res.string;
|
|
return OK;
|
|
diff -ru a/lookups/testdb.c b/lookups/testdb.c
|
|
--- a/src/lookups/testdb.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/testdb.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -38,7 +38,7 @@
|
|
|
|
static int
|
|
testdb_find(void *handle, uschar *filename, const uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
handle = handle; /* Keep picky compilers happy */
|
|
filename = filename;
|
|
@@ -57,7 +57,7 @@
|
|
return DEFER;
|
|
}
|
|
|
|
-if (Ustrcmp(query, "nocache") == 0) *do_cache = FALSE;
|
|
+if (Ustrcmp(query, "nocache") == 0) *do_cache = 0;
|
|
|
|
*result = string_copy(query);
|
|
return OK;
|
|
diff -ru a/lookups/whoson.c b/lookups/whoson.c
|
|
--- a/src/lookups/whoson.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/lookups/whoson.c 2017-04-24 09:33:17.364999757 +0200
|
|
@@ -36,7 +36,7 @@
|
|
|
|
static int
|
|
whoson_find(void *handle, uschar *filename, uschar *query, int length,
|
|
- uschar **result, uschar **errmsg, BOOL *do_cache)
|
|
+ uschar **result, uschar **errmsg, uint *do_cache)
|
|
{
|
|
uschar buffer[80];
|
|
handle = handle; /* Keep picky compilers happy */
|
|
diff -ru a/mime.c b/mime.c
|
|
--- a/src/mime.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/mime.c 2017-04-24 09:33:17.368999807 +0200
|
|
@@ -550,7 +550,8 @@
|
|
uschar * val = string_cat(NULL, &size, &ptr, US"=?", 2);
|
|
uschar c;
|
|
|
|
-val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
|
|
+if (charset)
|
|
+ val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
|
|
val = string_cat(val, &size, &ptr, US"?Q?", 3);
|
|
|
|
while ((c = *fname))
|
|
@@ -607,7 +608,7 @@
|
|
if (!fgets(CS header, MIME_MAX_HEADER_SIZE, f))
|
|
{
|
|
/* Hit EOF or read error. Ugh. */
|
|
- DEBUG(D_acl) debug_printf("Hit EOF ...\n");
|
|
+ DEBUG(D_acl) debug_printf("MIME: Hit EOF ...\n");
|
|
return rc;
|
|
}
|
|
|
|
@@ -619,12 +620,12 @@
|
|
if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
|
|
{
|
|
/* END boundary found */
|
|
- DEBUG(D_acl) debug_printf("End boundary found %s\n",
|
|
+ DEBUG(D_acl) debug_printf("MIME: End boundary found %s\n",
|
|
context->boundary);
|
|
return rc;
|
|
}
|
|
|
|
- DEBUG(D_acl) debug_printf("Next part with boundary %s\n",
|
|
+ DEBUG(D_acl) debug_printf("MIME: Next part with boundary %s\n",
|
|
context->boundary);
|
|
break;
|
|
}
|
|
@@ -648,7 +649,7 @@
|
|
|
|
for (q = p; *q != ';' && *q; q++) ;
|
|
*mh->value = string_copynlc(p, q-p);
|
|
- DEBUG(D_acl) debug_printf("found %s MIME header, value is '%s'\n",
|
|
+ DEBUG(D_acl) debug_printf("MIME: found %s header, value is '%s'\n",
|
|
mh->name, *mh->value);
|
|
|
|
if (*(p = q)) p++; /* jump past the ; */
|
|
@@ -666,7 +667,7 @@
|
|
{
|
|
mime_parameter * mp;
|
|
|
|
- DEBUG(D_acl) debug_printf(" considering paramlist '%s'\n", p);
|
|
+ DEBUG(D_acl) debug_printf("MIME: considering paramlist '%s'\n", p);
|
|
|
|
if ( !mime_filename
|
|
&& strncmpic(CUS"content-disposition:", header, 20) == 0
|
|
@@ -700,22 +701,27 @@
|
|
uschar * s = q;
|
|
|
|
/* look for a ' in the "filename" */
|
|
- while(*s != '\'' && *s) s++; /* s is ' or NUL */
|
|
+ while(*s != '\'' && *s) s++; /* s is 1st ' or NUL */
|
|
|
|
if ((size = s-q) > 0)
|
|
- {
|
|
mime_filename_charset = string_copyn(q, size);
|
|
- p = s;
|
|
|
|
- while(*p == '\'' && *p) p++; /* p is after ' */
|
|
- }
|
|
+ if (*(p = s)) p++;
|
|
+ while(*p == '\'') p++; /* p is after 2nd ' */
|
|
}
|
|
else
|
|
p = q;
|
|
|
|
+ DEBUG(D_acl) debug_printf("MIME: charset %s fname '%s'\n",
|
|
+ mime_filename_charset ? mime_filename_charset : US"<NULL>", p);
|
|
+
|
|
temp_string = rfc2231_to_2047(p, mime_filename_charset, &slen);
|
|
- temp_string = rfc2047_decode(temp_string, FALSE, NULL, 32,
|
|
+ DEBUG(D_acl) debug_printf("MIME: 2047-name %s\n", temp_string);
|
|
+
|
|
+ temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ',
|
|
NULL, &err_msg);
|
|
+ DEBUG(D_acl) debug_printf("MIME: plain-name %s\n", temp_string);
|
|
+
|
|
size = Ustrlen(temp_string);
|
|
|
|
if (size == slen)
|
|
@@ -750,7 +756,7 @@
|
|
&dummy_errstr)
|
|
: NULL;
|
|
DEBUG(D_acl) debug_printf(
|
|
- " found %s MIME parameter in %s header, value '%s'\n",
|
|
+ "MIME: found %s parameter in %s header, value '%s'\n",
|
|
mp->name, mh->name, *mp->value);
|
|
|
|
break; /* done matching param names */
|
|
@@ -768,7 +774,7 @@
|
|
if (decoding_failed) mime_filename = mime_fname_rfc2231;
|
|
|
|
DEBUG(D_acl) debug_printf(
|
|
- " found %s MIME parameter in %s header, value is '%s'\n",
|
|
+ "MIME: found %s parameter in %s header, value is '%s'\n",
|
|
"filename", mh->name, mime_filename);
|
|
}
|
|
}
|
|
@@ -809,8 +815,9 @@
|
|
(nested_context.boundary != NULL) &&
|
|
(Ustrncmp(mime_content_type,"multipart",9) == 0) )
|
|
{
|
|
- DEBUG(D_acl) debug_printf("Entering multipart recursion, boundary '%s'\n",
|
|
- nested_context.boundary);
|
|
+ DEBUG(D_acl)
|
|
+ debug_printf("MIME: Entering multipart recursion, boundary '%s'\n",
|
|
+ nested_context.boundary);
|
|
|
|
nested_context.context =
|
|
context && context->context == MBC_ATTACHMENT
|
|
diff -ru a/pdkim/base64.c b/pdkim/base64.c
|
|
--- a/src/pdkim/base64.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/pdkim/base64.c 2017-04-24 09:33:17.368999807 +0200
|
|
@@ -128,20 +128,22 @@
|
|
|
|
for( i = j = n = 0; i < slen; i++ )
|
|
{
|
|
+ unsigned char c = src[i];
|
|
+
|
|
if( ( slen - i ) >= 2 &&
|
|
- src[i] == '\r' && src[i + 1] == '\n' )
|
|
+ c == '\r' && src[i + 1] == '\n' )
|
|
continue;
|
|
|
|
- if( src[i] == '\n' )
|
|
+ if( c == '\n' || c == ' ' || c == '\t' )
|
|
continue;
|
|
|
|
- if( src[i] == '=' && ++j > 2 )
|
|
+ if( c == '=' && ++j > 2 )
|
|
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
|
|
|
|
- if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
|
|
+ if( c > 127 || base64_dec_map[src[i]] == 127 )
|
|
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
|
|
|
|
- if( base64_dec_map[src[i]] < 64 && j != 0 )
|
|
+ if( base64_dec_map[c] < 64 && j != 0 )
|
|
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
|
|
|
|
n++;
|
|
@@ -160,11 +162,13 @@
|
|
|
|
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
|
|
{
|
|
- if( *src == '\r' || *src == '\n' )
|
|
+ unsigned char c = *src;
|
|
+
|
|
+ if( c == '\r' || c == '\n' || c == ' ' || c == '\t' )
|
|
continue;
|
|
|
|
- j -= ( base64_dec_map[*src] == 64 );
|
|
- x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
|
|
+ j -= ( base64_dec_map[c] == 64 );
|
|
+ x = (x << 6) | ( base64_dec_map[c] & 0x3F );
|
|
|
|
if( ++n == 4 )
|
|
{
|
|
diff -ru a/readconf.c b/readconf.c
|
|
--- a/src/readconf.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/readconf.c 2017-04-24 09:33:17.368999807 +0200
|
|
@@ -3456,10 +3456,10 @@
|
|
" are obsolete\n");
|
|
#endif /*SUPPORT_TLS*/
|
|
|
|
-if ((!add_environment || *add_environment == '\0') && !keep_environment)
|
|
+if (!keep_environment && environ && *environ)
|
|
log_write(0, LOG_MAIN,
|
|
- "WARNING: purging the environment.\n"
|
|
- " Suggested action: use keep_environment and add_environment.\n");
|
|
+ "Warning: purging the environment.\n"
|
|
+ " Suggested action: use keep_environment.");
|
|
}
|
|
|
|
|
|
diff -ru a/receive.c b/receive.c
|
|
--- a/src/receive.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/receive.c 2017-04-24 09:33:17.368999807 +0200
|
|
@@ -835,7 +835,15 @@
|
|
ch_state = 4;
|
|
continue;
|
|
}
|
|
- ch_state = 1; /* The dot itself is removed */
|
|
+ /* The dot was removed at state 3. For a doubled dot, here, reinstate
|
|
+ it to cutthrough. The current ch, dot or not, is passed both to cutthrough
|
|
+ and to file below. */
|
|
+ if (ch == '.')
|
|
+ {
|
|
+ uschar c= ch;
|
|
+ (void) cutthrough_puts(&c, 1);
|
|
+ }
|
|
+ ch_state = 1;
|
|
break;
|
|
|
|
case 4: /* After [CR] LF . CR */
|
|
diff -ru a/search.c b/search.c
|
|
--- a/src/search.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/search.c 2017-04-24 09:33:17.372999860 +0200
|
|
@@ -466,6 +466,7 @@
|
|
{
|
|
tree_node *t = (tree_node *)handle;
|
|
search_cache *c = (search_cache *)(t->data.ptr);
|
|
+expiring_data *e;
|
|
uschar *data = NULL;
|
|
int search_type = t->name[0] - '0';
|
|
int old_pool = store_pool;
|
|
@@ -491,18 +492,27 @@
|
|
/* Look up the data for the key, unless it is already in the cache for this
|
|
file. No need to check c->item_cache for NULL, tree_search will do so. */
|
|
|
|
-if ((t = tree_search(c->item_cache, keystring)) == NULL)
|
|
+if ( (t = tree_search(c->item_cache, keystring))
|
|
+ && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
|
|
+ )
|
|
+ { /* Data was in the cache already; set the pointer from the tree node */
|
|
+ data = e->ptr;
|
|
+ DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
|
|
+ keystring,
|
|
+ filename ? US"\n in " : US"", filename ? filename : US"");
|
|
+ }
|
|
+else
|
|
{
|
|
- BOOL do_cache = TRUE;
|
|
+ uint do_cache = UINT_MAX;
|
|
int keylength = Ustrlen(keystring);
|
|
|
|
DEBUG(D_lookup)
|
|
{
|
|
- if (filename != NULL)
|
|
- debug_printf("file lookup required for %s\n in %s\n",
|
|
- keystring, filename);
|
|
- else
|
|
- debug_printf("database lookup required for %s\n", keystring);
|
|
+ if (t) debug_printf("cached data found but past valid time; ");
|
|
+ debug_printf("%s lookup required for %s%s%s\n",
|
|
+ filename ? US"file" : US"database",
|
|
+ keystring,
|
|
+ filename ? US"\n in " : US"", filename ? filename : US"");
|
|
}
|
|
|
|
/* Call the code for the different kinds of search. DEFER is handled
|
|
@@ -511,9 +521,7 @@
|
|
|
|
if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
|
|
&data, &search_error_message, &do_cache) == DEFER)
|
|
- {
|
|
search_find_defer = TRUE;
|
|
- }
|
|
|
|
/* A record that has been found is now in data, which is either NULL
|
|
or points to a bit of dynamic store. Cache the result of the lookup if
|
|
@@ -524,10 +532,22 @@
|
|
else if (do_cache)
|
|
{
|
|
int len = keylength + 1;
|
|
- t = store_get(sizeof(tree_node) + len);
|
|
- memcpy(t->name, keystring, len);
|
|
- t->data.ptr = data;
|
|
- tree_insertnode(&c->item_cache, t);
|
|
+
|
|
+ if (t) /* Previous, out-of-date cache entry. Update with the */
|
|
+ { /* new result and forget the old one */
|
|
+ e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
|
|
+ e->ptr = data;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len);
|
|
+ e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
|
|
+ e->ptr = data;
|
|
+ t = (tree_node *)(e+1);
|
|
+ memcpy(t->name, keystring, len);
|
|
+ t->data.ptr = e;
|
|
+ tree_insertnode(&c->item_cache, t);
|
|
+ }
|
|
}
|
|
|
|
/* If caching was disabled, empty the cache tree. We just set the cache
|
|
@@ -540,34 +560,19 @@
|
|
}
|
|
}
|
|
|
|
-/* Data was in the cache already; set the pointer from the tree node */
|
|
-
|
|
-else
|
|
- {
|
|
- data = US t->data.ptr;
|
|
- DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
|
|
- keystring,
|
|
- (filename == NULL)? US"" : US"\n in ",
|
|
- (filename == NULL)? US"" : filename);
|
|
- }
|
|
-
|
|
-/* Debug: output the answer */
|
|
-
|
|
DEBUG(D_lookup)
|
|
{
|
|
- if (data == NULL)
|
|
- {
|
|
- if (search_find_defer) debug_printf("lookup deferred: %s\n",
|
|
- search_error_message);
|
|
- else debug_printf("lookup failed\n");
|
|
- }
|
|
- else debug_printf("lookup yielded: %s\n", data);
|
|
+ if (data)
|
|
+ debug_printf("lookup yielded: %s\n", data);
|
|
+ else if (search_find_defer)
|
|
+ debug_printf("lookup deferred: %s\n", search_error_message);
|
|
+ else debug_printf("lookup failed\n");
|
|
}
|
|
|
|
/* Return it in new dynamic store in the regular pool */
|
|
|
|
store_pool = old_pool;
|
|
-return (data == NULL)? NULL : string_copy(data);
|
|
+return data ? string_copy(data) : NULL;
|
|
}
|
|
|
|
|
|
diff -ru a/smtp_in.c b/smtp_in.c
|
|
--- a/src/smtp_in.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/smtp_in.c 2017-04-24 09:33:17.372999860 +0200
|
|
@@ -9,6 +9,7 @@
|
|
|
|
|
|
#include "exim.h"
|
|
+#include <assert.h>
|
|
|
|
|
|
/* Initialize for TCP wrappers if so configured. It appears that the macro
|
|
@@ -232,6 +233,7 @@
|
|
|
|
/* Sanity check and validate optional args to MAIL FROM: envelope */
|
|
enum {
|
|
+ ENV_MAIL_OPT_NULL,
|
|
ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
|
|
#ifndef DISABLE_PRDR
|
|
ENV_MAIL_OPT_PRDR,
|
|
@@ -240,7 +242,6 @@
|
|
#ifdef EXPERIMENTAL_INTERNATIONAL
|
|
ENV_MAIL_OPT_UTF8,
|
|
#endif
|
|
- ENV_MAIL_OPT_NULL
|
|
};
|
|
typedef struct {
|
|
uschar * name; /* option requested during MAIL cmd */
|
|
@@ -260,7 +261,8 @@
|
|
#ifdef EXPERIMENTAL_INTERNATIONAL
|
|
{ US"SMTPUTF8",ENV_MAIL_OPT_UTF8, FALSE }, /* rfc6531 */
|
|
#endif
|
|
- { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
|
|
+ /* keep this the last entry */
|
|
+ { US"NULL", ENV_MAIL_OPT_NULL, FALSE },
|
|
};
|
|
|
|
/* When reading SMTP from a remote host, we have to use our own versions of the
|
|
@@ -3887,7 +3889,7 @@
|
|
if (!extract_option(&name, &value)) break;
|
|
|
|
for (mail_args = env_mail_type_list;
|
|
- (char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
|
|
+ mail_args->value != ENV_MAIL_OPT_NULL;
|
|
mail_args++
|
|
)
|
|
if (strcmpic(name, mail_args->name) == 0)
|
|
@@ -4066,15 +4068,17 @@
|
|
}
|
|
break;
|
|
#endif
|
|
- /* Unknown option. Stick back the terminator characters and break
|
|
+ /* No valid option. Stick back the terminator characters and break
|
|
the loop. Do the name-terminator second as extract_option sets
|
|
- value==name when it found no equal-sign.
|
|
- An error for a malformed address will occur. */
|
|
- default:
|
|
+ value==name when it found no equal-sign.
|
|
+ An error for a malformed address will occur. */
|
|
+ case ENV_MAIL_OPT_NULL:
|
|
value[-1] = '=';
|
|
name[-1] = ' ';
|
|
arg_error = TRUE;
|
|
break;
|
|
+
|
|
+ default: assert(0);
|
|
}
|
|
/* Break out of for loop if switch() had bad argument or
|
|
when start of the email address is reached */
|
|
diff -ru a/smtp_out.c b/smtp_out.c
|
|
--- a/src/smtp_out.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/smtp_out.c 2017-04-24 09:33:17.372999860 +0200
|
|
@@ -26,7 +26,6 @@
|
|
which case the function does nothing
|
|
host_af AF_INET or AF_INET6 for the outgoing IP address
|
|
addr the mail address being handled (for setting errors)
|
|
- changed if not NULL, set TRUE if expansion actually changed istring
|
|
interface point this to the interface
|
|
msg to add to any error message
|
|
|
|
@@ -36,7 +35,7 @@
|
|
|
|
BOOL
|
|
smtp_get_interface(uschar *istring, int host_af, address_item *addr,
|
|
- BOOL *changed, uschar **interface, uschar *msg)
|
|
+ uschar **interface, uschar *msg)
|
|
{
|
|
const uschar * expint;
|
|
uschar *iface;
|
|
@@ -54,8 +53,6 @@
|
|
return FALSE;
|
|
}
|
|
|
|
-if (changed != NULL) *changed = expint != istring;
|
|
-
|
|
while (isspace(*expint)) expint++;
|
|
if (*expint == 0) return TRUE;
|
|
|
|
diff -ru a/structs.h b/structs.h
|
|
--- a/src/structs.h 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/structs.h 2017-04-24 09:33:17.372999860 +0200
|
|
@@ -657,6 +657,16 @@
|
|
uschar name[1]; /* node name - variable length */
|
|
} tree_node;
|
|
|
|
+/* Structure for holding time-limited data such as DNS returns.
|
|
+We use this rather than extending tree_node to avoid wasting
|
|
+space for most tree use (variables...) at the cost of complexity
|
|
+for the lookups cache */
|
|
+
|
|
+typedef struct expiring_data {
|
|
+ time_t expiry; /* if nonzero, data invalid after this time */
|
|
+ void *ptr; /* pointer to data */
|
|
+} expiring_data;
|
|
+
|
|
/* Structure for holding the handle and the cached last lookup for searches.
|
|
This block is pointed to by the tree entry for the file. The file can get
|
|
closed if too many are opened at once. There is a LRU chain for deciding which
|
|
@@ -676,6 +686,7 @@
|
|
typedef struct {
|
|
uschar name[DNS_MAXNAME]; /* domain name */
|
|
int type; /* record type */
|
|
+ unsigned short ttl; /* time-to-live, seconds */
|
|
int size; /* size of data */
|
|
uschar *data; /* pointer to data */
|
|
} dns_record;
|
|
diff -ru a/tls-gnu.c b/tls-gnu.c
|
|
--- a/src/tls-gnu.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/tls-gnu.c 2017-04-24 09:33:17.376999910 +0200
|
|
@@ -1729,6 +1729,7 @@
|
|
|
|
if (!sigalrm_seen)
|
|
{
|
|
+ gnutls_certificate_free_credentials(state->x509_cred);
|
|
(void)fclose(smtp_out);
|
|
(void)fclose(smtp_in);
|
|
}
|
|
@@ -2014,6 +2015,8 @@
|
|
}
|
|
|
|
gnutls_deinit(state->session);
|
|
+gnutls_certificate_free_credentials(state->x509_cred);
|
|
+
|
|
|
|
state->tlsp->active = -1;
|
|
memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
|
|
@@ -2074,6 +2077,8 @@
|
|
receive_smtp_buffered = smtp_buffered;
|
|
|
|
gnutls_deinit(state->session);
|
|
+ gnutls_certificate_free_credentials(state->x509_cred);
|
|
+
|
|
state->session = NULL;
|
|
state->tlsp->active = -1;
|
|
state->tlsp->bits = 0;
|
|
diff -ru a/transport.c b/transport.c
|
|
--- a/src/transport.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/transport.c 2017-04-24 09:33:17.376999910 +0200
|
|
@@ -1752,7 +1752,7 @@
|
|
{
|
|
if (split_spool_directory)
|
|
sprintf(CS spool_file, "%s%c/%s-D",
|
|
- spool_dir, new_message_id[5], msgq[i].message_id);
|
|
+ spool_dir, msgq[i].message_id[5], msgq[i].message_id);
|
|
else
|
|
sprintf(CS spool_file, "%s%s-D", spool_dir, msgq[i].message_id);
|
|
|
|
diff -ru a/transports/smtp.c b/transports/smtp.c
|
|
--- a/src/transports/smtp.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/transports/smtp.c 2017-04-24 09:33:17.376999910 +0200
|
|
@@ -1274,14 +1274,19 @@
|
|
static BOOL
|
|
smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
|
|
{
|
|
-uschar * save_sender_address = sender_address;
|
|
-uschar * current_local_identity =
|
|
+
|
|
+uschar * message_local_identity,
|
|
+ * current_local_identity,
|
|
+ * new_sender_address;
|
|
+
|
|
+current_local_identity =
|
|
smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
|
|
-uschar * new_sender_address = deliver_get_sender_address(message_id);
|
|
-uschar * message_local_identity =
|
|
- smtp_local_identity(new_sender_address, s_compare->tblock);
|
|
|
|
-sender_address = save_sender_address;
|
|
+if (!(new_sender_address = deliver_get_sender_address(message_id)))
|
|
+ return 0;
|
|
+
|
|
+message_local_identity =
|
|
+ smtp_local_identity(new_sender_address, s_compare->tblock);
|
|
|
|
return Ustrcmp(current_local_identity, message_local_identity) == 0;
|
|
}
|
|
@@ -3169,7 +3174,6 @@
|
|
BOOL serialized = FALSE;
|
|
BOOL host_is_expired = FALSE;
|
|
BOOL message_defer = FALSE;
|
|
- BOOL ifchanges = FALSE;
|
|
BOOL some_deferred = FALSE;
|
|
address_item *first_addr = NULL;
|
|
uschar *interface = NULL;
|
|
@@ -3345,15 +3349,18 @@
|
|
if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
|
|
|
|
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
|
|
- string changes upon expansion, we must add it to the key that is used for
|
|
- retries, because connections to the same host from a different interface
|
|
- should be treated separately. */
|
|
+ string is set, even if constant (as different transports can have different
|
|
+ constant settings), we must add it to the key that is used for retries,
|
|
+ because connections to the same host from a different interface should be
|
|
+ treated separately. */
|
|
|
|
host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET : AF_INET6;
|
|
- if (!smtp_get_interface(ob->interface, host_af, addrlist, &ifchanges,
|
|
- &interface, tid))
|
|
- return FALSE;
|
|
- if (ifchanges) pistring = string_sprintf("%s/%s", pistring, interface);
|
|
+ if ((rs = ob->interface) && *rs)
|
|
+ {
|
|
+ if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid))
|
|
+ return FALSE;
|
|
+ pistring = string_sprintf("%s/%s", pistring, interface);
|
|
+ }
|
|
|
|
/* The first time round the outer loop, check the status of the host by
|
|
inspecting the retry data. The second time round, we are interested only
|
|
diff -ru a/verify.c b/verify.c
|
|
--- a/src/verify.c 2016-03-02 18:27:51.000000000 +0100
|
|
+++ b/src/verify.c 2017-04-24 09:33:17.380999961 +0200
|
|
@@ -21,6 +21,7 @@
|
|
/* Structure for caching DNSBL lookups */
|
|
|
|
typedef struct dnsbl_cache_block {
|
|
+ time_t expiry;
|
|
dns_address *rhs;
|
|
uschar *text;
|
|
int rc;
|
|
@@ -443,7 +444,7 @@
|
|
|
|
host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
|
|
|
|
- if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
|
|
+ if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
|
|
US"callout") ||
|
|
!smtp_get_port(tf->port, addr, &port, US"callout"))
|
|
log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
|
|
@@ -578,7 +579,7 @@
|
|
deliver_domain = addr->domain;
|
|
transport_name = addr->transport->name;
|
|
|
|
- if ( !smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
|
|
+ if ( !smtp_get_interface(tf->interface, host_af, addr, &interface,
|
|
US"callout")
|
|
|| !smtp_get_port(tf->port, addr, &port, US"callout")
|
|
)
|
|
@@ -3584,21 +3585,37 @@
|
|
|
|
/* Look for this query in the cache. */
|
|
|
|
-t = tree_search(dnsbl_cache, query);
|
|
+if ( (t = tree_search(dnsbl_cache, query))
|
|
+ && (cb = t->data.ptr)->expiry > time(NULL)
|
|
+ )
|
|
+
|
|
+/* Previous lookup was cached */
|
|
+
|
|
+ {
|
|
+ HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
|
|
+ }
|
|
|
|
/* If not cached from a previous lookup, we must do a DNS lookup, and
|
|
cache the result in permanent memory. */
|
|
|
|
-if (t == NULL)
|
|
+else
|
|
{
|
|
+ uint ttl = 3600;
|
|
+
|
|
store_pool = POOL_PERM;
|
|
|
|
- /* Set up a tree entry to cache the lookup */
|
|
+ if (t)
|
|
+ {
|
|
+ HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
|
|
+ }
|
|
|
|
- t = store_get(sizeof(tree_node) + Ustrlen(query));
|
|
- Ustrcpy(t->name, query);
|
|
- t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
|
|
- (void)tree_insertnode(&dnsbl_cache, t);
|
|
+ else
|
|
+ { /* Set up a tree entry to cache the lookup */
|
|
+ t = store_get(sizeof(tree_node) + Ustrlen(query));
|
|
+ Ustrcpy(t->name, query);
|
|
+ t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
|
|
+ (void)tree_insertnode(&dnsbl_cache, t);
|
|
+ }
|
|
|
|
/* Do the DNS loopup . */
|
|
|
|
@@ -3616,7 +3633,10 @@
|
|
|
|
Quite apart from one A6 RR generating multiple addresses, there are DNS
|
|
lists that return more than one A record, so we must handle multiple
|
|
- addresses generated in that way as well. */
|
|
+ addresses generated in that way as well.
|
|
+
|
|
+ Mark the cache entry with the "now" plus the minimum of the address TTLs,
|
|
+ or some suitably far-future time if none were found. */
|
|
|
|
if (cb->rc == DNS_SUCCEED)
|
|
{
|
|
@@ -3634,6 +3654,7 @@
|
|
*addrp = da;
|
|
while (da->next != NULL) da = da->next;
|
|
addrp = &(da->next);
|
|
+ if (ttl > rr->ttl) ttl = rr->ttl;
|
|
}
|
|
}
|
|
}
|
|
@@ -3645,17 +3666,10 @@
|
|
if (cb->rhs == NULL) cb->rc = DNS_NODATA;
|
|
}
|
|
|
|
+ cb->expiry = time(NULL)+ttl;
|
|
store_pool = old_pool;
|
|
}
|
|
|
|
-/* Previous lookup was cached */
|
|
-
|
|
-else
|
|
- {
|
|
- HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
|
|
- cb = t->data.ptr;
|
|
- }
|
|
-
|
|
/* We now have the result of the DNS lookup, either newly done, or cached
|
|
from a previous call. If the lookup succeeded, check against the address
|
|
list if there is one. This may be a positive equality list (introduced by
|
|
Only in a: version.sh
|