]> git.pld-linux.org Git - packages/exim.git/blob - exim-git.patch
915f246d2025318ae726a25bc44fcad917adc285
[packages/exim.git] / exim-git.patch
1 commit da1aecfce80fba32b9abb328cf78088d95b7700a
2 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
3 Date:   Wed Aug 19 15:22:41 2015 +0200
4
5     Fix post-transport-crash.
6     
7     The crash probably was introduced in a39bd74d3e94 and
8     needs 'split_spool_directory=yes' to expose.
9     
10     Thanks to Wolfgang Breyha, who found the same fix.
11     
12     (cherry picked from commit 6b51df8340eacc95e3def9a4376506610e91996c)
13
14 diff --git a/src/src/transport.c b/src/src/transport.c
15 index fa6f869..a6ad3ed 100644
16 --- a/src/src/transport.c
17 +++ b/src/src/transport.c
18 @@ -1752,7 +1752,7 @@ while (1)
19      {
20      if (split_spool_directory)
21         sprintf(CS spool_file, "%s%c/%s-D",
22 -                     spool_dir, new_message_id[5], msgq[i].message_id);
23 +                     spool_dir, msgq[i].message_id[5], msgq[i].message_id);
24      else
25         sprintf(CS spool_file, "%s%s-D", spool_dir, msgq[i].message_id);
26  
27
28 commit d7168d8b112d3ba642a25ed04de36fb76d4a847d
29 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
30 Date:   Thu Aug 20 13:58:06 2015 +0200
31
32     Fix post-transport-crash: safeguard for missing spool BUG 1671
33     
34     Based on a proposal from Wolfgang Breyha.
35     
36     (cherry picked from commit dadff1d47e54962b0fdf98e8ce5cef42b6cb7fb5)
37
38 diff --git a/src/src/deliver.c b/src/src/deliver.c
39 index 78f8f4b..4154ff7 100644
40 --- a/src/src/deliver.c
41 +++ b/src/src/deliver.c
42 @@ -9,6 +9,7 @@
43  
44  
45  #include "exim.h"
46 +#include <assert.h>
47  
48  
49  /* Data block for keeping track of subprocesses for parallel remote
50 @@ -7904,17 +7905,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
51  uschar *
52  deliver_get_sender_address (uschar * id)
53  {
54 +int rc;
55 +uschar * new_sender_address,
56 +       * save_sender_address;
57 +
58  if (!spool_open_datafile(id))
59    return NULL;
60  
61 +/* Save and restore the global sender_address.  I'm not sure if we should
62 +not save/restore all the other global variables too, because
63 +spool_read_header() may change all of them. But OTOH, when this
64 +deliver_get_sender_address() gets called, the current message is done
65 +already and nobody needs the globals anymore. (HS12, 2015-08-21) */
66 +
67  sprintf(CS spoolname, "%s-H", id);
68 -if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
69 +save_sender_address = sender_address;
70 +
71 +rc = spool_read_header(spoolname, TRUE, TRUE);
72 +
73 +new_sender_address = sender_address;
74 +sender_address = save_sender_address;
75 +
76 +if (rc != spool_read_OK)
77    return NULL;
78  
79 +assert(new_sender_address);
80 +
81  (void)close(deliver_datafile);
82  deliver_datafile = -1;
83  
84 -return sender_address;
85 +return new_sender_address;
86  }
87  
88  /* vi: aw ai sw=2
89 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
90 index a952413..5ac5533 100644
91 --- a/src/src/transports/smtp.c
92 +++ b/src/src/transports/smtp.c
93 @@ -1274,14 +1274,19 @@ we will veto this new message.  */
94  static BOOL
95  smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
96  {
97 -uschar * save_sender_address = sender_address;
98 -uschar * current_local_identity =
99 +
100 +uschar * message_local_identity,
101 +       * current_local_identity,
102 +       * new_sender_address;
103 +
104 +current_local_identity =
105    smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
106 -uschar * new_sender_address = deliver_get_sender_address(message_id);
107 -uschar * message_local_identity =
108 -  smtp_local_identity(new_sender_address, s_compare->tblock);
109  
110 -sender_address = save_sender_address;
111 +if (!(new_sender_address = deliver_get_sender_address(message_id)))
112 +    return 0;
113 +
114 +message_local_identity =
115 +  smtp_local_identity(new_sender_address, s_compare->tblock);
116  
117  return Ustrcmp(current_local_identity, message_local_identity) == 0;
118  }
119
120 commit 9e1acebc3fbb288da804ab9031c7c448dffd841a
121 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
122 Date:   Tue Aug 11 17:36:29 2015 +0200
123
124     Fix ESMTP MAIL command option processing
125     
126     If the address containes spaces, the option processing
127     was confused.
128     
129     (cherry picked from commit 2ef7ed082481b2dccd3c2e0eae849b24bf0b172a)
130
131 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
132 index cf0a5d6..980d54b 100644
133 --- a/src/src/smtp_in.c
134 +++ b/src/src/smtp_in.c
135 @@ -9,6 +9,7 @@
136  
137  
138  #include "exim.h"
139 +#include <assert.h>
140  
141  
142  /* Initialize for TCP wrappers if so configured. It appears that the macro
143 @@ -232,6 +233,7 @@ static uschar *protocols[] = {
144  
145  /* Sanity check and validate optional args to MAIL FROM: envelope */
146  enum {
147 +  ENV_MAIL_OPT_NULL,
148    ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
149  #ifndef DISABLE_PRDR
150    ENV_MAIL_OPT_PRDR,
151 @@ -240,7 +242,6 @@ enum {
152  #ifdef EXPERIMENTAL_INTERNATIONAL
153    ENV_MAIL_OPT_UTF8,
154  #endif
155 -  ENV_MAIL_OPT_NULL
156    };
157  typedef struct {
158    uschar *   name;  /* option requested during MAIL cmd */
159 @@ -260,7 +261,8 @@ static env_mail_type_t env_mail_type_list[] = {
160  #ifdef EXPERIMENTAL_INTERNATIONAL
161      { US"SMTPUTF8",ENV_MAIL_OPT_UTF8,  FALSE },                /* rfc6531 */
162  #endif
163 -    { US"NULL",   ENV_MAIL_OPT_NULL,   FALSE }
164 +    /* keep this the last entry */
165 +    { US"NULL",   ENV_MAIL_OPT_NULL,   FALSE },
166    };
167  
168  /* When reading SMTP from a remote host, we have to use our own versions of the
169 @@ -3887,7 +3889,7 @@ while (done <= 0)
170        if (!extract_option(&name, &value)) break;
171  
172        for (mail_args = env_mail_type_list;
173 -           (char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
174 +           mail_args->value != ENV_MAIL_OPT_NULL;
175             mail_args++
176            )
177          if (strcmpic(name, mail_args->name) == 0)
178 @@ -4066,15 +4068,17 @@ while (done <= 0)
179             }
180           break;
181  #endif
182 -        /* Unknown option. Stick back the terminator characters and break
183 +        /* No valid option. Stick back the terminator characters and break
184          the loop.  Do the name-terminator second as extract_option sets
185 -       value==name when it found no equal-sign.
186 -       An error for a malformed address will occur. */
187 -        default:
188 +        value==name when it found no equal-sign.
189 +        An error for a malformed address will occur. */
190 +        case ENV_MAIL_OPT_NULL:
191            value[-1] = '=';
192            name[-1] = ' ';
193            arg_error = TRUE;
194            break;
195 +
196 +        default:  assert(0);
197          }
198        /* Break out of for loop if switch() had bad argument or
199           when start of the email address is reached */
200
201 commit 22c82c48aa5d23c49d38e3581810ea54587df61b
202 Author: Jeremy Harris <jgh146exb@wizmail.org>
203 Date:   Tue Aug 25 10:36:27 2015 +0100
204
205     Close logs after daemon-process exceptional write.  Bug 728
206     
207     (cherry picked from commit c8899c20aa08c9ae6a4c291aad23ba90512bebe4)
208
209 diff --git a/src/src/daemon.c b/src/src/daemon.c
210 index 894a96f..a7a49f0 100644
211 --- a/src/src/daemon.c
212 +++ b/src/src/daemon.c
213 @@ -735,6 +735,7 @@ else (void)close(dup_accept_socket);
214  /* Release any store used in this process, including the store used for holding
215  the incoming host address and an expanded active_hostname. */
216  
217 +log_close_all();
218  store_reset(reset_point);
219  sender_host_address = NULL;
220  }
221
222 commit 4d3b8805796ffa39889060d9f216bfaf7391c542
223 Author: Jeremy Harris <jgh146exb@wizmail.org>
224 Date:   Thu Sep 17 13:35:16 2015 +0100
225
226     DNS: time-limit cached returns, using TTL.  Bug 1395
227     
228     This can matter for fast-changing data such as DNSBLs.
229     
230     (cherry picked from commit 14b3c5bc64a16df07583fe4b5ef2e0129d063893)
231     
232     DNS: avoid overflow in cache TTL for negative entries.  Bug 1395
233     
234     (cherry picked from commit e162fc9757d4b8cb41aca74214e968622d6c3dee)
235
236 diff --git a/src/src/dns.c b/src/src/dns.c
237 index 64958d9..abed126 100644
238 --- a/src/src/dns.c
239 +++ b/src/src/dns.c
240 @@ -390,7 +390,8 @@ from the following bytes. */
241  
242  dnss->aptr += namelen;
243  GETSHORT(dnss->srr.type, dnss->aptr); /* Record type */
244 -dnss->aptr += 6;                      /* Don't want class or TTL */
245 +dnss->aptr += 2;                      /* Don't want class */
246 +GETLONG(dnss->srr.ttl, dnss->aptr);   /* TTL */
247  GETSHORT(dnss->srr.size, dnss->aptr); /* Size of data portion */
248  dnss->srr.data = dnss->aptr;          /* The record's data follows */
249  dnss->aptr += dnss->srr.size;         /* Advance to next RR */
250 diff --git a/src/src/lookupapi.h b/src/src/lookupapi.h
251 index cdd1c85..03de8f6 100644
252 --- a/src/src/lookupapi.h
253 +++ b/src/src/lookupapi.h
254 @@ -34,7 +34,7 @@ typedef struct lookup_info {
255      int,                          /* length of key or query */
256      uschar **,                    /* for returning answer */
257      uschar **,                    /* for error message */
258 -    BOOL *);                      /* to request cache cleanup */
259 +    uint *);                      /* cache TTL, sconds */
260    void (*close)(                  /* close function */
261      void *);                      /* handle */
262    void (*tidy)(void);             /* tidy function */
263 @@ -46,9 +46,10 @@ typedef struct lookup_info {
264  } lookup_info;
265  
266  /* This magic number is used by the following lookup_module_info structure
267 -   for checking API compatibility. It's equivalent to the string"LMM2" */
268 -#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4d32
269 +   for checking API compatibility. It used to be equivalent to the string"LMM3" */
270 +#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4933
271  /* Version 2 adds: version_report */
272 +/* Version 3 change: non/cache becomes TTL in seconds */
273  
274  typedef struct lookup_module_info {
275    uint magic;
276 diff --git a/src/src/lookups/README b/src/src/lookups/README
277 index 98905dc..31fea64 100644
278 --- a/src/src/lookups/README
279 +++ b/src/src/lookups/README
280 @@ -122,12 +122,15 @@ DEFER. The arguments are:
281    uschar **errmsg     where to put an error message on failure;
282                        this is initially set to "", and should be left
283                        as that for a standard "entry not found" error
284 -  BOOL *do_cache      the lookup should set this to FALSE when it changes data.
285 -                      This is TRUE by default. When set to FALSE the cache tree
286 +  uint *do_cache      the lookup should set this to 0 when it changes data.
287 +                      This is MAXINT by default. When set to 0 the cache tree
288                        of the current search handle will be cleaned and the
289                        current result will NOT be cached. Currently the mysql
290                        and pgsql lookups use this when UPDATE/INSERT queries are
291                        executed.
292 +                      If set to a nonzero number of seconds, the cached value
293 +                      becomes unusable after this time. Currently the dnsdb
294 +                      lookup uses this to support the TTL value.
295  
296  Even though the key is zero-terminated, the length is passed because in the
297  common case it has been computed already and is often needed.
298 diff --git a/src/src/lookups/cdb.c b/src/src/lookups/cdb.c
299 index ea017de..ba925dc 100644
300 --- a/src/src/lookups/cdb.c
301 +++ b/src/src/lookups/cdb.c
302 @@ -279,7 +279,7 @@ cdb_find(void *handle,
303          int  key_len,
304          uschar **result,
305          uschar **errmsg,
306 -        BOOL *do_cache)
307 +        uint *do_cache)
308  {
309    struct cdb_state * cdbp = handle;
310    uint32 item_key_len,
311 diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c
312 index 03248e4..b8c42d5 100644
313 --- a/src/src/lookups/dbmdb.c
314 +++ b/src/src/lookups/dbmdb.c
315 @@ -87,7 +87,7 @@ the keylength in order to include the terminating zero. */
316  
317  static int
318  dbmdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
319 -  uschar **result, uschar **errmsg, BOOL *do_cache)
320 +  uschar **result, uschar **errmsg, uint *do_cache)
321  {
322  EXIM_DB *d = (EXIM_DB *)handle;
323  EXIM_DATUM key, data;
324 @@ -120,7 +120,7 @@ return FAIL;
325  
326  int
327  static dbmnz_find(void *handle, uschar *filename, const uschar *keystring, int length,
328 -  uschar **result, uschar **errmsg, BOOL *do_cache)
329 +  uschar **result, uschar **errmsg, uint *do_cache)
330  {
331  return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
332    do_cache);
333 @@ -140,7 +140,7 @@ return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
334  
335  static int
336  dbmjz_find(void *handle, uschar *filename, const uschar *keystring, int length,
337 -  uschar **result, uschar **errmsg, BOOL *do_cache)
338 +  uschar **result, uschar **errmsg, uint *do_cache)
339  {
340  uschar *key_item, *key_buffer, *key_p;
341  const uschar *key_elems = keystring;
342 diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c
343 index e3de279..70e6c8c 100644
344 --- a/src/src/lookups/dnsdb.c
345 +++ b/src/src/lookups/dnsdb.c
346 @@ -131,7 +131,7 @@ separator, as always, is colon. */
347  
348  static int
349  dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
350 -  uschar **result, uschar **errmsg, BOOL *do_cache)
351 +  uschar **result, uschar **errmsg, uint *do_cache)
352  {
353  int rc;
354  int size = 256;
355 @@ -388,6 +388,9 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
356        {
357        if (rr->type != searchtype) continue;
358  
359 +      if (*do_cache > rr->ttl)
360 +       *do_cache = rr->ttl;
361 +
362        if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
363          {
364          dns_address *da;
365 diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c
366 index f8c592a..9f7dd8d 100644
367 --- a/src/src/lookups/dsearch.c
368 +++ b/src/src/lookups/dsearch.c
369 @@ -67,7 +67,7 @@ for us. */
370  
371  int
372  static dsearch_find(void *handle, uschar *dirname, const uschar *keystring, int length,
373 -  uschar **result, uschar **errmsg, BOOL *do_cache)
374 +  uschar **result, uschar **errmsg, uint *do_cache)
375  {
376  struct stat statbuf;
377  int save_errno;
378 diff --git a/src/src/lookups/ibase.c b/src/src/lookups/ibase.c
379 index 23e1dea..7fd53d0 100644
380 --- a/src/src/lookups/ibase.c
381 +++ b/src/src/lookups/ibase.c
382 @@ -451,7 +451,7 @@ deferred with a retryable error. */
383  
384  static int
385  ibase_find(void *handle, uschar * filename, uschar * query, int length,
386 -           uschar ** result, uschar ** errmsg, BOOL *do_cache)
387 +           uschar ** result, uschar ** errmsg, uint *do_cache)
388  {
389      int sep = 0;
390      uschar *server;
391 diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c
392 index a56eff3..b870df1 100644
393 --- a/src/src/lookups/ldap.c
394 +++ b/src/src/lookups/ldap.c
395 @@ -1339,7 +1339,7 @@ The handle and filename arguments are not used. */
396  
397  static int
398  eldap_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
399 -  uschar **result, uschar **errmsg, BOOL *do_cache)
400 +  uschar **result, uschar **errmsg, uint *do_cache)
401  {
402  /* Keep picky compilers happy */
403  do_cache = do_cache;
404 @@ -1348,7 +1348,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
405  
406  static int
407  eldapm_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
408 -  uschar **result, uschar **errmsg, BOOL *do_cache)
409 +  uschar **result, uschar **errmsg, uint *do_cache)
410  {
411  /* Keep picky compilers happy */
412  do_cache = do_cache;
413 @@ -1357,7 +1357,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
414  
415  static int
416  eldapdn_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
417 -  uschar **result, uschar **errmsg, BOOL *do_cache)
418 +  uschar **result, uschar **errmsg, uint *do_cache)
419  {
420  /* Keep picky compilers happy */
421  do_cache = do_cache;
422 @@ -1366,7 +1366,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
423  
424  int
425  eldapauth_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
426 -  uschar **result, uschar **errmsg, BOOL *do_cache)
427 +  uschar **result, uschar **errmsg, uint *do_cache)
428  {
429  /* Keep picky compilers happy */
430  do_cache = do_cache;
431 diff --git a/src/src/lookups/lf_functions.h b/src/src/lookups/lf_functions.h
432 index 73e9303..d2487d3 100644
433 --- a/src/src/lookups/lf_functions.h
434 +++ b/src/src/lookups/lf_functions.h
435 @@ -12,7 +12,7 @@ extern int     lf_check_file(int, uschar *, int, int, uid_t *, gid_t *,
436  extern uschar *lf_quote(uschar *, uschar *, int, uschar *, int *, int *);
437  extern int     lf_sqlperform(const uschar *, const uschar *, const uschar *,
438                  const uschar *, uschar **,
439 -                 uschar **, BOOL *, int(*)(const uschar *, uschar *, uschar **,
440 -                 uschar **, BOOL *, BOOL *));
441 +                 uschar **, uint *, int(*)(const uschar *, uschar *, uschar **,
442 +                 uschar **, BOOL *, uint *));
443  
444  /* End of lf_functions.h */
445 diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c
446 index 2d7f326..6d4f7a7 100644
447 --- a/src/src/lookups/lf_sqlperform.c
448 +++ b/src/src/lookups/lf_sqlperform.c
449 @@ -27,7 +27,7 @@ Arguments:
450    query          the query
451    result         where to pass back the result
452    errmsg         where to pass back an error message
453 -  do_cache       to be set FALSE if data is changed
454 +  do_cache       to be set zero if data is changed
455    func           the lookup function to call
456  
457  Returns:         the return from the lookup function, or DEFER
458 @@ -36,8 +36,8 @@ Returns:         the return from the lookup function, or DEFER
459  int
460  lf_sqlperform(const uschar *name, const uschar *optionname,
461    const uschar *optserverlist, const uschar *query,
462 -  uschar **result, uschar **errmsg, BOOL *do_cache,
463 -  int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, BOOL *))
464 +  uschar **result, uschar **errmsg, uint *do_cache,
465 +  int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *))
466  {
467  int sep, rc;
468  uschar *server;
469 diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c
470 index 3883d4b..eb70a45 100644
471 --- a/src/src/lookups/lsearch.c
472 +++ b/src/src/lookups/lsearch.c
473 @@ -323,7 +323,7 @@ return FAIL;
474  
475  static int
476  lsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
477 -  uschar **result, uschar **errmsg, BOOL *do_cache)
478 +  uschar **result, uschar **errmsg, uint *do_cache)
479  {
480  do_cache = do_cache;  /* Keep picky compilers happy */
481  return internal_lsearch_find(handle, filename, keystring, length, result,
482 @@ -340,7 +340,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
483  
484  static int
485  wildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
486 -  uschar **result, uschar **errmsg, BOOL *do_cache)
487 +  uschar **result, uschar **errmsg, uint *do_cache)
488  {
489  do_cache = do_cache;  /* Keep picky compilers happy */
490  return internal_lsearch_find(handle, filename, keystring, length, result,
491 @@ -357,7 +357,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
492  
493  static int
494  nwildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
495 -  uschar **result, uschar **errmsg, BOOL *do_cache)
496 +  uschar **result, uschar **errmsg, uint *do_cache)
497  {
498  do_cache = do_cache;  /* Keep picky compilers happy */
499  return internal_lsearch_find(handle, filename, keystring, length, result,
500 @@ -375,7 +375,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
501  
502  static int
503  iplsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
504 -  uschar **result, uschar **errmsg, BOOL *do_cache)
505 +  uschar **result, uschar **errmsg, uint *do_cache)
506  {
507  do_cache = do_cache;  /* Keep picky compilers happy */
508  if ((length == 1 && keystring[0] == '*') ||
509 diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c
510 index 8dff86a..1ce8831 100644
511 --- a/src/src/lookups/mysql.c
512 +++ b/src/src/lookups/mysql.c
513 @@ -74,7 +74,7 @@ Arguments:
514    resultptr    where to store the result
515    errmsg       where to point an error message
516    defer_break  TRUE if no more servers are to be tried after DEFER
517 -  do_cache     set false if data is changed
518 +  do_cache     set zero if data is changed
519  
520  The server string is of the form "host/dbname/user/password". The host can be
521  host:port. This string is in a nextinlist temporary buffer, so can be
522 @@ -85,7 +85,7 @@ Returns:       OK, FAIL, or DEFER
523  
524  static int
525  perform_mysql_search(const uschar *query, uschar *server, uschar **resultptr,
526 -  uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
527 +  uschar **errmsg, BOOL *defer_break, uint *do_cache)
528  {
529  MYSQL *mysql_handle = NULL;        /* Keep compilers happy */
530  MYSQL_RES *mysql_result = NULL;
531 @@ -225,7 +225,7 @@ can be detected by calling mysql_field_count(). If its result is zero, no data
532  was expected (this is all explained clearly in the MySQL manual). In this case,
533  we return the number of rows affected by the command. In this event, we do NOT
534  want to cache the result; also the whole cache for the handle must be cleaned
535 -up. Setting do_cache FALSE requests this. */
536 +up. Setting do_cache zero requests this. */
537  
538  if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
539    {
540 @@ -233,7 +233,7 @@ if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
541      {
542      DEBUG(D_lookup) debug_printf("MYSQL: query was not one that returns data\n");
543      result = string_sprintf("%d", mysql_affected_rows(mysql_handle));
544 -    *do_cache = FALSE;
545 +    *do_cache = 0;
546      goto MYSQL_EXIT;
547      }
548    *errmsg = string_sprintf("MYSQL: lookup result failed: %s\n",
549 @@ -341,7 +341,7 @@ shared with other SQL lookups. */
550  
551  static int
552  mysql_find(void *handle, uschar *filename, const uschar *query, int length,
553 -  uschar **result, uschar **errmsg, BOOL *do_cache)
554 +  uschar **result, uschar **errmsg, uint *do_cache)
555  {
556  return lf_sqlperform(US"MySQL", US"mysql_servers", mysql_servers, query,
557    result, errmsg, do_cache, perform_mysql_search);
558 diff --git a/src/src/lookups/nis.c b/src/src/lookups/nis.c
559 index 7b012b1..1faa884 100644
560 --- a/src/src/lookups/nis.c
561 +++ b/src/src/lookups/nis.c
562 @@ -42,7 +42,7 @@ code. */
563  
564  static int
565  nis_find(void *handle, uschar *filename, uschar *keystring, int length,
566 -  uschar **result, uschar **errmsg, BOOL *do_cache)
567 +  uschar **result, uschar **errmsg, uint *do_cache)
568  {
569  int rc;
570  uschar *nis_data;
571 @@ -68,7 +68,7 @@ return (rc == YPERR_KEY || rc == YPERR_MAP)? FAIL : DEFER;
572  
573  static int
574  nis0_find(void *handle, uschar *filename, uschar *keystring, int length,
575 -  uschar **result, uschar **errmsg, BOOL *do_cache)
576 +  uschar **result, uschar **errmsg, uint *do_cache)
577  {
578  int rc;
579  uschar *nis_data;
580 diff --git a/src/src/lookups/nisplus.c b/src/src/lookups/nisplus.c
581 index 8895cee..a4a7a2d 100644
582 --- a/src/src/lookups/nisplus.c
583 +++ b/src/src/lookups/nisplus.c
584 @@ -43,7 +43,7 @@ equals sign. */
585  
586  static int
587  nisplus_find(void *handle, uschar *filename, uschar *query, int length,
588 -  uschar **result, uschar **errmsg, BOOL *do_cache)
589 +  uschar **result, uschar **errmsg, uint *do_cache)
590  {
591  int i;
592  int ssize = 0;
593 diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c
594 index 1f2520a..adb17b4 100644
595 --- a/src/src/lookups/oracle.c
596 +++ b/src/src/lookups/oracle.c
597 @@ -517,7 +517,7 @@ deferred with a retryable error. */
598  
599  static int
600  oracle_find(void *handle, uschar *filename, uschar *query, int length,
601 -  uschar **result, uschar **errmsg, BOOL *do_cache)
602 +  uschar **result, uschar **errmsg, uint *do_cache)
603  {
604  int sep = 0;
605  uschar *server;
606 diff --git a/src/src/lookups/passwd.c b/src/src/lookups/passwd.c
607 index e726f3e..315677f 100644
608 --- a/src/src/lookups/passwd.c
609 +++ b/src/src/lookups/passwd.c
610 @@ -34,7 +34,7 @@ return (void *)(-1);     /* Just return something non-null */
611  
612  static int
613  passwd_find(void *handle, uschar *filename, const uschar *keystring, int length,
614 -  uschar **result, uschar **errmsg, BOOL *do_cache)
615 +  uschar **result, uschar **errmsg, uint *do_cache)
616  {
617  struct passwd *pw;
618  
619 diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c
620 index c86ac23..4be3d98 100644
621 --- a/src/src/lookups/pgsql.c
622 +++ b/src/src/lookups/pgsql.c
623 @@ -119,7 +119,7 @@ Returns:       OK, FAIL, or DEFER
624  
625  static int
626  perform_pgsql_search(const uschar *query, uschar *server, uschar **resultptr,
627 -  uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
628 +  uschar **errmsg, BOOL *defer_break, uint *do_cache)
629  {
630  PGconn *pg_conn = NULL;
631  PGresult *pg_result = NULL;
632 @@ -290,10 +290,10 @@ else
633      /* The command was successful but did not return any data since it was
634       * not SELECT but either an INSERT, UPDATE or DELETE statement. Tell the
635       * high level code to not cache this query, and clean the current cache for
636 -     * this handle by setting *do_cache FALSE. */
637 +     * this handle by setting *do_cache zero. */
638      result = string_copy(US PQcmdTuples(pg_result));
639      offset = Ustrlen(result);
640 -    *do_cache = FALSE;
641 +    *do_cache = 0;
642      DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data "
643        "but was successful. Rows affected: %s\n", result);
644  
645 @@ -399,7 +399,7 @@ shared with other SQL lookups. */
646  
647  static int
648  pgsql_find(void *handle, uschar *filename, const uschar *query, int length,
649 -  uschar **result, uschar **errmsg, BOOL *do_cache)
650 +  uschar **result, uschar **errmsg, uint *do_cache)
651  {
652  return lf_sqlperform(US"PostgreSQL", US"pgsql_servers", pgsql_servers, query,
653    result, errmsg, do_cache, perform_pgsql_search);
654 diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c
655 index ac4d0ec..18cd3a0 100644
656 --- a/src/src/lookups/redis.c
657 +++ b/src/src/lookups/redis.c
658 @@ -65,7 +65,7 @@ redis_tidy(void)
659   */
660  static int
661  perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
662 -  uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
663 +  uschar **errmsg, BOOL *defer_break, uint *do_cache)
664  {
665         redisContext *redis_handle = NULL;        /* Keep compilers happy */
666         redisReply *redis_reply = NULL;
667 @@ -197,7 +197,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
668         case REDIS_REPLY_ERROR:
669                 *errmsg = string_sprintf("REDIS: lookup result failed: %s\n", redis_reply->str);
670                 *defer_break = FALSE;
671 -               *do_cache = FALSE;
672 +               *do_cache = 0;
673                 goto REDIS_EXIT;
674                 /* NOTREACHED */
675  
676 @@ -205,7 +205,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
677         case REDIS_REPLY_NIL:
678                 DEBUG(D_lookup) debug_printf("REDIS: query was not one that returned any data\n");
679                 result = string_sprintf("");
680 -               *do_cache = FALSE;
681 +               *do_cache = 0;
682                 goto REDIS_EXIT;
683                 /* NOTREACHED */
684  
685 @@ -304,7 +304,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
686  
687  static int
688  redis_find(void *handle __attribute__((unused)), uschar *filename __attribute__((unused)),
689 -           uschar *command, int length, uschar **result, uschar **errmsg, BOOL *do_cache)
690 +           uschar *command, int length, uschar **result, uschar **errmsg, uint *do_cache)
691  {
692         return lf_sqlperform(US"Redis", US"redis_servers", redis_servers, command,
693           result, errmsg, do_cache, perform_redis_search);
694 diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c
695 index 23ad2ad..2671fc9 100644
696 --- a/src/src/lookups/spf.c
697 +++ b/src/src/lookups/spf.c
698 @@ -31,7 +31,9 @@ static void dummy(int x) { dummy2(x-1); }
699  #include <spf2/spf_dns_resolv.h>
700  #include <spf2/spf_dns_cache.h>
701  
702 -static void *spf_open(uschar *filename, uschar **errmsg) {
703 +static void *
704 +spf_open(uschar *filename, uschar **errmsg)
705 +{
706    SPF_server_t *spf_server = NULL;
707    spf_server = SPF_server_new(SPF_DNS_CACHE, 0);
708    if (spf_server == NULL) {
709 @@ -41,13 +43,17 @@ static void *spf_open(uschar *filename, uschar **errmsg) {
710    return (void *) spf_server;
711  }
712  
713 -static void spf_close(void *handle) {
714 +static void
715 +spf_close(void *handle)
716 +{
717    SPF_server_t *spf_server = handle;
718    if (spf_server) SPF_server_free(spf_server);
719  }
720  
721 -static int spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
722 -             uschar **result, uschar **errmsg, BOOL *do_cache) {
723 +static int
724 +spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
725 +             uschar **result, uschar **errmsg, uint *do_cache)
726 +{
727    SPF_server_t *spf_server = handle;
728    SPF_request_t *spf_request = NULL;
729    SPF_response_t *spf_response = NULL;
730 diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c
731 index bb92c8c..e2330f9 100644
732 --- a/src/src/lookups/sqlite.c
733 +++ b/src/src/lookups/sqlite.c
734 @@ -81,7 +81,7 @@ return 0;
735  
736  static int
737  sqlite_find(void *handle, uschar *filename, const uschar *query, int length,
738 -  uschar **result, uschar **errmsg, BOOL *do_cache)
739 +  uschar **result, uschar **errmsg, uint *do_cache)
740  {
741  int ret;
742  struct strbuf res = { NULL, 0, 0 };
743 @@ -93,7 +93,7 @@ if (ret != SQLITE_OK)
744    return FAIL;
745    }
746  
747 -if (res.string == NULL) *do_cache = FALSE;
748 +if (res.string == NULL) *do_cache = 0;
749  
750  *result = res.string;
751  return OK;
752 diff --git a/src/src/lookups/testdb.c b/src/src/lookups/testdb.c
753 index c82fa7f..401f7c8 100644
754 --- a/src/src/lookups/testdb.c
755 +++ b/src/src/lookups/testdb.c
756 @@ -38,7 +38,7 @@ return (void *)(1);    /* Just return something non-null */
757  
758  static int
759  testdb_find(void *handle, uschar *filename, const uschar *query, int length,
760 -  uschar **result, uschar **errmsg, BOOL *do_cache)
761 +  uschar **result, uschar **errmsg, uint *do_cache)
762  {
763  handle = handle;          /* Keep picky compilers happy */
764  filename = filename;
765 @@ -57,7 +57,7 @@ if (Ustrcmp(query, "defer") == 0)
766    return DEFER;
767    }
768  
769 -if (Ustrcmp(query, "nocache") == 0) *do_cache = FALSE;
770 +if (Ustrcmp(query, "nocache") == 0) *do_cache = 0;
771  
772  *result = string_copy(query);
773  return OK;
774 diff --git a/src/src/lookups/whoson.c b/src/src/lookups/whoson.c
775 index 4166089..9ac5a3a 100644
776 --- a/src/src/lookups/whoson.c
777 +++ b/src/src/lookups/whoson.c
778 @@ -36,7 +36,7 @@ return (void *)(1);    /* Just return something non-null */
779  
780  static int
781  whoson_find(void *handle, uschar *filename, uschar *query, int length,
782 -  uschar **result, uschar **errmsg, BOOL *do_cache)
783 +  uschar **result, uschar **errmsg, uint *do_cache)
784  {
785  uschar buffer[80];
786  handle = handle;          /* Keep picky compilers happy */
787 diff --git a/src/src/search.c b/src/src/search.c
788 index a055291..cd522da 100644
789 --- a/src/src/search.c
790 +++ b/src/src/search.c
791 @@ -466,6 +466,7 @@ internal_search_find(void *handle, uschar *filename, uschar *keystring)
792  {
793  tree_node *t = (tree_node *)handle;
794  search_cache *c = (search_cache *)(t->data.ptr);
795 +expiring_data *e;
796  uschar *data = NULL;
797  int search_type = t->name[0] - '0';
798  int old_pool = store_pool;
799 @@ -491,18 +492,27 @@ store_pool = POOL_SEARCH;
800  /* Look up the data for the key, unless it is already in the cache for this
801  file. No need to check c->item_cache for NULL, tree_search will do so. */
802  
803 -if ((t = tree_search(c->item_cache, keystring)) == NULL)
804 +if (  (t = tree_search(c->item_cache, keystring))
805 +   && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
806 +   )
807 +  { /* Data was in the cache already; set the pointer from the tree node */
808 +  data = e->ptr;
809 +  DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
810 +    keystring,
811 +    filename ? US"\n  in " : US"", filename ? filename : US"");
812 +  }
813 +else
814    {
815 -  BOOL do_cache = TRUE;
816 +  uint do_cache = UINT_MAX;
817    int keylength = Ustrlen(keystring);
818  
819    DEBUG(D_lookup)
820      {
821 -    if (filename != NULL)
822 -      debug_printf("file lookup required for %s\n  in %s\n",
823 -        keystring, filename);
824 -    else
825 -      debug_printf("database lookup required for %s\n", keystring);
826 +    if (t) debug_printf("cached data found but past valid time; ");
827 +    debug_printf("%s lookup required for %s%s%s\n",
828 +      filename ? US"file" : US"database",
829 +      keystring,
830 +      filename ? US"\n  in " : US"", filename ? filename : US"");
831      }
832  
833    /* Call the code for the different kinds of search. DEFER is handled
834 @@ -511,9 +521,7 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
835  
836    if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
837        &data, &search_error_message, &do_cache) == DEFER)
838 -    {
839      search_find_defer = TRUE;
840 -    }
841  
842    /* A record that has been found is now in data, which is either NULL
843    or points to a bit of dynamic store. Cache the result of the lookup if
844 @@ -524,10 +532,22 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
845    else if (do_cache)
846      {
847      int len = keylength + 1;
848 -    t = store_get(sizeof(tree_node) + len);
849 -    memcpy(t->name, keystring, len);
850 -    t->data.ptr = data;
851 -    tree_insertnode(&c->item_cache, t);
852 +
853 +    if (t)     /* Previous, out-of-date cache entry.  Update with the */
854 +      {        /* new result and forget the old one */
855 +      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
856 +      e->ptr = data;
857 +      }
858 +    else
859 +      {
860 +      t = store_get(sizeof(tree_node) + len + sizeof(expiring_data));
861 +      e = (expiring_data *)((char *)t + sizeof(tree_node) + len);
862 +      e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
863 +      e->ptr = data;
864 +      memcpy(t->name, keystring, len);
865 +      t->data.ptr = e;
866 +      tree_insertnode(&c->item_cache, t);
867 +      }
868      }
869  
870    /* If caching was disabled, empty the cache tree. We just set the cache
871 @@ -540,34 +560,19 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
872      }
873    }
874  
875 -/* Data was in the cache already; set the pointer from the tree node */
876 -
877 -else
878 -  {
879 -  data = US t->data.ptr;
880 -  DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
881 -    keystring,
882 -    (filename == NULL)? US"" : US"\n  in ",
883 -    (filename == NULL)? US"" : filename);
884 -  }
885 -
886 -/* Debug: output the answer */
887 -
888  DEBUG(D_lookup)
889    {
890 -  if (data == NULL)
891 -    {
892 -    if (search_find_defer) debug_printf("lookup deferred: %s\n",
893 -      search_error_message);
894 -    else debug_printf("lookup failed\n");
895 -    }
896 -  else debug_printf("lookup yielded: %s\n", data);
897 +  if (data)
898 +    debug_printf("lookup yielded: %s\n", data);
899 +  else if (search_find_defer)
900 +    debug_printf("lookup deferred: %s\n", search_error_message);
901 +  else debug_printf("lookup failed\n");
902    }
903  
904  /* Return it in new dynamic store in the regular pool */
905  
906  store_pool = old_pool;
907 -return (data == NULL)? NULL : string_copy(data);
908 +return data ? string_copy(data) : NULL;
909  }
910  
911  
912 diff --git a/src/src/structs.h b/src/src/structs.h
913 index 6f143d6..d9da38b 100644
914 --- a/src/src/structs.h
915 +++ b/src/src/structs.h
916 @@ -657,6 +657,16 @@ typedef struct tree_node {
917    uschar  name[1];                /* node name - variable length */
918  } tree_node;
919  
920 +/* Structure for holding time-limited data such as DNS returns.
921 +We use this rather than extending tree_node to avoid wasting
922 +space for most tree use (variables...) at the cost of complexity
923 +for the lookups cache */
924 +
925 +typedef struct expiring_data {
926 +  time_t expiry;                 /* if nonzero, data invalid after this time */
927 +  void   *ptr;                   /* pointer to data */
928 +} expiring_data;
929 +
930  /* Structure for holding the handle and the cached last lookup for searches.
931  This block is pointed to by the tree entry for the file. The file can get
932  closed if too many are opened at once. There is a LRU chain for deciding which
933 @@ -676,6 +686,7 @@ uncompressed, but the data pointer is into the raw data. */
934  typedef struct {
935    uschar  name[DNS_MAXNAME];      /* domain name */
936    int     type;                   /* record type */
937 +  unsigned short ttl;            /* time-to-live, seconds */
938    int     size;                   /* size of data */
939    uschar *data;                   /* pointer to data */
940  } dns_record;
941 diff --git a/src/src/verify.c b/src/src/verify.c
942 index e00e7b9..d392fda 100644
943 --- a/src/src/verify.c
944 +++ b/src/src/verify.c
945 @@ -21,6 +21,7 @@ uschar ctbuffer[8192];
946  /* Structure for caching DNSBL lookups */
947  
948  typedef struct dnsbl_cache_block {
949 +  time_t expiry;
950    dns_address *rhs;
951    uschar *text;
952    int rc;
953 @@ -3584,21 +3585,37 @@ if (!string_format(query, sizeof(query), "%s.%s", prepend, domain))
954  
955  /* Look for this query in the cache. */
956  
957 -t = tree_search(dnsbl_cache, query);
958 +if (  (t = tree_search(dnsbl_cache, query))
959 +   && (cb = t->data.ptr)->expiry > time(NULL)
960 +   )
961 +
962 +/* Previous lookup was cached */
963 +
964 +  {
965 +  HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
966 +  }
967  
968  /* If not cached from a previous lookup, we must do a DNS lookup, and
969  cache the result in permanent memory. */
970  
971 -if (t == NULL)
972 +else
973    {
974 +  uint ttl = 3600;
975 +
976    store_pool = POOL_PERM;
977  
978 -  /* Set up a tree entry to cache the lookup */
979 +  if (t)
980 +    {
981 +    HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
982 +    }
983  
984 -  t = store_get(sizeof(tree_node) + Ustrlen(query));
985 -  Ustrcpy(t->name, query);
986 -  t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
987 -  (void)tree_insertnode(&dnsbl_cache, t);
988 +  else
989 +    {  /* Set up a tree entry to cache the lookup */
990 +    t = store_get(sizeof(tree_node) + Ustrlen(query));
991 +    Ustrcpy(t->name, query);
992 +    t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
993 +    (void)tree_insertnode(&dnsbl_cache, t);
994 +    }
995  
996    /* Do the DNS loopup . */
997  
998 @@ -3616,7 +3633,10 @@ if (t == NULL)
999  
1000    Quite apart from one A6 RR generating multiple addresses, there are DNS
1001    lists that return more than one A record, so we must handle multiple
1002 -  addresses generated in that way as well. */
1003 +  addresses generated in that way as well.
1004 +
1005 +  Mark the cache entry with the "now" plus the minimum of the address TTLs,
1006 +  or some suitably far-future time if none were found. */
1007  
1008    if (cb->rc == DNS_SUCCEED)
1009      {
1010 @@ -3634,6 +3654,7 @@ if (t == NULL)
1011            *addrp = da;
1012            while (da->next != NULL) da = da->next;
1013            addrp = &(da->next);
1014 +         if (ttl > rr->ttl) ttl = rr->ttl;
1015            }
1016          }
1017        }
1018 @@ -3645,17 +3666,10 @@ if (t == NULL)
1019      if (cb->rhs == NULL) cb->rc = DNS_NODATA;
1020      }
1021  
1022 +  cb->expiry = time(NULL)+ttl;
1023    store_pool = old_pool;
1024    }
1025  
1026 -/* Previous lookup was cached */
1027 -
1028 -else
1029 -  {
1030 -  HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
1031 -  cb = t->data.ptr;
1032 -  }
1033 -
1034  /* We now have the result of the DNS lookup, either newly done, or cached
1035  from a previous call. If the lookup succeeded, check against the address
1036  list if there is one. This may be a positive equality list (introduced by
1037
1038 commit c4dcf906ceb3a45c6b30f76476d73ca836b262cd
1039 Author: Jeremy Harris <jgh146exb@wizmail.org>
1040 Date:   Sat Sep 19 13:59:22 2015 +0100
1041
1042     Retry: always use interface, if set, for retry DB key.  Bug 1678
1043     
1044     Even constant values must be used, as multiple transports with
1045     different values may be in play and should be kept distinct.
1046     
1047     (cherry picked from commit 6f6dedccb47f231a0712d882da20feffbac8d0bc)
1048
1049 diff --git a/src/src/functions.h b/src/src/functions.h
1050 index 0257904..94e3f5f 100644
1051 --- a/src/src/functions.h
1052 +++ b/src/src/functions.h
1053 @@ -374,7 +374,7 @@ extern int     smtp_sock_connect(host_item *, int, int, uschar *,
1054  extern int     smtp_feof(void);
1055  extern int     smtp_ferror(void);
1056  extern uschar *smtp_get_connection_info(void);
1057 -extern BOOL    smtp_get_interface(uschar *, int, address_item *, BOOL *,
1058 +extern BOOL    smtp_get_interface(uschar *, int, address_item *,
1059                   uschar **, uschar *);
1060  extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
1061  extern int     smtp_getc(void);
1062 diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
1063 index c704a0b..2fdf38b 100644
1064 --- a/src/src/smtp_out.c
1065 +++ b/src/src/smtp_out.c
1066 @@ -26,7 +26,6 @@ Arguments:
1067                 which case the function does nothing
1068    host_af    AF_INET or AF_INET6 for the outgoing IP address
1069    addr       the mail address being handled (for setting errors)
1070 -  changed    if not NULL, set TRUE if expansion actually changed istring
1071    interface  point this to the interface
1072    msg        to add to any error message
1073  
1074 @@ -36,7 +35,7 @@ Returns:     TRUE on success, FALSE on failure, with error message
1075  
1076  BOOL
1077  smtp_get_interface(uschar *istring, int host_af, address_item *addr,
1078 -  BOOL *changed, uschar **interface, uschar *msg)
1079 +  uschar **interface, uschar *msg)
1080  {
1081  const uschar * expint;
1082  uschar *iface;
1083 @@ -54,8 +53,6 @@ if (expint == NULL)
1084    return FALSE;
1085    }
1086  
1087 -if (changed != NULL) *changed = expint != istring;
1088 -
1089  while (isspace(*expint)) expint++;
1090  if (*expint == 0) return TRUE;
1091  
1092 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
1093 index 5ac5533..ba7fb5e 100644
1094 --- a/src/src/transports/smtp.c
1095 +++ b/src/src/transports/smtp.c
1096 @@ -3174,7 +3174,6 @@ for (cutoff_retry = 0; expired &&
1097      BOOL serialized = FALSE;
1098      BOOL host_is_expired = FALSE;
1099      BOOL message_defer = FALSE;
1100 -    BOOL ifchanges = FALSE;
1101      BOOL some_deferred = FALSE;
1102      address_item *first_addr = NULL;
1103      uschar *interface = NULL;
1104 @@ -3350,15 +3349,18 @@ for (cutoff_retry = 0; expired &&
1105      if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
1106  
1107      /* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
1108 -    string changes upon expansion, we must add it to the key that is used for
1109 -    retries, because connections to the same host from a different interface
1110 -    should be treated separately. */
1111 +    string is set, even if constant (as different transports can have different
1112 +    constant settings), we must add it to the key that is used for retries,
1113 +    because connections to the same host from a different interface should be
1114 +    treated separately. */
1115  
1116      host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET : AF_INET6;
1117 -    if (!smtp_get_interface(ob->interface, host_af, addrlist, &ifchanges,
1118 -         &interface, tid))
1119 -      return FALSE;
1120 -    if (ifchanges) pistring = string_sprintf("%s/%s", pistring, interface);
1121 +    if ((rs = ob->interface) && *rs)
1122 +      {
1123 +      if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid))
1124 +       return FALSE;
1125 +      pistring = string_sprintf("%s/%s", pistring, interface);
1126 +      }
1127  
1128      /* The first time round the outer loop, check the status of the host by
1129      inspecting the retry data. The second time round, we are interested only
1130 diff --git a/src/src/verify.c b/src/src/verify.c
1131 index d392fda..6411c7e 100644
1132 --- a/src/src/verify.c
1133 +++ b/src/src/verify.c
1134 @@ -444,7 +444,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
1135  
1136           host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
1137  
1138 -         if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
1139 +         if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
1140                   US"callout") ||
1141               !smtp_get_port(tf->port, addr, &port, US"callout"))
1142             log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
1143 @@ -579,7 +579,7 @@ can do it there for the non-rcpt-verify case.  For this we keep an addresscount.
1144      deliver_domain = addr->domain;
1145      transport_name = addr->transport->name;
1146  
1147 -    if (  !smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
1148 +    if (  !smtp_get_interface(tf->interface, host_af, addr, &interface,
1149              US"callout")
1150         || !smtp_get_port(tf->port, addr, &port, US"callout")
1151         )
1152
1153 commit 1bd52978055bc07dfa150d296ffb344f10fff7fe
1154 Author: Jeremy Harris <jgh146exb@wizmail.org>
1155 Date:   Mon Nov 2 19:03:26 2015 +0000
1156
1157     Avoid misaligned access in cached lookup.  Bug 1708
1158     
1159     (cherry picked from commit 98b98887f926be87eabccc7919e57ce625c63c03)
1160
1161 diff --git a/src/src/search.c b/src/src/search.c
1162 index cd522da..ccad250 100644
1163 --- a/src/src/search.c
1164 +++ b/src/src/search.c
1165 @@ -540,10 +540,10 @@ else
1166        }
1167      else
1168        {
1169 -      t = store_get(sizeof(tree_node) + len + sizeof(expiring_data));
1170 -      e = (expiring_data *)((char *)t + sizeof(tree_node) + len);
1171 +      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len);
1172        e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
1173        e->ptr = data;
1174 +      t = (tree_node *)(e+1);
1175        memcpy(t->name, keystring, len);
1176        t->data.ptr = e;
1177        tree_insertnode(&c->item_cache, t);
1178
1179 commit e7c3de301824738c6f302e02e566f9da75d3130c
1180 Author: Jeremy Harris <jgh146exb@wizmail.org>
1181 Date:   Thu Oct 15 21:40:17 2015 +0100
1182
1183     DKIM: ignore space & tab embedded in base64 during decode.  Bug 1700
1184     
1185     (cherry picked from commit 0f557e9065b0bcfce38ee1fea5fc947bf0c5431c)
1186
1187 diff --git a/src/src/pdkim/base64.c b/src/src/pdkim/base64.c
1188 index a82fc2d..1395be4 100644
1189 --- a/src/src/pdkim/base64.c
1190 +++ b/src/src/pdkim/base64.c
1191 @@ -128,20 +128,22 @@ int base64_decode( unsigned char *dst, int *dlen,
1192  
1193      for( i = j = n = 0; i < slen; i++ )
1194      {
1195 +       unsigned char c = src[i];
1196 +
1197          if( ( slen - i ) >= 2 &&
1198 -            src[i] == '\r' && src[i + 1] == '\n' )
1199 +            c == '\r' && src[i + 1] == '\n' )
1200              continue;
1201  
1202 -        if( src[i] == '\n' )
1203 +        if( c == '\n' || c == ' ' || c == '\t' )
1204              continue;
1205  
1206 -        if( src[i] == '=' && ++j > 2 )
1207 +        if( c == '=' && ++j > 2 )
1208              return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
1209  
1210 -        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
1211 +        if( c > 127 || base64_dec_map[src[i]] == 127 )
1212              return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
1213  
1214 -        if( base64_dec_map[src[i]] < 64 && j != 0 )
1215 +        if( base64_dec_map[c] < 64 && j != 0 )
1216              return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
1217  
1218          n++;
1219 @@ -160,11 +162,13 @@ int base64_decode( unsigned char *dst, int *dlen,
1220  
1221     for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
1222     {
1223 -        if( *src == '\r' || *src == '\n' )
1224 +       unsigned char c = *src;
1225 +
1226 +        if( c == '\r' || c == '\n' || c == ' ' || c == '\t' )
1227              continue;
1228  
1229 -        j -= ( base64_dec_map[*src] == 64 );
1230 -        x  = (x << 6) | ( base64_dec_map[*src] & 0x3F );
1231 +        j -= ( base64_dec_map[c] == 64 );
1232 +        x  = (x << 6) | ( base64_dec_map[c] & 0x3F );
1233  
1234          if( ++n == 4 )
1235          {
1236
1237 commit a23a9d099ac9d112a6d961e00539bcf1bbb1ef7e
1238 Author: Jeremy Harris <jgh146exb@wizmail.org>
1239 Date:   Wed Nov 25 17:49:03 2015 +0000
1240
1241     MIME: fix crash on filenames having null charset.  Bug 1730
1242     
1243     (cherry picked from commit 622dbd6a512d2c7786125e3b80e96a43e54b8e90)
1244
1245 diff --git a/src/src/mime.c b/src/src/mime.c
1246 index 618364a..cc9ffb7 100644
1247 --- a/src/src/mime.c
1248 +++ b/src/src/mime.c
1249 @@ -550,7 +550,8 @@ int size = 0, ptr = 0;
1250  uschar * val = string_cat(NULL, &size, &ptr, US"=?", 2);
1251  uschar c;
1252  
1253 -val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
1254 +if (charset)
1255 +  val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
1256  val = string_cat(val, &size, &ptr, US"?Q?", 3);
1257  
1258  while ((c = *fname))
1259 @@ -607,7 +608,7 @@ while(1)
1260      if (!fgets(CS header, MIME_MAX_HEADER_SIZE, f))
1261        {
1262        /* Hit EOF or read error. Ugh. */
1263 -      DEBUG(D_acl) debug_printf("Hit EOF ...\n");
1264 +      DEBUG(D_acl) debug_printf("MIME: Hit EOF ...\n");
1265        return rc;
1266        }
1267  
1268 @@ -619,12 +620,12 @@ while(1)
1269        if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
1270         {
1271         /* END boundary found */
1272 -       DEBUG(D_acl) debug_printf("End boundary found %s\n",
1273 +       DEBUG(D_acl) debug_printf("MIME: End boundary found %s\n",
1274           context->boundary);
1275         return rc;
1276         }
1277  
1278 -      DEBUG(D_acl) debug_printf("Next part with boundary %s\n",
1279 +      DEBUG(D_acl) debug_printf("MIME: Next part with boundary %s\n",
1280         context->boundary);
1281        break;
1282        }
1283 @@ -648,7 +649,7 @@ while(1)
1284  
1285        for (q = p; *q != ';' && *q; q++) ;
1286        *mh->value = string_copynlc(p, q-p);
1287 -      DEBUG(D_acl) debug_printf("found %s MIME header, value is '%s'\n",
1288 +      DEBUG(D_acl) debug_printf("MIME: found %s header, value is '%s'\n",
1289         mh->name, *mh->value);
1290  
1291        if (*(p = q)) p++;                       /* jump past the ; */
1292 @@ -666,7 +667,7 @@ while(1)
1293           {
1294           mime_parameter * mp;
1295  
1296 -         DEBUG(D_acl) debug_printf("  considering paramlist '%s'\n", p);
1297 +         DEBUG(D_acl) debug_printf("MIME:   considering paramlist '%s'\n", p);
1298  
1299           if (  !mime_filename
1300              && strncmpic(CUS"content-disposition:", header, 20) == 0
1301 @@ -700,22 +701,27 @@ while(1)
1302                   uschar * s = q;
1303  
1304                   /* look for a ' in the "filename" */
1305 -                 while(*s != '\'' && *s) s++;  /* s is ' or NUL */
1306 +                 while(*s != '\'' && *s) s++;  /* s is 1st ' or NUL */
1307  
1308                   if ((size = s-q) > 0)
1309 -                   {
1310                     mime_filename_charset = string_copyn(q, size);
1311 -                   p = s;
1312  
1313 -                   while(*p == '\'' && *p) p++; /* p is after ' */
1314 -                   }
1315 +                 if (*(p = s)) p++;
1316 +                 while(*p == '\'') p++;        /* p is after 2nd ' */
1317                   }
1318                 else
1319                   p = q;
1320  
1321 +               DEBUG(D_acl) debug_printf("MIME:    charset %s fname '%s'\n",
1322 +                 mime_filename_charset ? mime_filename_charset : US"<NULL>", p);
1323 +
1324                 temp_string = rfc2231_to_2047(p, mime_filename_charset, &slen);
1325 -               temp_string = rfc2047_decode(temp_string, FALSE, NULL, 32,
1326 +               DEBUG(D_acl) debug_printf("MIME:    2047-name %s\n", temp_string);
1327 +
1328 +               temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ',
1329                   NULL, &err_msg);
1330 +               DEBUG(D_acl) debug_printf("MIME:    plain-name %s\n", temp_string);
1331 +
1332                 size = Ustrlen(temp_string);
1333  
1334                 if (size == slen)
1335 @@ -750,7 +756,7 @@ while(1)
1336                     &dummy_errstr)
1337                 : NULL;
1338               DEBUG(D_acl) debug_printf(
1339 -               " found %s MIME parameter in %s header, value '%s'\n",
1340 +               "MIME:  found %s parameter in %s header, value '%s'\n",
1341                 mp->name, mh->name, *mp->value);
1342  
1343               break;                    /* done matching param names */
1344 @@ -768,7 +774,7 @@ while(1)
1345           if (decoding_failed) mime_filename = mime_fname_rfc2231;
1346  
1347           DEBUG(D_acl) debug_printf(
1348 -           " found %s MIME parameter in %s header, value is '%s'\n",
1349 +           "MIME:  found %s parameter in %s header, value is '%s'\n",
1350             "filename", mh->name, mime_filename);
1351           }
1352         }
1353 @@ -809,8 +815,9 @@ while(1)
1354         (nested_context.boundary != NULL) &&
1355         (Ustrncmp(mime_content_type,"multipart",9) == 0) )
1356      {
1357 -    DEBUG(D_acl) debug_printf("Entering multipart recursion, boundary '%s'\n",
1358 -      nested_context.boundary);
1359 +    DEBUG(D_acl)
1360 +      debug_printf("MIME: Entering multipart recursion, boundary '%s'\n",
1361 +       nested_context.boundary);
1362  
1363      nested_context.context =
1364        context && context->context == MBC_ATTACHMENT
1365
1366 commit 8d58e3501ce731c5d6d5efc9e76058832d4bc941
1367 Author: Jeremy Harris <jgh146exb@wizmail.org>
1368 Date:   Thu Jan 21 15:37:08 2016 +0000
1369
1370     Cutthrough: Fix bug with dot-only line
1371     
1372     (cherry picked from commit 1bc460a64a0de0766d21f4f8660c6597bc410cbc)
1373
1374 diff --git a/src/src/receive.c b/src/src/receive.c
1375 index 64cf1ae..d1f81d3 100644
1376 --- a/src/src/receive.c
1377 +++ b/src/src/receive.c
1378 @@ -835,7 +835,15 @@ while ((ch = (receive_getc)()) != EOF)
1379        ch_state = 4;
1380        continue;
1381        }
1382 -    ch_state = 1;                       /* The dot itself is removed */
1383 +    /* The dot was removed at state 3. For a doubled dot, here, reinstate
1384 +    it to cutthrough. The current ch, dot or not, is passed both to cutthrough
1385 +    and to file below. */
1386 +    if (ch == '.')
1387 +      {
1388 +      uschar c= ch;
1389 +      (void) cutthrough_puts(&c, 1);
1390 +      }
1391 +    ch_state = 1;
1392      break;
1393  
1394      case 4:                             /* After [CR] LF . CR */
This page took 0.277541 seconds and 2 git commands to generate.