1 commit da1aecfce80fba32b9abb328cf78088d95b7700a
2 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
3 Date: Wed Aug 19 15:22:41 2015 +0200
5 Fix post-transport-crash.
7 The crash probably was introduced in a39bd74d3e94 and
8 needs 'split_spool_directory=yes' to expose.
10 Thanks to Wolfgang Breyha, who found the same fix.
12 (cherry picked from commit 6b51df8340eacc95e3def9a4376506610e91996c)
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)
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);
25 sprintf(CS spool_file, "%s%s-D", spool_dir, msgq[i].message_id);
28 commit d7168d8b112d3ba642a25ed04de36fb76d4a847d
29 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
30 Date: Thu Aug 20 13:58:06 2015 +0200
32 Fix post-transport-crash: safeguard for missing spool BUG 1671
34 Based on a proposal from Wolfgang Breyha.
36 (cherry picked from commit dadff1d47e54962b0fdf98e8ce5cef42b6cb7fb5)
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
49 /* Data block for keeping track of subprocesses for parallel remote
50 @@ -7904,17 +7905,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
52 deliver_get_sender_address (uschar * id)
55 +uschar * new_sender_address,
56 + * save_sender_address;
58 if (!spool_open_datafile(id))
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) */
67 sprintf(CS spoolname, "%s-H", id);
68 -if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
69 +save_sender_address = sender_address;
71 +rc = spool_read_header(spoolname, TRUE, TRUE);
73 +new_sender_address = sender_address;
74 +sender_address = save_sender_address;
76 +if (rc != spool_read_OK)
79 +assert(new_sender_address);
81 (void)close(deliver_datafile);
82 deliver_datafile = -1;
84 -return sender_address;
85 +return new_sender_address;
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. */
95 smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
97 -uschar * save_sender_address = sender_address;
98 -uschar * current_local_identity =
100 +uschar * message_local_identity,
101 + * current_local_identity,
102 + * new_sender_address;
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);
110 -sender_address = save_sender_address;
111 +if (!(new_sender_address = deliver_get_sender_address(message_id)))
114 +message_local_identity =
115 + smtp_local_identity(new_sender_address, s_compare->tblock);
117 return Ustrcmp(current_local_identity, message_local_identity) == 0;
120 commit 9e1acebc3fbb288da804ab9031c7c448dffd841a
121 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
122 Date: Tue Aug 11 17:36:29 2015 +0200
124 Fix ESMTP MAIL command option processing
126 If the address containes spaces, the option processing
129 (cherry picked from commit 2ef7ed082481b2dccd3c2e0eae849b24bf0b172a)
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
142 /* Initialize for TCP wrappers if so configured. It appears that the macro
143 @@ -232,6 +233,7 @@ static uschar *protocols[] = {
145 /* Sanity check and validate optional args to MAIL FROM: envelope */
148 ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
151 @@ -240,7 +242,6 @@ enum {
152 #ifdef EXPERIMENTAL_INTERNATIONAL
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 */
163 - { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
164 + /* keep this the last entry */
165 + { US"NULL", ENV_MAIL_OPT_NULL, FALSE },
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;
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;
177 if (strcmpic(name, mail_args->name) == 0)
178 @@ -4066,15 +4068,17 @@ while (done <= 0)
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. */
188 + value==name when it found no equal-sign.
189 + An error for a malformed address will occur. */
190 + case ENV_MAIL_OPT_NULL:
196 + default: assert(0);
198 /* Break out of for loop if switch() had bad argument or
199 when start of the email address is reached */
201 commit 22c82c48aa5d23c49d38e3581810ea54587df61b
202 Author: Jeremy Harris <jgh146exb@wizmail.org>
203 Date: Tue Aug 25 10:36:27 2015 +0100
205 Close logs after daemon-process exceptional write. Bug 728
207 (cherry picked from commit c8899c20aa08c9ae6a4c291aad23ba90512bebe4)
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. */
218 store_reset(reset_point);
219 sender_host_address = NULL;
222 commit 4d3b8805796ffa39889060d9f216bfaf7391c542
223 Author: Jeremy Harris <jgh146exb@wizmail.org>
224 Date: Thu Sep 17 13:35:16 2015 +0100
226 DNS: time-limit cached returns, using TTL. Bug 1395
228 This can matter for fast-changing data such as DNSBLs.
230 (cherry picked from commit 14b3c5bc64a16df07583fe4b5ef2e0129d063893)
232 DNS: avoid overflow in cache TTL for negative entries. Bug 1395
234 (cherry picked from commit e162fc9757d4b8cb41aca74214e968622d6c3dee)
236 diff --git a/src/src/dns.c b/src/src/dns.c
237 index 64958d9..abed126 100644
240 @@ -390,7 +390,8 @@ from the following bytes. */
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 {
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 */
274 typedef struct lookup_module_info {
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
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.
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,
309 struct cdb_state * cdbp = handle;
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. */
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)
322 EXIM_DB *d = (EXIM_DB *)handle;
323 EXIM_DATUM key, data;
324 @@ -120,7 +120,7 @@ return FAIL;
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)
331 return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
333 @@ -140,7 +140,7 @@ return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
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)
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. */
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)
355 @@ -388,6 +388,9 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
357 if (rr->type != searchtype) continue;
359 + if (*do_cache > rr->ttl)
360 + *do_cache = rr->ttl;
362 if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
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. */
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)
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. */
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)
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. */
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)
402 /* Keep picky compilers happy */
404 @@ -1348,7 +1348,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
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)
411 /* Keep picky compilers happy */
413 @@ -1357,7 +1357,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
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)
420 /* Keep picky compilers happy */
422 @@ -1366,7 +1366,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
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)
429 /* Keep picky compilers happy */
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 *));
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:
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
457 Returns: the return from the lookup function, or DEFER
458 @@ -36,8 +36,8 @@ Returns: the return from the lookup function, or DEFER
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 *))
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;
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)
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,
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)
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,
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)
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,
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)
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
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
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)
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. */
538 if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
540 @@ -233,7 +233,7 @@ if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
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));
548 *errmsg = string_sprintf("MYSQL: lookup result failed: %s\n",
549 @@ -341,7 +341,7 @@ shared with other SQL lookups. */
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)
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. */
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)
571 @@ -68,7 +68,7 @@ return (rc == YPERR_KEY || rc == YPERR_MAP)? FAIL : DEFER;
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)
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. */
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)
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. */
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)
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 */
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)
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
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)
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);
642 DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data "
643 "but was successful. Rows affected: %s\n", result);
645 @@ -399,7 +399,7 @@ shared with other SQL lookups. */
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)
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)
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)
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;
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("");
685 @@ -304,7 +304,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
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)
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>
702 -static void *spf_open(uschar *filename, uschar **errmsg) {
704 +spf_open(uschar *filename, uschar **errmsg)
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;
713 -static void spf_close(void *handle) {
715 +spf_close(void *handle)
717 SPF_server_t *spf_server = handle;
718 if (spf_server) SPF_server_free(spf_server);
721 -static int spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
722 - uschar **result, uschar **errmsg, BOOL *do_cache) {
724 +spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
725 + uschar **result, uschar **errmsg, uint *do_cache)
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;
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)
742 struct strbuf res = { NULL, 0, 0 };
743 @@ -93,7 +93,7 @@ if (ret != SQLITE_OK)
747 -if (res.string == NULL) *do_cache = FALSE;
748 +if (res.string == NULL) *do_cache = 0;
750 *result = res.string;
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 */
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)
763 handle = handle; /* Keep picky compilers happy */
765 @@ -57,7 +57,7 @@ if (Ustrcmp(query, "defer") == 0)
769 -if (Ustrcmp(query, "nocache") == 0) *do_cache = FALSE;
770 +if (Ustrcmp(query, "nocache") == 0) *do_cache = 0;
772 *result = string_copy(query);
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 */
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)
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)
793 tree_node *t = (tree_node *)handle;
794 search_cache *c = (search_cache *)(t->data.ptr);
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. */
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))
807 + { /* Data was in the cache already; set the pointer from the tree node */
809 + DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
811 + filename ? US"\n in " : US"", filename ? filename : US"");
815 - BOOL do_cache = TRUE;
816 + uint do_cache = UINT_MAX;
817 int keylength = Ustrlen(keystring);
821 - if (filename != NULL)
822 - debug_printf("file lookup required for %s\n in %s\n",
823 - keystring, filename);
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",
830 + filename ? US"\n in " : US"", filename ? filename : US"");
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)
836 if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
837 &data, &search_error_message, &do_cache) == DEFER)
839 search_find_defer = TRUE;
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)
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);
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;
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;
864 + memcpy(t->name, keystring, len);
866 + tree_insertnode(&c->item_cache, t);
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)
875 -/* Data was in the cache already; set the pointer from the tree node */
879 - data = US t->data.ptr;
880 - DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
882 - (filename == NULL)? US"" : US"\n in ",
883 - (filename == NULL)? US"" : filename);
886 -/* Debug: output the answer */
892 - if (search_find_defer) debug_printf("lookup deferred: %s\n",
893 - search_error_message);
894 - else debug_printf("lookup failed\n");
896 - else debug_printf("lookup yielded: %s\n", 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");
904 /* Return it in new dynamic store in the regular pool */
906 store_pool = old_pool;
907 -return (data == NULL)? NULL : string_copy(data);
908 +return data ? string_copy(data) : NULL;
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 */
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 */
925 +typedef struct expiring_data {
926 + time_t expiry; /* if nonzero, data invalid after this time */
927 + void *ptr; /* pointer to data */
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. */
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 */
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 */
948 typedef struct dnsbl_cache_block {
953 @@ -3584,21 +3585,37 @@ if (!string_format(query, sizeof(query), "%s.%s", prepend, domain))
955 /* Look for this query in the cache. */
957 -t = tree_search(dnsbl_cache, query);
958 +if ( (t = tree_search(dnsbl_cache, query))
959 + && (cb = t->data.ptr)->expiry > time(NULL)
962 +/* Previous lookup was cached */
965 + HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
968 /* If not cached from a previous lookup, we must do a DNS lookup, and
969 cache the result in permanent memory. */
976 store_pool = POOL_PERM;
978 - /* Set up a tree entry to cache the lookup */
981 + HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
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);
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);
996 /* Do the DNS loopup . */
998 @@ -3616,7 +3633,10 @@ if (t == NULL)
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.
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. */
1008 if (cb->rc == DNS_SUCCEED)
1010 @@ -3634,6 +3654,7 @@ if (t == NULL)
1012 while (da->next != NULL) da = da->next;
1013 addrp = &(da->next);
1014 + if (ttl > rr->ttl) ttl = rr->ttl;
1018 @@ -3645,17 +3666,10 @@ if (t == NULL)
1019 if (cb->rhs == NULL) cb->rc = DNS_NODATA;
1022 + cb->expiry = time(NULL)+ttl;
1023 store_pool = old_pool;
1026 -/* Previous lookup was cached */
1030 - HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
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
1038 commit c4dcf906ceb3a45c6b30f76476d73ca836b262cd
1039 Author: Jeremy Harris <jgh146exb@wizmail.org>
1040 Date: Sat Sep 19 13:59:22 2015 +0100
1042 Retry: always use interface, if set, for retry DB key. Bug 1678
1044 Even constant values must be used, as multiple transports with
1045 different values may be in play and should be kept distinct.
1047 (cherry picked from commit 6f6dedccb47f231a0712d882da20feffbac8d0bc)
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
1074 @@ -36,7 +35,7 @@ Returns: TRUE on success, FALSE on failure, with error message
1077 smtp_get_interface(uschar *istring, int host_af, address_item *addr,
1078 - BOOL *changed, uschar **interface, uschar *msg)
1079 + uschar **interface, uschar *msg)
1081 const uschar * expint;
1083 @@ -54,8 +53,6 @@ if (expint == NULL)
1087 -if (changed != NULL) *changed = expint != istring;
1089 while (isspace(*expint)) expint++;
1090 if (*expint == 0) return TRUE;
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"";
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. */
1116 host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET : AF_INET6;
1117 - if (!smtp_get_interface(ob->interface, host_af, addrlist, &ifchanges,
1120 - if (ifchanges) pistring = string_sprintf("%s/%s", pistring, interface);
1121 + if ((rs = ob->interface) && *rs)
1123 + if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid))
1125 + pistring = string_sprintf("%s/%s", pistring, interface);
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.
1136 host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
1138 - if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
1139 + if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
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;
1147 - if ( !smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
1148 + if ( !smtp_get_interface(tf->interface, host_af, addr, &interface,
1150 || !smtp_get_port(tf->port, addr, &port, US"callout")
1153 commit 1bd52978055bc07dfa150d296ffb344f10fff7fe
1154 Author: Jeremy Harris <jgh146exb@wizmail.org>
1155 Date: Mon Nov 2 19:03:26 2015 +0000
1157 Avoid misaligned access in cached lookup. Bug 1708
1159 (cherry picked from commit 98b98887f926be87eabccc7919e57ce625c63c03)
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
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;
1174 + t = (tree_node *)(e+1);
1175 memcpy(t->name, keystring, len);
1177 tree_insertnode(&c->item_cache, t);
1179 commit e7c3de301824738c6f302e02e566f9da75d3130c
1180 Author: Jeremy Harris <jgh146exb@wizmail.org>
1181 Date: Thu Oct 15 21:40:17 2015 +0100
1183 DKIM: ignore space & tab embedded in base64 during decode. Bug 1700
1185 (cherry picked from commit 0f557e9065b0bcfce38ee1fea5fc947bf0c5431c)
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,
1193 for( i = j = n = 0; i < slen; i++ )
1195 + unsigned char c = src[i];
1197 if( ( slen - i ) >= 2 &&
1198 - src[i] == '\r' && src[i + 1] == '\n' )
1199 + c == '\r' && src[i + 1] == '\n' )
1202 - if( src[i] == '\n' )
1203 + if( c == '\n' || c == ' ' || c == '\t' )
1206 - if( src[i] == '=' && ++j > 2 )
1207 + if( c == '=' && ++j > 2 )
1208 return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
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 );
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 );
1219 @@ -160,11 +162,13 @@ int base64_decode( unsigned char *dst, int *dlen,
1221 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
1223 - if( *src == '\r' || *src == '\n' )
1224 + unsigned char c = *src;
1226 + if( c == '\r' || c == '\n' || c == ' ' || c == '\t' )
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 );
1237 commit a23a9d099ac9d112a6d961e00539bcf1bbb1ef7e
1238 Author: Jeremy Harris <jgh146exb@wizmail.org>
1239 Date: Wed Nov 25 17:49:03 2015 +0000
1241 MIME: fix crash on filenames having null charset. Bug 1730
1243 (cherry picked from commit 622dbd6a512d2c7786125e3b80e96a43e54b8e90)
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);
1253 -val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
1255 + val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
1256 val = string_cat(val, &size, &ptr, US"?Q?", 3);
1258 while ((c = *fname))
1259 @@ -607,7 +608,7 @@ while(1)
1260 if (!fgets(CS header, MIME_MAX_HEADER_SIZE, f))
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");
1268 @@ -619,12 +620,12 @@ while(1)
1269 if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
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",
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",
1283 @@ -648,7 +649,7 @@ while(1)
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);
1291 if (*(p = q)) p++; /* jump past the ; */
1292 @@ -666,7 +667,7 @@ while(1)
1294 mime_parameter * mp;
1296 - DEBUG(D_acl) debug_printf(" considering paramlist '%s'\n", p);
1297 + DEBUG(D_acl) debug_printf("MIME: considering paramlist '%s'\n", p);
1300 && strncmpic(CUS"content-disposition:", header, 20) == 0
1301 @@ -700,22 +701,27 @@ while(1)
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 */
1308 if ((size = s-q) > 0)
1310 mime_filename_charset = string_copyn(q, size);
1313 - while(*p == '\'' && *p) p++; /* p is after ' */
1315 + if (*(p = s)) p++;
1316 + while(*p == '\'') p++; /* p is after 2nd ' */
1321 + DEBUG(D_acl) debug_printf("MIME: charset %s fname '%s'\n",
1322 + mime_filename_charset ? mime_filename_charset : US"<NULL>", p);
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);
1328 + temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ',
1330 + DEBUG(D_acl) debug_printf("MIME: plain-name %s\n", temp_string);
1332 size = Ustrlen(temp_string);
1335 @@ -750,7 +756,7 @@ while(1)
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);
1343 break; /* done matching param names */
1344 @@ -768,7 +774,7 @@ while(1)
1345 if (decoding_failed) mime_filename = mime_fname_rfc2231;
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);
1353 @@ -809,8 +815,9 @@ while(1)
1354 (nested_context.boundary != NULL) &&
1355 (Ustrncmp(mime_content_type,"multipart",9) == 0) )
1357 - DEBUG(D_acl) debug_printf("Entering multipart recursion, boundary '%s'\n",
1358 - nested_context.boundary);
1360 + debug_printf("MIME: Entering multipart recursion, boundary '%s'\n",
1361 + nested_context.boundary);
1363 nested_context.context =
1364 context && context->context == MBC_ATTACHMENT
1366 commit 8d58e3501ce731c5d6d5efc9e76058832d4bc941
1367 Author: Jeremy Harris <jgh146exb@wizmail.org>
1368 Date: Thu Jan 21 15:37:08 2016 +0000
1370 Cutthrough: Fix bug with dot-only line
1372 (cherry picked from commit 1bc460a64a0de0766d21f4f8660c6597bc410cbc)
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)
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. */
1389 + (void) cutthrough_puts(&c, 1);
1394 case 4: /* After [CR] LF . CR */