1 commit aa7751be078fe9a20efa2cf2a8856fadb98f4178
2 Author: Jeremy Harris <jgh146exb@wizmail.org>
3 Date: Sun Jun 28 15:14:02 2015 +0100
7 diff --git a/src/src/dns.c b/src/src/dns.c
8 index 64958d9..a239bec 100644
11 @@ -40,7 +40,6 @@ fakens_search(const uschar *domain, int type, uschar *answerptr, int size)
13 int len = Ustrlen(domain);
14 int asize = size; /* Locally modified */
18 uschar *aptr = answerptr; /* Locally modified */
19 @@ -51,7 +50,6 @@ struct stat statbuf;
20 if (domain[len - 1] == '.') len--;
21 Ustrncpy(name, domain, len);
23 -endname = name + len;
25 /* Look for the fakens utility, and if it exists, call it. */
27 @@ -86,7 +84,7 @@ if (stat(CS utilname, &statbuf) >= 0)
28 asize -= rc; /* may need to be passed on to res_search(). */
31 - /* If we ran out of output buffer before exhasting the return,
32 + /* If we ran out of output buffer before exhausting the return,
33 carry on reading and counting it. */
36 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
37 index cf0a5d6..711ee86 100644
38 --- a/src/src/smtp_in.c
39 +++ b/src/src/smtp_in.c
40 @@ -3293,7 +3293,7 @@ while (done <= 0)
42 int start, end, sender_domain, recipient_domain;
49 diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
50 index e1dcd77..d8377fd 100644
51 --- a/src/src/tls-openssl.c
52 +++ b/src/src/tls-openssl.c
53 @@ -708,7 +708,7 @@ if ( (nid = OBJ_sn2nid (CCS exp_curve)) == NID_undef
55 if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
57 - tls_error("Unable to create ec curve", host, NULL);
58 + tls_error(US"Unable to create ec curve", host, NULL);
62 diff --git a/src/src/utf8.c b/src/src/utf8.c
63 index a0ec003..8a7cf38 100644
66 @@ -127,7 +127,7 @@ if ((rc = punycode_decode(p_len, CCS alabel+4, &p_len, p, NULL)) != PUNYCODE_SUC
70 -s = stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
71 +s = US stringprep_ucs4_to_utf8(p, p_len, NULL, &p_len);
72 res = string_copyn(s, p_len);
76 commit 5b881b5a8e0d7bc540f4b63cc9559d2cb1775965
77 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
78 Date: Thu Jul 30 09:43:51 2015 +0200
80 Docs: Add a note about the maximum spam bar length
82 diff --git a/src/src/spam.h b/src/src/spam.h
83 index 05ab655..2fe7380 100644
87 /* timeout for reading and writing spamd */
88 #define SPAMD_TIMEOUT 120
90 -/* maximum length of the spam bar */
91 +/* maximum length of the spam bar, please update the
92 + * spec, the max length is mentioned there */
93 #define MAX_SPAM_BAR_CHARS 50
95 /* SHUT_WR seems to be undefined on Unixware ? */
97 commit 98716abe2b636d275e866f3ad6374cb70bf6e504
98 Author: Jeremy Harris <jgh146exb@wizmail.org>
99 Date: Sun Aug 2 13:44:31 2015 +0100
101 Testsuite: Add testcase for OCSP-nonaware client, to supporting server. Bug 1664
103 The logfile here is for (I hope) the passing case, though the fixed GnuTLS library
104 is not yet available. Also due to the bug, client-gnutls is not usable for the
105 test; client-openssl must be used - meaning that a GnuTLS-only system cannot run
108 OCSP-GnuTLS/5650 OCSP stapling, server
109 ** Command 15 ("client-ssl", starting at line 98)
110 ** Return code 127 (expected 0)
112 diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
113 index 61ed0e8..e2ac17c 100644
114 --- a/src/src/tls-gnu.c
115 +++ b/src/src/tls-gnu.c
116 @@ -842,7 +842,7 @@ if ( !host /* server */
117 gnutls_certificate_set_ocsp_status_request_function(state->x509_cred,
118 server_ocsp_stapling_cb, state->exp_tls_ocsp_file);
120 - DEBUG(D_tls) debug_printf("Set OCSP response file %s\n", &state->exp_tls_ocsp_file);
121 + DEBUG(D_tls) debug_printf("OCSP response file = %s\n", state->exp_tls_ocsp_file);
126 commit 9196d5bf543d75a81ae0825a352920d27241c325
127 Author: Jeremy Harris <jgh146exb@wizmail.org>
128 Date: Sun Aug 2 13:53:15 2015 +0100
130 GnuTLS: avoid using OCSP on buggy library versions. Bug 1664
132 diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
133 index e2ac17c..8aabc5c 100644
134 --- a/src/src/tls-gnu.c
135 +++ b/src/src/tls-gnu.c
136 @@ -176,6 +176,8 @@ static const char * const exim_default_gnutls_priority = "NORMAL";
138 static BOOL exim_gnutls_base_init_done = FALSE;
140 +static BOOL gnutls_buggy_ocsp = FALSE;
143 /* ------------------------------------------------------------------------ */
145 @@ -831,18 +833,25 @@ if ( !host /* server */
149 - if (!expand_check(tls_ocsp_file, US"tls_ocsp_file",
150 - &state->exp_tls_ocsp_file))
152 + if (gnutls_buggy_ocsp)
154 + DEBUG(D_tls) debug_printf("GnuTLS library is buggy for OCSP; avoiding\n");
158 + if (!expand_check(tls_ocsp_file, US"tls_ocsp_file",
159 + &state->exp_tls_ocsp_file))
162 - /* Use the full callback method for stapling just to get observability.
163 - More efficient would be to read the file once only, if it never changed
164 - (due to SNI). Would need restart on file update, or watch datestamp. */
165 + /* Use the full callback method for stapling just to get observability.
166 + More efficient would be to read the file once only, if it never changed
167 + (due to SNI). Would need restart on file update, or watch datestamp. */
169 - gnutls_certificate_set_ocsp_status_request_function(state->x509_cred,
170 - server_ocsp_stapling_cb, state->exp_tls_ocsp_file);
171 + gnutls_certificate_set_ocsp_status_request_function(state->x509_cred,
172 + server_ocsp_stapling_cb, state->exp_tls_ocsp_file);
174 - DEBUG(D_tls) debug_printf("OCSP response file = %s\n", state->exp_tls_ocsp_file);
175 + DEBUG(D_tls) debug_printf("OCSP response file = %s\n", state->exp_tls_ocsp_file);
180 @@ -1011,6 +1020,35 @@ return OK;
181 * Initialize for GnuTLS *
182 *************************************************/
186 +tls_is_buggy_ocsp(void)
189 +uschar maj, mid, mic;
191 +s = CUS gnutls_check_version(NULL);
195 + while (*s && *s != '.') s++;
196 + mid = atoi(CCS ++s);
203 + while (*s && *s != '.') s++;
204 + mic = atoi(CCS ++s);
205 + return mic <= (mid == 3 ? 16 : 3);
213 /* Called from both server and client code. In the case of a server, errors
214 before actual TLS negotiation return DEFER.
216 @@ -1074,6 +1112,9 @@ if (!exim_gnutls_base_init_done)
220 + if ((gnutls_buggy_ocsp = tls_is_buggy_ocsp()))
221 + log_write(0, LOG_MAIN, "OCSP unusable with this GnuTLS library version");
223 exim_gnutls_base_init_done = TRUE;
227 commit 63f0dbe0ca0aba7be3bc8807f45c8703a1cfafe1
228 Author: Jeremy Harris <jgh146exb@wizmail.org>
229 Date: Thu Aug 6 21:38:33 2015 +0100
231 OpenSSL: fix complile on pre-EC-capable library versions
233 diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
234 index d8377fd..b1dccb8 100644
235 --- a/src/src/tls-openssl.c
236 +++ b/src/src/tls-openssl.c
237 @@ -659,15 +659,15 @@ Returns: TRUE if OK (nothing to set up, or setup worked)
239 init_ecdh(SSL_CTX * sctx, host_item * host)
241 +#ifdef OPENSSL_NO_ECDH
250 -#ifdef OPENSSL_NO_ECDH
254 if (host) /* No ECDH setup for clients, only for servers */
258 commit 755762fd4c420cabbcba4a9c79947e926fa82219
259 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
260 Date: Sun Aug 9 23:29:44 2015 +0200
264 diff --git a/src/src/malware.c b/src/src/malware.c
265 index 141c6ea..96af1e8 100644
266 --- a/src/src/malware.c
267 +++ b/src/src/malware.c
268 @@ -886,7 +886,7 @@ if (!malware_ok)
269 string_sprintf("unable to read result (%s)", strerror(errno)),
272 - for (p[bread] = '\0'; q = Ustrchr(p, '\n'); p = q+1)
273 + for (p[bread] = '\0'; (q = Ustrchr(p, '\n')); p = q+1)
277 @@ -1880,6 +1880,9 @@ if (!malware_ok)
279 /* here for any unexpected response from the scanner */
282 + case AVA_DONE: log_write(0, LOG_PANIC, "%s:%d:%s: should not happen",
283 + __FILE__, __LINE__, __FUNCTION__);
287 diff --git a/src/src/spam.c b/src/src/spam.c
288 index ca8d207..457aa3a 100644
291 @@ -297,7 +297,7 @@ start = time(NULL);
292 sd = (spamd_address_container *)store_get(sizeof(spamd_address_container));
294 for (sublist = address, args = 0, spamd_param_init(sd);
295 - s = string_nextinlist(&sublist, &sublist_sep, NULL, 0);
296 + (s = string_nextinlist(&sublist, &sublist_sep, NULL, 0));
300 diff --git a/src/src/tlscert-openssl.c b/src/src/tlscert-openssl.c
301 index 72808a7..19db040 100644
302 --- a/src/src/tlscert-openssl.c
303 +++ b/src/src/tlscert-openssl.c
304 @@ -127,7 +127,7 @@ else
307 struct tm * tm_p = &tm;
309 + BOOL mod_tz = TRUE;
310 uschar * tz = to_tz(US"GMT0"); /* need to call strptime with baseline TZ */
312 /* Parse OpenSSL ASN1_TIME_print output. A shame there seems to
313 @@ -164,7 +164,7 @@ else
323 commit 4bd6107db73131e1b48f1902833fd7c637c08bda
324 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
325 Date: Mon Aug 10 00:39:36 2015 +0200
327 Really re-select() when interrupted.
329 diff --git a/src/src/ip.c b/src/src/ip.c
330 index ead7299..cb54f16 100644
333 @@ -499,7 +499,7 @@ do
335 /* If the socket is ready, break out of the loop. */
337 -while (!FD_ISSET(fd, &select_inset));
338 +while (rc < 0 || !FD_ISSET(fd, &select_inset));
343 commit 505d976aa23de4294751162dee6466e335c96fbf
344 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
345 Date: Tue Aug 11 09:13:11 2015 +0200
347 Build: Make test_{os,parse,dbfn,string} work
349 diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base
350 index 1d5a5f6..95110e6 100644
351 --- a/src/OS/Makefile-Base
352 +++ b/src/OS/Makefile-Base
353 @@ -743,11 +743,11 @@ sa-os.o: $(HDRS) os.c
354 # These are the test targets themselves
356 test_dbfn: config.h dbfn.c dummies.o sa-globals.o sa-os.o store.o \
357 - string.o tod.o version.o
358 + string.o tod.o version.o utf8.o
359 $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE dbfn.c
360 $(LNCC) -o test_dbfn $(LFLAGS) dbfn.o \
361 dummies.o sa-globals.o sa-os.o store.o string.o \
362 - tod.o version.o $(LIBS) $(DBMLIB)
363 + tod.o version.o utf8.o $(LIBS) $(DBMLIB) $(LDFLAGS)
366 test_host: config.h child.c host.c dns.c dummies.c sa-globals.o os.o \
367 @@ -761,23 +761,24 @@ test_host: config.h child.c host.c dns.c dummies.c sa-globals.o os.o \
368 tod.o tree.o $(LIBS) $(LIBRESOLV)
369 rm -f child.o dummies.o host.o dns.o
371 -test_os: os.h os.c dummies.o sa-globals.o store.o string.o tod.o
372 +test_os: os.h os.c dummies.o sa-globals.o store.o string.o tod.o utf8.o
373 $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE os.c
374 $(LNCC) -o test_os $(LFLAGS) os.o dummies.o \
375 - sa-globals.o store.o string.o tod.o $(LIBS)
376 + sa-globals.o store.o string.o tod.o utf8.o $(LIBS) $(LDFLAGS)
379 test_parse: config.h parse.c dummies.o sa-globals.o \
380 - store.o string.o tod.o version.o
381 + store.o string.o tod.o version.o utf8.o
382 $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE parse.c
383 $(LNCC) -o test_parse $(LFLAGS) parse.o \
384 - dummies.o sa-globals.o store.o string.o tod.o version.o
385 + dummies.o sa-globals.o store.o string.o tod.o version.o \
389 -test_string: config.h string.c dummies.o sa-globals.o store.o tod.o
390 +test_string: config.h string.c dummies.o sa-globals.o store.o tod.o utf8.o
391 $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE string.c
392 $(LNCC) -o test_string $(LFLAGS) -DSTAND_ALONE string.o \
393 - dummies.o sa-globals.o store.o tod.o $(LIBS)
394 + dummies.o sa-globals.o store.o tod.o utf8.o $(LIBS) $(LDFLAGS)
398 diff --git a/src/src/host.c b/src/src/host.c
399 index 94126d4..31c2bbf 100644
402 @@ -3212,7 +3212,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
405 int flags = whichrrs;
412 commit 2ef7ed082481b2dccd3c2e0eae849b24bf0b172a
413 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
414 Date: Tue Aug 11 17:36:29 2015 +0200
416 Fix ESMTP MAIL command option processing
418 If the address containes spaces, the option processing
421 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
422 index 711ee86..effc636 100644
423 --- a/src/src/smtp_in.c
424 +++ b/src/src/smtp_in.c
432 /* Initialize for TCP wrappers if so configured. It appears that the macro
433 @@ -232,6 +233,7 @@ static uschar *protocols[] = {
435 /* Sanity check and validate optional args to MAIL FROM: envelope */
438 ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
441 @@ -240,7 +242,6 @@ enum {
442 #ifdef EXPERIMENTAL_INTERNATIONAL
448 uschar * name; /* option requested during MAIL cmd */
449 @@ -260,7 +261,8 @@ static env_mail_type_t env_mail_type_list[] = {
450 #ifdef EXPERIMENTAL_INTERNATIONAL
451 { US"SMTPUTF8",ENV_MAIL_OPT_UTF8, FALSE }, /* rfc6531 */
453 - { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
454 + /* keep this the last entry */
455 + { US"NULL", ENV_MAIL_OPT_NULL, FALSE },
458 /* When reading SMTP from a remote host, we have to use our own versions of the
459 @@ -3887,7 +3889,7 @@ while (done <= 0)
460 if (!extract_option(&name, &value)) break;
462 for (mail_args = env_mail_type_list;
463 - (char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
464 + mail_args->value != ENV_MAIL_OPT_NULL;
467 if (strcmpic(name, mail_args->name) == 0)
468 @@ -4066,15 +4068,17 @@ while (done <= 0)
472 - /* Unknown option. Stick back the terminator characters and break
473 + /* No valid option. Stick back the terminator characters and break
474 the loop. Do the name-terminator second as extract_option sets
475 - value==name when it found no equal-sign.
476 - An error for a malformed address will occur. */
478 + value==name when it found no equal-sign.
479 + An error for a malformed address will occur. */
480 + case ENV_MAIL_OPT_NULL:
486 + default: assert(0);
488 /* Break out of for loop if switch() had bad argument or
489 when start of the email address is reached */
491 commit 4fb7df6d044a39151e72346ac0d67ac09686f704
492 Author: Jeremy Harris <jgh146exb@wizmail.org>
493 Date: Tue Aug 11 22:54:53 2015 +0100
495 GnuTLS: avoid whining about OCSP when not requested by config
497 diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c
498 index 8aabc5c..fe18094 100644
499 --- a/src/src/tls-gnu.c
500 +++ b/src/src/tls-gnu.c
501 @@ -176,7 +176,9 @@ static const char * const exim_default_gnutls_priority = "NORMAL";
503 static BOOL exim_gnutls_base_init_done = FALSE;
505 +#ifndef DISABLE_OCSP
506 static BOOL gnutls_buggy_ocsp = FALSE;
510 /* ------------------------------------------------------------------------ */
511 @@ -1021,6 +1023,8 @@ return OK;
512 *************************************************/
515 +#ifndef DISABLE_OCSP
518 tls_is_buggy_ocsp(void)
520 @@ -1047,6 +1051,7 @@ if (maj == 3)
527 /* Called from both server and client code. In the case of a server, errors
528 @@ -1112,8 +1117,10 @@ if (!exim_gnutls_base_init_done)
532 - if ((gnutls_buggy_ocsp = tls_is_buggy_ocsp()))
533 +#ifndef DISABLE_OCSP
534 + if (tls_ocsp_file && (gnutls_buggy_ocsp = tls_is_buggy_ocsp()))
535 log_write(0, LOG_MAIN, "OCSP unusable with this GnuTLS library version");
538 exim_gnutls_base_init_done = TRUE;
541 commit c528cec4dbfdb6e367a6ac0ed72e2e768a9c4392
542 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
543 Date: Wed Aug 12 23:45:44 2015 +0200
545 Adjust the timeout after interrupted select()
547 diff --git a/src/src/ip.c b/src/src/ip.c
548 index cb54f16..7991a58 100644
551 @@ -451,8 +451,8 @@ BOOL
552 fd_ready(int fd, int timeout)
556 time_t start_recv = time(NULL);
557 +int time_left = timeout;
561 @@ -464,10 +464,9 @@ if (timeout <= 0)
565 + struct timeval tv = { time_left, 0 };
566 FD_ZERO (&select_inset);
567 FD_SET (fd, &select_inset);
568 - tv.tv_sec = timeout;
571 /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
572 rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv);
573 @@ -479,25 +478,24 @@ do
574 Aug 2004: Somebody set up a cron job that ran exiwhat every 2 minutes, making
575 the interrupt not at all rare. Since the timeout is typically more than 2
576 minutes, the effect was to block the timeout completely. To prevent this
577 - happening again, we do an explicit time test. */
578 + happening again, we do an explicit time test and adjust the timeout
581 if (rc < 0 && errno == EINTR)
583 DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n");
584 - if (time(NULL) - start_recv < timeout) continue;
585 - DEBUG(D_transport) debug_printf("total wait time exceeds timeout\n");
586 + /* Watch out, 'continue' jumps to the condition, not to the loops top */
587 + if (time_left = timeout - (time(NULL) - start_recv)) continue;
590 - /* Handle a timeout, and treat any other select error as a timeout, including
591 - an EINTR when we have been in this loop for longer than timeout. */
599 - /* If the socket is ready, break out of the loop. */
600 + /* Checking the FD_ISSET is not enough, if we're interrupted, the
601 + select_inset may still contain the 'input'. */
603 while (rc < 0 || !FD_ISSET(fd, &select_inset));
606 commit 85ff3cf9f3ab78c4dfa9f9ff34d27e6fe8f73c39
607 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
608 Date: Thu Aug 13 00:20:12 2015 +0200
610 Fix timeout adjustment in c528cec4
612 diff --git a/src/src/ip.c b/src/src/ip.c
613 index 7991a58..2d71705 100644
616 @@ -455,7 +455,7 @@ time_t start_recv = time(NULL);
617 int time_left = timeout;
625 @@ -484,8 +484,10 @@ do
626 if (rc < 0 && errno == EINTR)
628 DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n");
630 /* Watch out, 'continue' jumps to the condition, not to the loops top */
631 - if (time_left = timeout - (time(NULL) - start_recv)) continue;
632 + time_left = timeout - (time(NULL) - start_recv);
633 + if (time_left > 0) continue;
638 commit 6c6d6e483411af2c087ff258f4041d38eb65e775
639 Author: Tony Finch <dot@dotat.at>
640 Date: Thu Aug 13 15:16:48 2015 +0100
642 Overhaul the debug_selector and log_selector machinery to support variable-length bit vectors. No functional change.
644 diff --git a/src/src/acl.c b/src/src/acl.c
645 index 91ee571..f2e0ef2 100644
648 @@ -4287,7 +4287,7 @@ while (acl != NULL)
651 acl_warn(where, *user_msgptr, *log_msgptr);
652 - else if (cond == DEFER && (log_extra_selector & LX_acl_warn_skipped) != 0)
653 + else if (cond == DEFER && LOGGING(acl_warn_skipped))
654 log_write(0, LOG_MAIN, "%s Warning: ACL \"warn\" statement skipped: "
655 "condition test deferred%s%s", host_and_ident(TRUE),
656 (*log_msgptr == NULL)? US"" : US": ",
657 diff --git a/src/src/daemon.c b/src/src/daemon.c
658 index 894a96f..2d10387 100644
659 --- a/src/src/daemon.c
660 +++ b/src/src/daemon.c
661 @@ -145,7 +145,7 @@ int dup_accept_socket = -1;
662 int max_for_this_host = 0;
665 -int use_log_write_selector = log_write_selector;
666 +int save_log_selector = *log_selector;
667 uschar *whofrom = NULL;
669 void *reset_point = store_get(0);
670 @@ -206,11 +206,11 @@ memory is reclaimed. */
672 whofrom = string_append(whofrom, &wfsize, &wfptr, 3, "[", sender_host_address, "]");
674 -if ((log_extra_selector & LX_incoming_port) != 0)
675 +if (LOGGING(incoming_port))
676 whofrom = string_append(whofrom, &wfsize, &wfptr, 2, ":", string_sprintf("%d",
679 -if ((log_extra_selector & LX_incoming_interface) != 0)
680 +if (LOGGING(incoming_interface))
681 whofrom = string_append(whofrom, &wfsize, &wfptr, 4, " I=[",
682 interface_address, "]:", string_sprintf("%d", interface_port));
684 @@ -338,11 +338,11 @@ the generalized logging code each time when the selector is false. If the
685 selector is set, check whether the host is on the list for logging. If not,
686 arrange to unset the selector in the subprocess. */
688 -if ((log_write_selector & L_smtp_connection) != 0)
689 +if (LOGGING(smtp_connection))
691 uschar *list = hosts_connection_nolog;
692 if (list != NULL && verify_check_host(&list) == OK)
693 - use_log_write_selector &= ~L_smtp_connection;
694 + save_log_selector &= ~L_smtp_connection;
696 log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s "
697 "(TCP/IP connection count = %d)", whofrom, smtp_accept_count + 1);
698 @@ -372,7 +372,7 @@ if (pid == 0)
700 /* May have been modified for the subprocess */
702 - log_write_selector = use_log_write_selector;
703 + *log_selector = save_log_selector;
705 /* Get the local interface address into permanent store */
707 diff --git a/src/src/deliver.c b/src/src/deliver.c
708 index 78f8f4b..c796de0 100644
709 --- a/src/src/deliver.c
710 +++ b/src/src/deliver.c
711 @@ -682,7 +682,7 @@ d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
713 s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
714 US" [", addr->host_used->address, US"]");
715 - if ((log_extra_selector & LX_outgoing_port) != 0)
716 + if (LOGGING(outgoing_port))
717 s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
718 addr->host_used->port));
720 @@ -692,10 +692,9 @@ d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
722 d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
724 - if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
725 + if (LOGGING(tls_cipher) && addr->cipher != NULL)
726 s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
727 - if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
728 - addr->cipher != NULL)
729 + if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
730 s = string_append(s, sizep, ptrp, 2, US" CV=",
731 testflag(addr, af_cert_verified)
733 @@ -706,7 +705,7 @@ d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
737 - if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
738 + if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
739 s = string_append(s, sizep, ptrp, 3, US" DN=\"",
740 string_printing(addr->peerdn), US"\"");
742 @@ -808,7 +807,7 @@ pointer to a single host item in their host list, for use by the transport. */
744 s = reset_point = store_get(size);
746 -log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
747 +log_address = string_log_address(addr, LOGGING(all_parents), TRUE);
749 s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address);
751 @@ -817,11 +816,11 @@ else
752 s = string_append(s, &size, &ptr, 2, US"> ", log_address);
755 -if (log_extra_selector & LX_incoming_interface && sending_ip_address)
756 +if (LOGGING(incoming_interface) && sending_ip_address)
757 s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
758 /* for the port: string_sprintf("%d", sending_port) */
760 -if ((log_extra_selector & LX_sender_on_delivery) != 0 || msg)
761 +if (LOGGING(sender_on_delivery) || msg)
762 s = string_append(s, &size, &ptr, 3, US" F=<",
763 #ifdef EXPERIMENTAL_INTERNATIONAL
764 testflag(addr, af_utf8_downcvt)
765 @@ -841,8 +840,7 @@ delivery; indeed, I did for some time, until this statement crashed. The case
766 when it is not set is for a delivery to /dev/null which is optimised by not
769 -if (used_return_path != NULL &&
770 - (log_extra_selector & LX_return_path_on_delivery) != 0)
771 +if (used_return_path != NULL && LOGGING(return_path_on_delivery))
772 s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
775 @@ -854,7 +852,7 @@ if (addr->router != NULL)
777 s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
779 -if ((log_extra_selector & LX_delivery_size) != 0)
780 +if (LOGGING(delivery_size))
781 s = string_append(s, &size, &ptr, 2, US" S=",
782 string_sprintf("%d", transport_count));
784 @@ -901,7 +899,7 @@ else
787 s = string_append(s, &size, &ptr, 2, US":", addr->auth_id);
788 - if (log_extra_selector & LX_smtp_mailauth && addr->auth_sndr)
789 + if (LOGGING(smtp_mailauth) && addr->auth_sndr)
790 s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr);
793 @@ -914,8 +912,7 @@ else
795 /* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
797 -if (log_extra_selector & LX_smtp_confirmation &&
799 +if (LOGGING(smtp_confirmation) && addr->message &&
800 (addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0))
803 @@ -935,11 +932,11 @@ if (log_extra_selector & LX_smtp_confirmation &&
805 /* Time on queue and actual time taken to deliver */
807 -if ((log_extra_selector & LX_queue_time) != 0)
808 +if (LOGGING(queue_time))
809 s = string_append(s, &size, &ptr, 2, US" QT=",
810 readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
812 -if ((log_extra_selector & LX_deliver_time) != 0)
813 +if (LOGGING(deliver_time))
814 s = string_append(s, &size, &ptr, 2, US" DT=",
815 readconf_printtime(addr->more_errno));
817 @@ -1230,8 +1227,7 @@ else if (result == DEFER || result == PANIC)
818 /* Create the address string for logging. Must not do this earlier, because
819 an OK result may be changed to FAIL when a pipe returns text. */
821 - log_address = string_log_address(addr,
822 - (log_write_selector & L_all_parents) != 0, result == OK);
823 + log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
825 s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
827 @@ -1342,18 +1338,16 @@ else
828 /* Create the address string for logging. Must not do this earlier, because
829 an OK result may be changed to FAIL when a pipe returns text. */
831 - log_address = string_log_address(addr,
832 - (log_write_selector & L_all_parents) != 0, result == OK);
833 + log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
835 s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
837 - if ((log_extra_selector & LX_sender_on_delivery) != 0)
838 + if (LOGGING(sender_on_delivery))
839 s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
841 /* Return path may not be set if no delivery actually happened */
843 - if (used_return_path != NULL &&
844 - (log_extra_selector & LX_return_path_on_delivery) != 0)
845 + if (used_return_path != NULL && LOGGING(return_path_on_delivery))
846 s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
848 if (addr->router != NULL)
849 @@ -4449,7 +4443,7 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
852 /* Local interface address/port */
853 - if (log_extra_selector & LX_incoming_interface && sending_ip_address)
854 + if (LOGGING(incoming_interface) && sending_ip_address)
856 uschar * ptr = big_buffer;
857 sprintf(CS ptr, "%.128s", sending_ip_address);
858 @@ -7365,7 +7359,7 @@ if (addr_defer == NULL)
860 /* Log the end of this message, with queue time if requested. */
862 - if ((log_extra_selector & LX_queue_time_overall) != 0)
863 + if (LOGGING(queue_time_overall))
864 log_write(0, LOG_MAIN, "Completed QT=%s",
865 readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
867 diff --git a/src/src/exim.c b/src/src/exim.c
868 index f9d57ab..d7cb5d8 100644
871 @@ -1639,6 +1639,10 @@ if (log_buffer == NULL)
875 +/* Initialize the default log options. */
877 +bits_set(log_selector, log_selector_size, log_default);
879 /* Set log_stderr to stderr, provided that stderr exists. This gets reset to
880 NULL when the daemon is run and the file is closed. We have to use this
881 indirection, because some systems don't allow writing to the variable "stderr".
882 @@ -2451,8 +2455,8 @@ for (i = 1; i < argc; i++)
886 - decode_bits(&selector, NULL, D_memory, 0, argrest, debug_options,
887 - debug_options_count, US"debug", 0);
888 + decode_bits(&selector, 1, debug_notall, argrest,
889 + debug_options, debug_options_count, US"debug", 0);
890 debug_selector = selector;
893 @@ -3787,14 +3791,17 @@ else
895 /* Handle the decoding of logging options. */
897 -decode_bits(&log_write_selector, &log_extra_selector, 0, 0,
898 +decode_bits(log_selector, log_selector_size, log_notall,
899 log_selector_string, log_options, log_options_count, US"log", 0);
904 debug_printf("configuration file is %s\n", config_main_filename);
905 - debug_printf("log selectors = %08x %08x\n", log_write_selector,
906 - log_extra_selector);
907 + debug_printf("log selectors =");
908 + for (i = 0; i < log_selector_size; i++)
909 + debug_printf(" %08x", log_selector[i]);
910 + debug_printf("\n");
913 /* If domain literals are not allowed, check the sender address that was
914 @@ -4001,7 +4008,7 @@ a debugging feature for finding out what arguments certain MUAs actually use.
915 Don't attempt it if logging is disabled, or if listing variables or if
916 verifying/testing addresses or expansions. */
918 -if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0)
919 +if (((debug_selector & D_any) != 0 || LOGGING(arguments))
920 && really_exim && !list_options && !checking)
923 @@ -4036,7 +4043,7 @@ if (((debug_selector & D_any) != 0 || (log_extra_selector & LX_arguments) != 0)
927 - if ((log_extra_selector & LX_arguments) != 0)
928 + if (LOGGING(arguments))
929 log_write(0, LOG_MAIN, "%s", big_buffer);
931 debug_printf("%s\n", big_buffer);
932 @@ -5021,7 +5028,7 @@ if (host_checking)
933 sender_host_address);
935 if (verify_check_host(&hosts_connection_nolog) == OK)
936 - log_write_selector &= ~L_smtp_connection;
937 + BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
938 log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
940 /* NOTE: We do *not* call smtp_log_no_mail() if smtp_start_session() fails,
941 @@ -5195,7 +5202,7 @@ if (smtp_input)
944 if (verify_check_host(&hosts_connection_nolog) == OK)
945 - log_write_selector &= ~L_smtp_connection;
946 + BIT_CLEAR(log_selector, log_selector_size, Li_smtp_connection);
947 log_write(L_smtp_connection, LOG_MAIN, "%s", smtp_get_connection_info());
948 if (!smtp_start_session())
950 diff --git a/src/src/functions.h b/src/src/functions.h
951 index 0257904..4af0017 100644
952 --- a/src/src/functions.h
953 +++ b/src/src/functions.h
954 @@ -99,6 +99,9 @@ extern int auth_get_no64_data(uschar **, uschar *);
955 extern uschar *auth_xtextencode(uschar *, int);
956 extern int auth_xtextdecode(uschar *, uschar **);
958 +extern void bits_clear(unsigned int *, size_t, int *);
959 +extern void bits_set(unsigned int *, size_t, int *);
961 extern void cancel_cutthrough_connection(const char *);
962 extern int check_host(void *, const uschar *, const uschar **, uschar **);
963 extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
964 @@ -123,8 +126,8 @@ extern void debug_print_ids(uschar *);
965 extern void debug_print_string(uschar *);
966 extern void debug_print_tree(tree_node *);
967 extern void debug_vprintf(const char *, va_list);
968 -extern void decode_bits(unsigned int *, unsigned int *,
969 - int, int, uschar *, bit_table *, int, uschar *, int);
970 +extern void decode_bits(unsigned int *, size_t, int *,
971 + uschar *, bit_table *, int, uschar *, int);
972 extern address_item *deliver_make_addr(uschar *, BOOL);
973 extern void deliver_init(void);
974 extern void delivery_log(int, address_item *, int, uschar *);
975 diff --git a/src/src/globals.c b/src/src/globals.c
976 index 66baffe..1344b5a 100644
977 --- a/src/src/globals.c
978 +++ b/src/src/globals.c
979 @@ -536,40 +536,45 @@ uschar *dccifd_options = US"header";
980 BOOL debug_daemon = FALSE;
982 FILE *debug_file = NULL;
983 -bit_table debug_options[] = {
984 - { US"acl", D_acl },
985 - { US"all", D_all },
986 - { US"auth", D_auth },
987 - { US"deliver", D_deliver },
988 - { US"dns", D_dns },
989 - { US"dnsbl", D_dnsbl },
990 - { US"exec", D_exec },
991 - { US"expand", D_expand },
992 - { US"filter", D_filter },
993 - { US"hints_lookup", D_hints_lookup },
994 - { US"host_lookup", D_host_lookup },
995 - { US"ident", D_ident },
996 - { US"interface", D_interface },
997 - { US"lists", D_lists },
998 - { US"load", D_load },
999 - { US"local_scan", D_local_scan },
1000 - { US"lookup", D_lookup },
1001 - { US"memory", D_memory },
1002 - { US"pid", D_pid },
1003 - { US"process_info", D_process_info },
1004 - { US"queue_run", D_queue_run },
1005 - { US"receive", D_receive },
1006 - { US"resolver", D_resolver },
1007 - { US"retry", D_retry },
1008 - { US"rewrite", D_rewrite },
1009 - { US"route", D_route },
1010 - { US"timestamp", D_timestamp },
1011 - { US"tls", D_tls },
1012 - { US"transport", D_transport },
1013 - { US"uid", D_uid },
1014 - { US"verify", D_verify }
1015 +int debug_notall[] = {
1019 -int debug_options_count = sizeof(debug_options)/sizeof(bit_table);
1020 +bit_table debug_options[] = { /* must be in alphabetical order */
1021 + BIT_TABLE(D, acl),
1022 + BIT_TABLE(D, all),
1023 + BIT_TABLE(D, auth),
1024 + BIT_TABLE(D, deliver),
1025 + BIT_TABLE(D, dns),
1026 + BIT_TABLE(D, dnsbl),
1027 + BIT_TABLE(D, exec),
1028 + BIT_TABLE(D, expand),
1029 + BIT_TABLE(D, filter),
1030 + BIT_TABLE(D, hints_lookup),
1031 + BIT_TABLE(D, host_lookup),
1032 + BIT_TABLE(D, ident),
1033 + BIT_TABLE(D, interface),
1034 + BIT_TABLE(D, lists),
1035 + BIT_TABLE(D, load),
1036 + BIT_TABLE(D, local_scan),
1037 + BIT_TABLE(D, lookup),
1038 + BIT_TABLE(D, memory),
1039 + BIT_TABLE(D, pid),
1040 + BIT_TABLE(D, process_info),
1041 + BIT_TABLE(D, queue_run),
1042 + BIT_TABLE(D, receive),
1043 + BIT_TABLE(D, resolver),
1044 + BIT_TABLE(D, retry),
1045 + BIT_TABLE(D, rewrite),
1046 + BIT_TABLE(D, route),
1047 + BIT_TABLE(D, timestamp),
1048 + BIT_TABLE(D, tls),
1049 + BIT_TABLE(D, transport),
1050 + BIT_TABLE(D, uid),
1051 + BIT_TABLE(D, verify),
1053 +int debug_options_count = nelem(debug_options);
1055 unsigned int debug_selector = 0;
1056 int delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 };
1057 uschar *delay_warning_condition=
1058 @@ -813,78 +818,91 @@ uid_t local_user_uid = (uid_t)(-1);
1059 tree_node *localpartlist_anchor= NULL;
1060 int localpartlist_count = 0;
1061 uschar *log_buffer = NULL;
1062 -unsigned int log_extra_selector = LX_default;
1064 +int log_default[] = { /* for initializing log_selector */
1065 + Li_acl_warn_skipped,
1066 + Li_connection_reject,
1067 + Li_delay_delivery,
1070 + Li_host_lookup_failed,
1071 + Li_lost_incoming_connection,
1073 + Li_rejected_header,
1075 + Li_sender_verify_fail,
1078 + Li_smtp_confirmation,
1079 + Li_tls_certificate_verified,
1084 uschar *log_file_path = US LOG_FILE_PATH
1085 "\0<--------------Space to patch log_file_path->";
1087 -/* Those log options with L_xxx identifiers have values less than 0x800000 and
1088 -are the ones that get put into log_write_selector. They can be used in calls to
1089 -log_write() to test for the bit. The options with LX_xxx identifiers have
1090 -values greater than 0x80000000 and are put into log_extra_selector (without the
1091 -top bit). They are never used in calls to log_write(), but are tested
1092 -independently. This separation became necessary when the number of log
1093 -selectors was getting close to filling a 32-bit word. */
1095 -/* Note that this list must be in alphabetical order. */
1097 -bit_table log_options[] = {
1098 - { US"8bitmime", LX_8bitmime },
1099 - { US"acl_warn_skipped", LX_acl_warn_skipped },
1100 - { US"address_rewrite", L_address_rewrite },
1101 - { US"all", L_all },
1102 - { US"all_parents", L_all_parents },
1103 - { US"arguments", LX_arguments },
1104 - { US"connection_reject", L_connection_reject },
1105 - { US"delay_delivery", L_delay_delivery },
1106 - { US"deliver_time", LX_deliver_time },
1107 - { US"delivery_size", LX_delivery_size },
1108 - { US"dnslist_defer", L_dnslist_defer },
1109 - { US"etrn", L_etrn },
1110 - { US"host_lookup_failed", L_host_lookup_failed },
1111 - { US"ident_timeout", LX_ident_timeout },
1112 - { US"incoming_interface", LX_incoming_interface },
1113 - { US"incoming_port", LX_incoming_port },
1114 - { US"lost_incoming_connection", L_lost_incoming_connection },
1115 - { US"outgoing_port", LX_outgoing_port },
1116 - { US"pid", LX_pid },
1117 +int log_notall[] = {
1120 +bit_table log_options[] = { /* must be in alphabetical order */
1121 + BIT_TABLE(L, 8bitmime),
1122 + BIT_TABLE(L, acl_warn_skipped),
1123 + BIT_TABLE(L, address_rewrite),
1124 + BIT_TABLE(L, all),
1125 + BIT_TABLE(L, all_parents),
1126 + BIT_TABLE(L, arguments),
1127 + BIT_TABLE(L, connection_reject),
1128 + BIT_TABLE(L, delay_delivery),
1129 + BIT_TABLE(L, deliver_time),
1130 + BIT_TABLE(L, delivery_size),
1131 + BIT_TABLE(L, dnslist_defer),
1132 + BIT_TABLE(L, etrn),
1133 + BIT_TABLE(L, host_lookup_failed),
1134 + BIT_TABLE(L, ident_timeout),
1135 + BIT_TABLE(L, incoming_interface),
1136 + BIT_TABLE(L, incoming_port),
1137 + BIT_TABLE(L, lost_incoming_connection),
1138 + BIT_TABLE(L, outgoing_port),
1139 + BIT_TABLE(L, pid),
1140 #ifdef EXPERIMENTAL_PROXY
1141 - { US"proxy", LX_proxy },
1142 + BIT_TABLE(L, proxy),
1144 - { US"queue_run", L_queue_run },
1145 - { US"queue_time", LX_queue_time },
1146 - { US"queue_time_overall", LX_queue_time_overall },
1147 - { US"received_recipients", LX_received_recipients },
1148 - { US"received_sender", LX_received_sender },
1149 - { US"rejected_header", LX_rejected_header },
1150 - { US"rejected_headers", LX_rejected_header },
1151 - { US"retry_defer", L_retry_defer },
1152 - { US"return_path_on_delivery", LX_return_path_on_delivery },
1153 - { US"sender_on_delivery", LX_sender_on_delivery },
1154 - { US"sender_verify_fail", LX_sender_verify_fail },
1155 - { US"size_reject", L_size_reject },
1156 - { US"skip_delivery", L_skip_delivery },
1157 - { US"smtp_confirmation", LX_smtp_confirmation },
1158 - { US"smtp_connection", L_smtp_connection },
1159 - { US"smtp_incomplete_transaction", L_smtp_incomplete_transaction },
1160 - { US"smtp_mailauth", LX_smtp_mailauth },
1161 - { US"smtp_no_mail", LX_smtp_no_mail },
1162 - { US"smtp_protocol_error", L_smtp_protocol_error },
1163 - { US"smtp_syntax_error", L_smtp_syntax_error },
1164 - { US"subject", LX_subject },
1165 - { US"tls_certificate_verified", LX_tls_certificate_verified },
1166 - { US"tls_cipher", LX_tls_cipher },
1167 - { US"tls_peerdn", LX_tls_peerdn },
1168 - { US"tls_sni", LX_tls_sni },
1169 - { US"unknown_in_list", LX_unknown_in_list }
1170 + BIT_TABLE(L, queue_run),
1171 + BIT_TABLE(L, queue_time),
1172 + BIT_TABLE(L, queue_time_overall),
1173 + BIT_TABLE(L, received_recipients),
1174 + BIT_TABLE(L, received_sender),
1175 + BIT_TABLE(L, rejected_header),
1176 + { US"rejected_headers", Li_rejected_header },
1177 + BIT_TABLE(L, retry_defer),
1178 + BIT_TABLE(L, return_path_on_delivery),
1179 + BIT_TABLE(L, sender_on_delivery),
1180 + BIT_TABLE(L, sender_verify_fail),
1181 + BIT_TABLE(L, size_reject),
1182 + BIT_TABLE(L, skip_delivery),
1183 + BIT_TABLE(L, smtp_confirmation),
1184 + BIT_TABLE(L, smtp_connection),
1185 + BIT_TABLE(L, smtp_incomplete_transaction),
1186 + BIT_TABLE(L, smtp_mailauth),
1187 + BIT_TABLE(L, smtp_no_mail),
1188 + BIT_TABLE(L, smtp_protocol_error),
1189 + BIT_TABLE(L, smtp_syntax_error),
1190 + BIT_TABLE(L, subject),
1191 + BIT_TABLE(L, tls_certificate_verified),
1192 + BIT_TABLE(L, tls_cipher),
1193 + BIT_TABLE(L, tls_peerdn),
1194 + BIT_TABLE(L, tls_sni),
1195 + BIT_TABLE(L, unknown_in_list),
1197 +int log_options_count = nelem(log_options);
1199 -int log_options_count = sizeof(log_options)/sizeof(bit_table);
1200 int log_reject_target = 0;
1201 +unsigned int log_selector[log_selector_size]; /* initialized in main() */
1202 uschar *log_selector_string = NULL;
1203 FILE *log_stderr = NULL;
1204 BOOL log_testing_mode = FALSE;
1205 BOOL log_timezone = FALSE;
1206 -unsigned int log_write_selector= L_default;
1207 uschar *login_sender_address = NULL;
1208 uschar *lookup_dnssec_authenticated = NULL;
1209 int lookup_open_max = 25;
1210 diff --git a/src/src/globals.h b/src/src/globals.h
1211 index ab03302..978a4cc 100644
1212 --- a/src/src/globals.h
1213 +++ b/src/src/globals.h
1214 @@ -319,6 +319,7 @@ extern uschar *dccifd_options; /* options for the dccifd daemon */
1215 extern BOOL debug_daemon; /* Debug the daemon process only */
1216 extern int debug_fd; /* The fd for debug_file */
1217 extern FILE *debug_file; /* Where to write debugging info */
1218 +extern int debug_notall[]; /* Debug options excluded from +all */
1219 extern bit_table debug_options[]; /* Table of debug options */
1220 extern int debug_options_count; /* Size of table */
1221 extern int delay_warning[]; /* Times between warnings */
1222 @@ -531,16 +532,17 @@ extern uid_t local_user_uid; /* As it says; may be set in routers */
1223 extern tree_node *localpartlist_anchor;/* Tree of defined localpart lists */
1224 extern int localpartlist_count; /* Number defined */
1225 extern uschar *log_buffer; /* For constructing log entries */
1226 -extern unsigned int log_extra_selector;/* Bit map of logging options other than used by log_write() */
1227 +extern int log_default[]; /* Initialization list for log_selector */
1228 extern uschar *log_file_path; /* If unset, use default */
1229 +extern int log_notall[]; /* Log options excluded from +all */
1230 extern bit_table log_options[]; /* Table of options */
1231 extern int log_options_count; /* Size of table */
1232 extern int log_reject_target; /* Target log for ACL rejections */
1233 +extern unsigned int log_selector[]; /* Bit map of logging options */
1234 extern uschar *log_selector_string; /* As supplied in the config */
1235 extern FILE *log_stderr; /* Copy of stderr for log use, or NULL */
1236 extern BOOL log_testing_mode; /* TRUE in various testing modes */
1237 extern BOOL log_timezone; /* TRUE to include the timezone in log lines */
1238 -extern unsigned int log_write_selector;/* Bit map of logging options for log_write() */
1239 extern uschar *login_sender_address; /* The actual sender address */
1240 extern lookup_info **lookup_list; /* Array of pointers to available lookups */
1241 extern int lookup_list_count; /* Number of entries in the list */
1242 diff --git a/src/src/host.c b/src/src/host.c
1243 index 31c2bbf..5c69c7f 100644
1244 --- a/src/src/host.c
1245 +++ b/src/src/host.c
1246 @@ -544,7 +544,7 @@ use this directly as the first item for Received: because it ain't an RFC 2822
1249 address = string_sprintf("[%s]:%d", sender_host_address, sender_host_port);
1250 -if ((log_extra_selector & LX_incoming_port) == 0 || sender_host_port <= 0)
1251 +if (!LOGGING(incoming_port) || sender_host_port <= 0)
1252 *(Ustrrchr(address, ':')) = 0;
1254 /* If there's no EHLO/HELO data, we can't show it. */
1255 @@ -695,8 +695,7 @@ else
1257 uschar *flag = useflag? US"H=" : US"";
1258 uschar *iface = US"";
1259 - if ((log_extra_selector & LX_incoming_interface) != 0 &&
1260 - interface_address != NULL)
1261 + if (LOGGING(incoming_interface) && interface_address != NULL)
1262 iface = string_sprintf(" I=[%s]:%d", interface_address, interface_port);
1263 if (sender_ident == NULL)
1264 (void)string_format(big_buffer, big_buffer_size, "%s%s%s",
1265 diff --git a/src/src/log.c b/src/src/log.c
1266 index 11b3edf..b2d1fcf 100644
1269 @@ -613,7 +613,7 @@ If a message_id exists, we include it after the timestamp.
1272 selector write to main log or LOG_INFO only if this value is zero, or if
1273 - its bit is set in log_write_selector
1274 + its bit is set in log_selector[0]
1275 flags each bit indicates some independent action:
1276 LOG_SENDER add raw sender to the message
1277 LOG_RECIPIENTS add raw recipients list to message
1278 @@ -749,15 +749,12 @@ DEBUG(D_any|D_v)
1279 Ustrcpy(ptr, "LOG:");
1282 - /* Show the options that were passed into the call. These are those whose
1283 - flag values do not have the 0x80000000 bit in them. Note that this
1284 - automatically exclude the "all" setting. */
1285 + /* Show the selector that was passed into the call. */
1287 for (i = 0; i < log_options_count; i++)
1289 unsigned int bit = log_options[i].bit;
1290 - if ((bit & 0x80000000) != 0) continue;
1291 - if ((selector & bit) != 0)
1292 + if (bit < BITWORDSIZE && selector == BIT(bit))
1295 Ustrcpy(ptr, log_options[i].name);
1296 @@ -809,7 +806,7 @@ ptr = log_buffer;
1297 sprintf(CS ptr, "%s ", tod_stamp(tod_log));
1300 -if ((log_extra_selector & LX_pid) != 0)
1303 sprintf(CS ptr, "[%d] ", (int)getpid());
1305 @@ -869,7 +866,7 @@ or unless there is no log_stderr (expn called from daemon, for example). */
1306 if (!really_exim || log_testing_mode)
1308 if (debug_selector == 0 && log_stderr != NULL &&
1309 - (selector == 0 || (selector & log_write_selector) != 0))
1310 + (selector == 0 || (selector & log_selector[0]) != 0))
1313 fprintf(log_stderr, "LOG: %s", CS(log_buffer + 20)); /* no timestamp */
1314 @@ -887,7 +884,7 @@ has been renamed. Therefore, do a stat() and see if the inode has changed, and
1317 if ((flags & LOG_MAIN) != 0 &&
1318 - (selector == 0 || (selector & log_write_selector) != 0))
1319 + (selector == 0 || (selector & log_selector[0]) != 0))
1321 if ((logging_mode & LOG_MODE_SYSLOG) != 0 &&
1322 (syslog_duplication || (flags & (LOG_REJECT|LOG_PANIC)) == 0))
1323 @@ -956,7 +953,7 @@ if ((flags & LOG_REJECT) != 0)
1327 - if (header_list != NULL && (log_extra_selector & LX_rejected_header) != 0)
1328 + if (header_list != NULL && LOGGING(rejected_header))
1330 if (recipients_count > 0)
1332 @@ -1142,6 +1139,35 @@ syslog_open = FALSE;
1335 /*************************************************
1336 +* Multi-bit set or clear *
1337 +*************************************************/
1339 +/* These functions take a list of bit indexes (terminated by -1) and
1340 +clear or set the corresponding bits in the selector.
1343 + selector address of the bit string
1344 + selsize number of words in the bit string
1345 + bits list of bits to set
1349 +bits_clear(unsigned int *selector, size_t selsize, int *bits)
1351 +for(; *bits != -1; ++bits)
1352 + BIT_CLEAR(selector, selsize, *bits);
1356 +bits_set(unsigned int *selector, size_t selsize, int *bits)
1358 +for(; *bits != -1; ++bits)
1359 + BIT_SET(selector, selsize, *bits);
1364 +/*************************************************
1365 * Decode bit settings for log/debug *
1366 *************************************************/
1368 @@ -1151,13 +1177,9 @@ also recognizes a numeric setting of the form =<number>, but this is not
1369 intended for user use. It's an easy way for Exim to pass the debug settings
1370 when it is re-exec'ed.
1372 -The log options are held in two unsigned ints (because there became too many
1373 -for one). The top bit in the table means "put in 2nd selector". This does not
1374 -yet apply to debug options, so the "=" facility sets only the first selector.
1376 -The "all" selector, which must be equal to 0xffffffff, is recognized specially.
1377 -It sets all the bits in both selectors. However, there is a facility for then
1378 -unsetting certain bits, because we want to turn off "memory" in the debug case.
1379 +The option table is a list of names and bit indexes. The index -1
1380 +means "set all bits, except for those listed in notall". The notall
1381 +list is terminated by -1.
1383 The action taken for bad values varies depending upon why we're here.
1384 For log messages, or if the debugging is triggered from config, then we write
1385 @@ -1165,10 +1187,9 @@ to the log on the way out. For debug setting triggered from the command-line,
1386 we treat it as an unknown option: error message to stderr and die.
1389 - selector1 address of the first bit string
1390 - selector2 address of the second bit string, or NULL
1391 - notall1 bits to exclude from "all" for selector1
1392 - notall2 bits to exclude from "all" for selector2
1393 + selector address of the bit string
1394 + selsize number of words in the bit string
1395 + notall list of bits to exclude from "all"
1396 string the configured string
1397 options the table of option names
1399 @@ -1179,9 +1200,8 @@ Returns: nothing on success - bomb out on failure
1403 -decode_bits(unsigned int *selector1, unsigned int *selector2, int notall1,
1404 - int notall2, uschar *string, bit_table *options, int count, uschar *which,
1406 +decode_bits(unsigned int *selector, size_t selsize, int *notall,
1407 + uschar *string, bit_table *options, int count, uschar *which, int flags)
1410 if (string == NULL) return;
1411 @@ -1189,7 +1209,8 @@ if (string == NULL) return;
1414 char *end; /* Not uschar */
1415 - *selector1 = strtoul(CS string+1, &end, 0);
1416 + memset(selector, 0, sizeof(*selector)*selsize);
1417 + *selector = strtoul(CS string+1, &end, 0);
1418 if (*end == 0) return;
1419 errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1421 @@ -1232,40 +1253,22 @@ else for(;;)
1422 if (middle->name[len] != 0) c = -1; else
1424 unsigned int bit = middle->bit;
1425 - unsigned int *selector;
1427 - /* The value with all bits set means "force all bits in both selectors"
1428 - in the case where two are being handled. However, the top bit in the
1429 - second selector is never set. When setting, some bits can be excluded.
1432 - if (bit == 0xffffffff)
1436 - *selector1 = 0xffffffff ^ notall1;
1437 - if (selector2 != NULL) *selector2 = 0x7fffffff ^ notall2;
1442 - if (selector2 != NULL) *selector2 = 0;
1446 - /* Otherwise, the 0x80000000 bit means "this value, without the top
1447 - bit, belongs in the second selector". */
1451 - if ((bit & 0x80000000) != 0)
1453 - selector = selector2;
1454 - bit &= 0x7fffffff;
1456 - else selector = selector1;
1457 - if (adding) *selector |= bit; else *selector &= ~bit;
1463 + memset(selector, -1, sizeof(*selector)*selsize);
1464 + bits_clear(selector, selsize, notall);
1467 + memset(selector, 0, sizeof(*selector)*selsize);
1470 + BIT_SET(selector, selsize, bit);
1472 + BIT_CLEAR(selector, selsize, bit);
1474 break; /* Out of loop to match selector name */
1477 @@ -1335,10 +1338,8 @@ if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
1479 debug_selector = D_default;
1482 - decode_bits(&debug_selector, NULL, D_memory, 0, opts,
1483 + decode_bits(&debug_selector, 1, debug_notall, opts,
1484 debug_options, debug_options_count, US"debug", DEBUG_FROM_CONFIG);
1487 /* When activating from a transport process we may never have logged at all
1488 resulting in certain setup not having been done. Hack this for now so we
1489 diff --git a/src/src/macros.h b/src/src/macros.h
1490 index 61f9ca6..d63025e 100644
1491 --- a/src/src/macros.h
1492 +++ b/src/src/macros.h
1493 @@ -321,46 +321,84 @@ for having to swallow the rest of an SMTP message is whether the value is
1494 #define END_SIZE 4 /* Reading ended because message too big */
1495 #define END_WERROR 5 /* Write error while reading the message */
1497 -/* Options bits for debugging; D_v and D_local_scan are also in local_scan.h */
1499 -#define D_v 0x00000001
1500 -#define D_local_scan 0x00000002
1502 -#define D_acl 0x00000004
1503 -#define D_auth 0x00000008
1504 -#define D_deliver 0x00000010
1505 -#define D_dns 0x00000020
1506 -#define D_dnsbl 0x00000040
1507 -#define D_exec 0x00000080
1508 -#define D_expand 0x00000100
1509 -#define D_filter 0x00000200
1510 -#define D_hints_lookup 0x00000400
1511 -#define D_host_lookup 0x00000800
1512 -#define D_ident 0x00001000
1513 -#define D_interface 0x00002000
1514 -#define D_lists 0x00004000
1515 -#define D_load 0x00008000
1516 -#define D_lookup 0x00010000
1517 -#define D_memory 0x00020000
1518 -#define D_pid 0x00040000
1519 -#define D_process_info 0x00080000
1520 -#define D_queue_run 0x00100000
1521 -#define D_receive 0x00200000
1522 -#define D_resolver 0x00400000
1523 -#define D_retry 0x00800000
1524 -#define D_rewrite 0x01000000
1525 -#define D_route 0x02000000
1526 -#define D_timestamp 0x04000000
1527 -#define D_tls 0x08000000
1528 -#define D_transport 0x10000000
1529 -#define D_uid 0x20000000
1530 -#define D_verify 0x40000000
1532 -/* The D_all value must always have all bits set, as it is recognized specially
1533 -by the function that decodes debug and log selectors. This is to enable it to
1534 -set all the bits in a multi-word selector. Debug doesn't use this yet, but we
1535 -are getting close. In fact, we want to omit "memory" for -d+all, but can't
1536 -handle this here. It is fudged externally. */
1537 +/* Bit masks for debug and log selectors */
1539 +/* Assume words are 32 bits wide. Tiny waste of space on 64 bit
1540 +platforms, but this ensures bit vectors always work the same way. */
1541 +#define BITWORDSIZE 32
1543 +/* This macro is for single-word bit vectors: the debug selector,
1544 +and the first word of the log selector. */
1545 +#define BIT(n) (1 << (n))
1547 +/* And these are for multi-word vectors. */
1548 +#define BITWORD(n) ( (n) / BITWORDSIZE)
1549 +#define BITMASK(n) (1 << (n) % BITWORDSIZE)
1551 +#define BIT_CLEAR(s,z,n) ((s)[BITWORD(n)] &= ~BITMASK(n))
1552 +#define BIT_SET(s,z,n) ((s)[BITWORD(n)] |= BITMASK(n))
1553 +#define BIT_TEST(s,z,n) (((s)[BITWORD(n)] & BITMASK(n)) != 0)
1555 +/* Used in globals.c for initializing bit_table structures. T will be either
1556 +D or L correspondong to the debug and log selector bits declared below. */
1558 +#define BIT_TABLE(T,name) { US #name, T##i_##name }
1560 +/* IOTA allows us to keep an implicit sequential count, like a simple enum,
1561 +but we can have sequentially numbered identifiers which are not declared
1562 +sequentially. We use this for more compact declarations of bit indexes and
1563 +masks, alternating between sequential bit index and corresponding mask. */
1565 +#define IOTA(iota) (__LINE__ - iota)
1566 +#define IOTA_INIT(zero) (__LINE__ - zero + 1)
1568 +/* Options bits for debugging. DEBUG_BIT() declares both a bit index and the
1569 +corresponding mask. Di_all is a special value recognized by decode_bits().
1571 +Exim's code assumes in a number of places that the debug_selector is one
1572 +word, and this is exposed in the local_scan ABI. The D_v and D_local_scan bit
1573 +masks are part of the local_scan API so are #defined in local_scan.h */
1575 +#define DEBUG_BIT(name) Di_##name = IOTA(Di_iota), D_##name = BIT(Di_##name)
1580 + Di_local_scan = 1,
1582 + Di_iota = IOTA_INIT(2),
1585 + DEBUG_BIT(deliver),
1589 + DEBUG_BIT(expand),
1590 + DEBUG_BIT(filter),
1591 + DEBUG_BIT(hints_lookup),
1592 + DEBUG_BIT(host_lookup),
1594 + DEBUG_BIT(interface),
1597 + DEBUG_BIT(lookup),
1598 + DEBUG_BIT(memory),
1600 + DEBUG_BIT(process_info),
1601 + DEBUG_BIT(queue_run),
1602 + DEBUG_BIT(receive),
1603 + DEBUG_BIT(resolver),
1605 + DEBUG_BIT(rewrite),
1607 + DEBUG_BIT(timestamp),
1609 + DEBUG_BIT(transport),
1611 + DEBUG_BIT(verify),
1614 +/* Multi-bit debug masks */
1616 #define D_all 0xffffffff
1618 @@ -380,81 +418,67 @@ handle this here. It is fudged externally. */
1622 -/* Options bits for logging. Those that will end up in log_write_selector have
1623 -values < 0x80000000. They can be used in calls to log_write(). The others have
1624 -values > 0x80000000 and are put into log_extra_selector (without the top bit).
1625 -These are only ever tested independently. "All" is a magic value that is used
1626 -only in the name table to set all options in both bit maps. */
1628 -/* The L_all value must always have all bits set, as it is recognized specially
1629 -by the function that decodes debug and log selectors. This is to enable it to
1630 -set all the bits in a multi-word selector. */
1632 -#define L_all 0xffffffff
1634 -#define L_address_rewrite 0x00000001
1635 -#define L_all_parents 0x00000002
1636 -#define L_connection_reject 0x00000004
1637 -#define L_delay_delivery 0x00000008
1638 -#define L_dnslist_defer 0x00000010
1639 -#define L_etrn 0x00000020
1640 -#define L_host_lookup_failed 0x00000040
1641 -#define L_lost_incoming_connection 0x00000080
1642 -#define L_queue_run 0x00000100
1643 -#define L_retry_defer 0x00000200
1644 -#define L_size_reject 0x00000400
1645 -#define L_skip_delivery 0x00000800
1646 -#define L_smtp_connection 0x00001000
1647 -#define L_smtp_incomplete_transaction 0x00002000
1648 -#define L_smtp_protocol_error 0x00004000
1649 -#define L_smtp_syntax_error 0x00008000
1651 -#define LX_acl_warn_skipped 0x80000001
1652 -#define LX_arguments 0x80000002
1653 -#define LX_deliver_time 0x80000004
1654 -#define LX_delivery_size 0x80000008
1655 -#define LX_ident_timeout 0x80000010
1656 -#define LX_incoming_interface 0x80000020
1657 -#define LX_incoming_port 0x80000040
1658 -#define LX_outgoing_port 0x80000080
1659 -#define LX_pid 0x80000100
1660 -#define LX_queue_time 0x80000200
1661 -#define LX_queue_time_overall 0x80000400
1662 -#define LX_received_sender 0x80000800
1663 -#define LX_received_recipients 0x80001000
1664 -#define LX_rejected_header 0x80002000
1665 -#define LX_return_path_on_delivery 0x80004000
1666 -#define LX_sender_on_delivery 0x80008000
1667 -#define LX_sender_verify_fail 0x80010000
1668 -#define LX_smtp_confirmation 0x80020000
1669 -#define LX_smtp_no_mail 0x80040000
1670 -#define LX_subject 0x80080000
1671 -#define LX_tls_certificate_verified 0x80100000
1672 -#define LX_tls_cipher 0x80200000
1673 -#define LX_tls_peerdn 0x80400000
1674 -#define LX_tls_sni 0x80800000
1675 -#define LX_unknown_in_list 0x81000000
1676 -#define LX_8bitmime 0x82000000
1677 -#define LX_smtp_mailauth 0x84000000
1678 -#define LX_proxy 0x88000000
1680 -#define L_default (L_connection_reject | \
1681 - L_delay_delivery | \
1682 - L_dnslist_defer | \
1684 - L_host_lookup_failed | \
1685 - L_lost_incoming_connection | \
1691 -#define LX_default ((LX_acl_warn_skipped | \
1692 - LX_rejected_header | \
1693 - LX_sender_verify_fail | \
1694 - LX_smtp_confirmation | \
1695 - LX_tls_certificate_verified| \
1696 - LX_tls_cipher) & 0x7fffffff)
1697 +/* Options bits for logging. Those that have values < BITWORDSIZE can be used
1698 +in calls to log_write(). The others are put into later words in log_selector
1699 +and are only ever tested independently, so they do not need bit mask
1700 +declarations. The Li_all value is recognized specially by decode_bits(). */
1702 +#define LOG_BIT(name) Li_##name = IOTA(Li_iota), L_##name = BIT(Li_##name)
1707 + Li_iota = IOTA_INIT(0),
1708 + LOG_BIT(address_rewrite),
1709 + LOG_BIT(all_parents),
1710 + LOG_BIT(connection_reject),
1711 + LOG_BIT(delay_delivery),
1712 + LOG_BIT(dnslist_defer),
1714 + LOG_BIT(host_lookup_failed),
1715 + LOG_BIT(lost_incoming_connection),
1716 + LOG_BIT(queue_run),
1717 + LOG_BIT(retry_defer),
1718 + LOG_BIT(size_reject),
1719 + LOG_BIT(skip_delivery),
1720 + LOG_BIT(smtp_connection),
1721 + LOG_BIT(smtp_incomplete_transaction),
1722 + LOG_BIT(smtp_protocol_error),
1723 + LOG_BIT(smtp_syntax_error),
1725 + Li_acl_warn_skipped = BITWORDSIZE,
1730 + Li_incoming_interface,
1735 + Li_queue_time_overall,
1736 + Li_received_sender,
1737 + Li_received_recipients,
1738 + Li_rejected_header,
1739 + Li_return_path_on_delivery,
1740 + Li_sender_on_delivery,
1741 + Li_sender_verify_fail,
1742 + Li_smtp_confirmation,
1745 + Li_tls_certificate_verified,
1749 + Li_unknown_in_list,
1754 + log_selector_size = BITWORD(Li_proxy) + 1
1757 +#define LOGGING(opt) BIT_TEST(log_selector, log_selector_size, Li_##opt)
1759 /* Private error numbers for delivery failures, set negative so as not
1760 to conflict with system errno values. */
1761 diff --git a/src/src/match.c b/src/src/match.c
1762 index 9e47110..fa42187 100644
1763 --- a/src/src/match.c
1764 +++ b/src/src/match.c
1765 @@ -771,7 +771,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
1766 include_unknown? "yes":"no", error);
1767 if (!include_unknown)
1769 - if ((log_extra_selector & LX_unknown_in_list) != 0)
1770 + if (LOGGING(unknown_in_list))
1771 log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
1774 @@ -880,7 +880,7 @@ while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
1776 if (!include_unknown)
1778 - if ((log_extra_selector & LX_unknown_in_list) != 0)
1779 + if (LOGGING(unknown_in_list))
1780 log_write(0, LOG_MAIN, "list matching forced to fail: %s", error);
1783 diff --git a/src/src/rda.c b/src/src/rda.c
1784 index 7596466..2afd6dc 100644
1787 @@ -635,7 +635,7 @@ if ((pid = fork()) == 0)
1789 DEBUG(D_rewrite) debug_printf("turned off address rewrite logging (not "
1790 "root or exim in this process)\n");
1791 - log_write_selector &= ~L_address_rewrite;
1792 + BIT_CLEAR(log_selector, log_selector_size, Li_address_rewrite);
1795 /* Now do the business */
1796 diff --git a/src/src/receive.c b/src/src/receive.c
1797 index 64cf1ae..b430ee2 100644
1798 --- a/src/src/receive.c
1799 +++ b/src/src/receive.c
1800 @@ -1118,8 +1118,7 @@ add_host_info_for_log(uschar *s, int *sizeptr, int *ptrptr)
1801 if (sender_fullhost != NULL)
1803 s = string_append(s, sizeptr, ptrptr, 2, US" H=", sender_fullhost);
1804 - if ((log_extra_selector & LX_incoming_interface) != 0 &&
1805 - interface_address != NULL)
1806 + if (LOGGING(incoming_interface) && interface_address != NULL)
1808 uschar *ss = string_sprintf(" I=[%s]:%d", interface_address,
1810 @@ -2529,7 +2528,7 @@ if (msgid_header == NULL &&
1811 rewriting. Must copy the count, because later ACLs and the local_scan()
1812 function may mess with the real recipients. */
1814 -if ((log_extra_selector & LX_received_recipients) != 0)
1815 +if (LOGGING(received_recipients))
1817 raw_recipients = store_get(recipients_count * sizeof(uschar *));
1818 for (i = 0; i < recipients_count; i++)
1819 @@ -3573,7 +3572,7 @@ else
1822 case LOCAL_SCAN_REJECT_NOLOGHDR:
1823 - log_extra_selector &= ~LX_rejected_header;
1824 + BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
1827 case LOCAL_SCAN_REJECT:
1828 @@ -3582,7 +3581,7 @@ else
1831 case LOCAL_SCAN_TEMPREJECT_NOLOGHDR:
1832 - log_extra_selector &= ~LX_rejected_header;
1833 + BIT_CLEAR(log_selector, log_selector_size, Li_rejected_header);
1836 case LOCAL_SCAN_TEMPREJECT:
1837 @@ -3747,15 +3746,15 @@ if (message_reference != NULL)
1838 s = add_host_info_for_log(s, &size, &sptr);
1841 -if (log_extra_selector & LX_tls_cipher && tls_in.cipher)
1842 +if (LOGGING(tls_cipher) && tls_in.cipher)
1843 s = string_append(s, &size, &sptr, 2, US" X=", tls_in.cipher);
1844 -if (log_extra_selector & LX_tls_certificate_verified && tls_in.cipher)
1845 +if (LOGGING(tls_certificate_verified) && tls_in.cipher)
1846 s = string_append(s, &size, &sptr, 2, US" CV=",
1847 tls_in.certificate_verified? "yes":"no");
1848 -if (log_extra_selector & LX_tls_peerdn && tls_in.peerdn)
1849 +if (LOGGING(tls_peerdn) && tls_in.peerdn)
1850 s = string_append(s, &size, &sptr, 3, US" DN=\"",
1851 string_printing(tls_in.peerdn), US"\"");
1852 -if (log_extra_selector & LX_tls_sni && tls_in.sni)
1853 +if (LOGGING(tls_sni) && tls_in.sni)
1854 s = string_append(s, &size, &sptr, 3, US" SNI=\"",
1855 string_printing(tls_in.sni), US"\"");
1857 @@ -3766,7 +3765,7 @@ if (sender_host_authenticated)
1858 if (authenticated_id != NULL)
1860 s = string_append(s, &size, &sptr, 2, US":", authenticated_id);
1861 - if (log_extra_selector & LX_smtp_mailauth && authenticated_sender != NULL)
1862 + if (LOGGING(smtp_mailauth) && authenticated_sender != NULL)
1863 s = string_append(s, &size, &sptr, 2, US":", authenticated_sender);
1866 @@ -3777,7 +3776,7 @@ if (prdr_requested)
1869 #ifdef EXPERIMENTAL_PROXY
1870 -if (proxy_session && log_extra_selector & LX_proxy)
1871 +if (proxy_session && LOGGING(proxy))
1872 s = string_append(s, &size, &sptr, 2, US" PRX=", proxy_host_address);
1875 @@ -3788,7 +3787,7 @@ s = string_append(s, &size, &sptr, 2, US" S=", big_buffer);
1879 -if (log_extra_selector & LX_8bitmime)
1880 +if (LOGGING(8bitmime))
1882 sprintf(CS big_buffer, "%d", body_8bitmime);
1883 s = string_append(s, &size, &sptr, 2, US" M8S=", big_buffer);
1884 @@ -3814,7 +3813,7 @@ if (msgid_header != NULL)
1885 /* If subject logging is turned on, create suitable printing-character
1886 text. By expanding $h_subject: we make use of the MIME decoding. */
1888 -if ((log_extra_selector & LX_subject) != 0 && subject_header != NULL)
1889 +if (LOGGING(subject) && subject_header != NULL)
1892 uschar *p = big_buffer;
1893 @@ -4003,8 +4002,8 @@ if(!smtp_reply)
1896 log_write(0, LOG_MAIN |
1897 - (((log_extra_selector & LX_received_recipients) != 0)? LOG_RECIPIENTS : 0) |
1898 - (((log_extra_selector & LX_received_sender) != 0)? LOG_SENDER : 0),
1899 + (LOGGING(received_recipients)? LOG_RECIPIENTS : 0) |
1900 + (LOGGING(received_sender)? LOG_SENDER : 0),
1903 /* Log any control actions taken by an ACL or local_scan(). */
1904 diff --git a/src/src/rewrite.c b/src/src/rewrite.c
1905 index 296fe8c..ca7fb6a 100644
1906 --- a/src/src/rewrite.c
1907 +++ b/src/src/rewrite.c
1908 @@ -247,8 +247,7 @@ for (rule = rewrite_rules;
1910 /* We have a validly rewritten address */
1912 - if ((log_write_selector & L_address_rewrite) != 0 ||
1913 - (debug_selector & D_rewrite) != 0)
1914 + if (LOGGING(address_rewrite) || (debug_selector & D_rewrite) != 0)
1917 const uschar *where = CUS"?";
1918 diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
1919 index effc636..9982451 100644
1920 --- a/src/src/smtp_in.c
1921 +++ b/src/src/smtp_in.c
1922 @@ -1234,8 +1234,7 @@ if (sender_host_unknown || sender_host_notsocket)
1924 return string_sprintf("SMTP connection from %s (via inetd)", hostname);
1926 -if ((log_extra_selector & LX_incoming_interface) != 0 &&
1927 - interface_address != NULL)
1928 +if (LOGGING(incoming_interface) && interface_address != NULL)
1929 return string_sprintf("SMTP connection from %s I=[%s]:%d", hostname,
1930 interface_address, interface_port);
1932 @@ -1260,16 +1259,15 @@ s_tlslog(uschar * s, int * sizep, int * ptrp)
1933 int size = sizep ? *sizep : 0;
1934 int ptr = ptrp ? *ptrp : 0;
1936 - if ((log_extra_selector & LX_tls_cipher) != 0 && tls_in.cipher != NULL)
1937 + if (LOGGING(tls_cipher) && tls_in.cipher != NULL)
1938 s = string_append(s, &size, &ptr, 2, US" X=", tls_in.cipher);
1939 - if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
1940 - tls_in.cipher != NULL)
1941 + if (LOGGING(tls_certificate_verified) && tls_in.cipher != NULL)
1942 s = string_append(s, &size, &ptr, 2, US" CV=",
1943 tls_in.certificate_verified? "yes":"no");
1944 - if ((log_extra_selector & LX_tls_peerdn) != 0 && tls_in.peerdn != NULL)
1945 + if (LOGGING(tls_peerdn) && tls_in.peerdn != NULL)
1946 s = string_append(s, &size, &ptr, 3, US" DN=\"",
1947 string_printing(tls_in.peerdn), US"\"");
1948 - if ((log_extra_selector & LX_tls_sni) != 0 && tls_in.sni != NULL)
1949 + if (LOGGING(tls_sni) && tls_in.sni != NULL)
1950 s = string_append(s, &size, &ptr, 3, US" SNI=\"",
1951 string_printing(tls_in.sni), US"\"");
1953 @@ -1301,7 +1299,7 @@ smtp_log_no_mail(void)
1957 -if (smtp_mailcmd_count > 0 || (log_extra_selector & LX_smtp_no_mail) == 0)
1958 +if (smtp_mailcmd_count > 0 || !LOGGING(smtp_no_mail))
1962 @@ -2510,8 +2508,8 @@ static void
1963 incomplete_transaction_log(uschar *what)
1965 if (sender_address == NULL || /* No transaction in progress */
1966 - (log_write_selector & L_smtp_incomplete_transaction) == 0 /* Not logging */
1968 + !LOGGING(smtp_incomplete_transaction))
1971 /* Build list of recipients for logging */
1973 @@ -2762,7 +2760,7 @@ if (sender_verified_failed != NULL &&
1975 setflag(sender_verified_failed, af_sverify_told);
1977 - if (rc != FAIL || (log_extra_selector & LX_sender_verify_fail) != 0)
1978 + if (rc != FAIL || LOGGING(sender_verify_fail))
1979 log_write(0, LOG_MAIN|LOG_REJECT, "%s sender verify %s for <%s>%s",
1980 host_and_ident(TRUE),
1981 ((sender_verified_failed->special_action & 255) == DEFER)? "defer":"fail",
1982 diff --git a/src/src/structs.h b/src/src/structs.h
1983 index 6f143d6..438b521 100644
1984 --- a/src/src/structs.h
1985 +++ b/src/src/structs.h
1986 @@ -38,7 +38,7 @@ typedef struct macro_item {
1988 typedef struct bit_table {
1994 /* Block for holding a uid and gid, possibly unset, and an initgroups flag. */
1995 diff --git a/src/src/tls-openssl.c b/src/src/tls-openssl.c
1996 index b1dccb8..73ac807 100644
1997 --- a/src/src/tls-openssl.c
1998 +++ b/src/src/tls-openssl.c
1999 @@ -1111,8 +1111,7 @@ len = SSL_get_tlsext_status_ocsp_resp(s, &p);
2002 /* Expect this when we requested ocsp but got none */
2003 - if ( cbinfo->u_ocsp.client.verify_required
2004 - && log_extra_selector & LX_tls_cipher)
2005 + if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher))
2006 log_write(0, LOG_MAIN, "Received TLS status callback, null content");
2008 DEBUG(D_tls) debug_printf(" null\n");
2009 @@ -1122,7 +1121,7 @@ if(!p)
2010 if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
2012 tls_out.ocsp = OCSP_FAILED;
2013 - if (log_extra_selector & LX_tls_cipher)
2014 + if (LOGGING(tls_cipher))
2015 log_write(0, LOG_MAIN, "Received TLS cert status response, parse error");
2017 DEBUG(D_tls) debug_printf(" parse error\n");
2018 @@ -1132,7 +1131,7 @@ if(!(rsp = d2i_OCSP_RESPONSE(NULL, &p, len)))
2019 if(!(bs = OCSP_response_get1_basic(rsp)))
2021 tls_out.ocsp = OCSP_FAILED;
2022 - if (log_extra_selector & LX_tls_cipher)
2023 + if (LOGGING(tls_cipher))
2024 log_write(0, LOG_MAIN, "Received TLS cert status response, error parsing response");
2026 DEBUG(D_tls) debug_printf(" error parsing response\n");
2027 @@ -1163,7 +1162,7 @@ if(!(bs = OCSP_response_get1_basic(rsp)))
2028 cbinfo->u_ocsp.client.verify_store, 0)) <= 0)
2030 tls_out.ocsp = OCSP_FAILED;
2031 - if (log_extra_selector & LX_tls_cipher)
2032 + if (LOGGING(tls_cipher))
2033 log_write(0, LOG_MAIN, "Received TLS cert status response, itself unverifiable");
2034 BIO_printf(bp, "OCSP response verify failure\n");
2035 ERR_print_errors(bp);
2036 diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c
2037 index 0cd89af..1f4d7a6 100644
2038 --- a/src/src/transports/lmtp.c
2039 +++ b/src/src/transports/lmtp.c
2040 @@ -654,7 +654,7 @@ if (send_data)
2041 if (lmtp_read_response(out, buffer, sizeof(buffer), '2', timeout))
2043 addr->transport_return = OK;
2044 - if ((log_extra_selector & LX_smtp_confirmation) != 0)
2045 + if (LOGGING(smtp_confirmation))
2047 const uschar *s = string_printing(buffer);
2048 /* de-const safe here as string_printing known to have alloc'n'copied */
2049 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
2050 index a952413..609dba3 100644
2051 --- a/src/src/transports/smtp.c
2052 +++ b/src/src/transports/smtp.c
2053 @@ -638,7 +638,7 @@ if (addr->message)
2057 - if (log_extra_selector & LX_outgoing_port)
2058 + if (LOGGING(outgoing_port))
2059 message = string_sprintf("%s:%d", message,
2060 host->port == PORT_NONE ? 25 : host->port);
2061 log_write(0, LOG_MAIN, "%s %s", message, strerror(addr->basic_errno));
2062 @@ -2380,7 +2380,7 @@ if (!ok) ok = TRUE; else
2065 #ifndef EXPERIMENTAL_EVENT
2066 - (log_extra_selector & LX_smtp_confirmation) != 0 &&
2067 + LOGGING(smtp_confirmation) &&
2071 @@ -2435,7 +2435,7 @@ if (!ok) ok = TRUE; else
2074 completed_address = TRUE; /* NOW we can set this flag */
2075 - if ((log_extra_selector & LX_smtp_confirmation) != 0)
2076 + if (LOGGING(smtp_confirmation))
2078 const uschar *s = string_printing(buffer);
2079 /* deconst cast ok here as string_printing was checked to have alloc'n'copied */
2080 diff --git a/src/src/verify.c b/src/src/verify.c
2081 index e00e7b9..7992d58 100644
2082 --- a/src/src/verify.c
2083 +++ b/src/src/verify.c
2084 @@ -2916,7 +2916,7 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0)
2085 if (ip_connect(sock, host_af, sender_host_address, port, rfc1413_query_timeout)
2088 - if (errno == ETIMEDOUT && (log_extra_selector & LX_ident_timeout) != 0)
2089 + if (errno == ETIMEDOUT && LOGGING(ident_timeout))
2091 log_write(0, LOG_MAIN, "ident connection to %s timed out",
2092 sender_host_address);
2094 commit ac881e2749754fbe167b5f38784dd85b088571cf
2095 Author: Tony Finch <dot@dotat.at>
2096 Date: Thu Aug 13 15:16:51 2015 +0100
2098 Improve the consistency of logging incoming and outgoing interfaces.
2100 The I= interface field on outgoing lines is now after the H= remote
2101 host field, same as incoming lines. There is a separate outgoing_interface
2102 log selector which allows you to disable the outgoing I= field.
2104 (slight massaging by JH)
2106 diff --git a/src/src/deliver.c b/src/src/deliver.c
2107 index c796de0..0e7cea3 100644
2108 --- a/src/src/deliver.c
2109 +++ b/src/src/deliver.c
2110 @@ -676,39 +676,78 @@ while (addr->parent != NULL)
2114 +/*************************************************
2115 +* Delivery logging support functions *
2116 +*************************************************/
2118 +/* The LOGGING() checks in d_log_interface() are complicated for backwards
2119 +compatibility. When outgoing interface logging was originally added, it was
2120 +conditional on just incoming_interface (which is off by default). The
2121 +outgoing_interface option is on by default to preserve this behaviour, but
2122 +you can enable incoming_interface and disable outgoing_interface to get I=
2123 +fields on incoming lines only.
2126 + s The log line buffer
2127 + sizep Pointer to the buffer size
2128 + ptrp Pointer to current index into buffer
2129 + addr The address to be logged
2131 +Returns: New value for s
2135 -d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
2136 +d_log_interface(uschar *s, int *sizep, int *ptrp)
2138 - s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
2139 - US" [", addr->host_used->address, US"]");
2140 +if (LOGGING(incoming_interface) && LOGGING(outgoing_interface)
2141 + && sending_ip_address != NULL)
2143 + s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address);
2144 if (LOGGING(outgoing_port))
2145 - s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
2146 - addr->host_used->port));
2148 + s = string_append(s, sizep, ptrp, 2, US"]:",
2149 + string_sprintf("%d", sending_port));
2151 + s = string_cat(s, sizep, ptrp, "]", 1);
2159 +d_hostlog(uschar *s, int *sizep, int *ptrp, address_item *addr)
2161 +s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
2162 + US" [", addr->host_used->address, US"]");
2163 +if (LOGGING(outgoing_port))
2164 + s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
2165 + addr->host_used->port));
2166 +return d_log_interface(s, sizep, ptrp);
2173 d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
2175 - if (LOGGING(tls_cipher) && addr->cipher != NULL)
2176 - s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
2177 - if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
2178 - s = string_append(s, sizep, ptrp, 2, US" CV=",
2179 - testflag(addr, af_cert_verified)
2181 +if (LOGGING(tls_cipher) && addr->cipher != NULL)
2182 + s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
2183 +if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
2184 + s = string_append(s, sizep, ptrp, 2, US" CV=",
2185 + testflag(addr, af_cert_verified)
2187 #ifdef EXPERIMENTAL_DANE
2188 - testflag(addr, af_dane_verified)
2191 + testflag(addr, af_dane_verified)
2197 - if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
2198 - s = string_append(s, sizep, ptrp, 3, US" DN=\"",
2199 - string_printing(addr->peerdn), US"\"");
2203 +if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
2204 + s = string_append(s, sizep, ptrp, 3, US" DN=\"",
2205 + string_printing(addr->peerdn), US"\"");
2210 @@ -816,10 +855,6 @@ else
2211 s = string_append(s, &size, &ptr, 2, US"> ", log_address);
2214 -if (LOGGING(incoming_interface) && sending_ip_address)
2215 - s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
2216 - /* for the port: string_sprintf("%d", sending_port) */
2218 if (LOGGING(sender_on_delivery) || msg)
2219 s = string_append(s, &size, &ptr, 3, US" F=<",
2220 #ifdef EXPERIMENTAL_INTERNATIONAL
2221 @@ -862,6 +897,7 @@ if (addr->transport->info->local)
2223 if (addr->host_list)
2224 s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
2225 + s = d_log_interface(s, &size, &ptr);
2226 if (addr->shadow_message != NULL)
2227 s = string_cat(s, &size, &ptr, addr->shadow_message,
2228 Ustrlen(addr->shadow_message));
2229 diff --git a/src/src/globals.c b/src/src/globals.c
2230 index 1344b5a..4188b4d 100644
2231 --- a/src/src/globals.c
2232 +++ b/src/src/globals.c
2233 @@ -827,6 +827,7 @@ int log_default[] = { /* for initializing log_selector */
2235 Li_host_lookup_failed,
2236 Li_lost_incoming_connection,
2237 + Li_outgoing_interface, /* see d_log_interface in deliver.c */
2241 @@ -863,6 +864,7 @@ bit_table log_options[] = { /* must be in alphabetical order */
2242 BIT_TABLE(L, incoming_interface),
2243 BIT_TABLE(L, incoming_port),
2244 BIT_TABLE(L, lost_incoming_connection),
2245 + BIT_TABLE(L, outgoing_interface),
2246 BIT_TABLE(L, outgoing_port),
2248 #ifdef EXPERIMENTAL_PROXY
2249 diff --git a/src/src/log.c b/src/src/log.c
2250 index b2d1fcf..558c000 100644
2253 @@ -753,8 +753,8 @@ DEBUG(D_any|D_v)
2255 for (i = 0; i < log_options_count; i++)
2257 - unsigned int bit = log_options[i].bit;
2258 - if (bit < BITWORDSIZE && selector == BIT(bit))
2259 + unsigned int bitnum = log_options[i].bit;
2260 + if (bitnum < BITWORDSIZE && selector == BIT(bitnum))
2263 Ustrcpy(ptr, log_options[i].name);
2264 diff --git a/src/src/macros.h b/src/src/macros.h
2265 index d63025e..0ce24f8 100644
2266 --- a/src/src/macros.h
2267 +++ b/src/src/macros.h
2268 @@ -474,8 +474,9 @@ enum {
2272 + Li_outgoing_interface,
2274 - log_selector_size = BITWORD(Li_proxy) + 1
2275 + log_selector_size = BITWORD(Li_outgoing_interface) + 1
2278 #define LOGGING(opt) BIT_TEST(log_selector, log_selector_size, Li_##opt)
2280 commit 6b51df8340eacc95e3def9a4376506610e91996c
2281 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
2282 Date: Wed Aug 19 15:22:41 2015 +0200
2284 Fix post-transport-crash.
2286 The crash probably was introduced in a39bd74d3e94 and
2287 needs 'split_spool_directory=yes' to expose.
2289 Thanks to Wolfgang Breyha, who found the same fix.
2291 diff --git a/src/src/transport.c b/src/src/transport.c
2292 index fa6f869..a6ad3ed 100644
2293 --- a/src/src/transport.c
2294 +++ b/src/src/transport.c
2295 @@ -1752,7 +1752,7 @@ while (1)
2297 if (split_spool_directory)
2298 sprintf(CS spool_file, "%s%c/%s-D",
2299 - spool_dir, new_message_id[5], msgq[i].message_id);
2300 + spool_dir, msgq[i].message_id[5], msgq[i].message_id);
2302 sprintf(CS spool_file, "%s%s-D", spool_dir, msgq[i].message_id);
2305 commit b20b82a0b4169cb23380a373ed2a898b0cb337d2
2306 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
2307 Date: Fri Aug 21 12:26:50 2015 +0200
2309 Add a .ctags file to src
2311 diff --git a/src/.ctags b/src/.ctags
2312 new file mode 100644
2313 index 0000000..c764086
2320 commit dadff1d47e54962b0fdf98e8ce5cef42b6cb7fb5
2321 Author: Heiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
2322 Date: Thu Aug 20 13:58:06 2015 +0200
2324 Fix post-transport-crash: safeguard for missing spool BUG 1671
2326 Based on a proposal from Wolfgang Breyha.
2328 diff --git a/src/src/deliver.c b/src/src/deliver.c
2329 index 0e7cea3..b5aa9b9 100644
2330 --- a/src/src/deliver.c
2331 +++ b/src/src/deliver.c
2336 +#include <assert.h>
2339 /* Data block for keeping track of subprocesses for parallel remote
2340 @@ -7934,17 +7935,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
2342 deliver_get_sender_address (uschar * id)
2345 +uschar * new_sender_address,
2346 + * save_sender_address;
2348 if (!spool_open_datafile(id))
2351 +/* Save and restore the global sender_address. I'm not sure if we should
2352 +not save/restore all the other global variables too, because
2353 +spool_read_header() may change all of them. But OTOH, when this
2354 +deliver_get_sender_address() gets called, the current message is done
2355 +already and nobody needs the globals anymore. (HS12, 2015-08-21) */
2357 sprintf(CS spoolname, "%s-H", id);
2358 -if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
2359 +save_sender_address = sender_address;
2361 +rc = spool_read_header(spoolname, TRUE, TRUE);
2363 +new_sender_address = sender_address;
2364 +sender_address = save_sender_address;
2366 +if (rc != spool_read_OK)
2369 +assert(new_sender_address);
2371 (void)close(deliver_datafile);
2372 deliver_datafile = -1;
2374 -return sender_address;
2375 +return new_sender_address;
2379 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
2380 index 609dba3..c93f2ef 100644
2381 --- a/src/src/transports/smtp.c
2382 +++ b/src/src/transports/smtp.c
2383 @@ -1274,14 +1274,19 @@ we will veto this new message. */
2385 smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
2387 -uschar * save_sender_address = sender_address;
2388 -uschar * current_local_identity =
2390 +uschar * message_local_identity,
2391 + * current_local_identity,
2392 + * new_sender_address;
2394 +current_local_identity =
2395 smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
2396 -uschar * new_sender_address = deliver_get_sender_address(message_id);
2397 -uschar * message_local_identity =
2398 - smtp_local_identity(new_sender_address, s_compare->tblock);
2400 -sender_address = save_sender_address;
2401 +if (!(new_sender_address = deliver_get_sender_address(message_id)))
2404 +message_local_identity =
2405 + smtp_local_identity(new_sender_address, s_compare->tblock);
2407 return Ustrcmp(current_local_identity, message_local_identity) == 0;
2410 commit 3703d8187af01d13ca71f7918c7ef78529bb784d
2411 Author: Jeremy Harris <jgh146exb@wizmail.org>
2412 Date: Fri Aug 21 18:08:39 2015 +0100
2414 Remember the fail reason for verify=headers_syntax. Bug 264
2416 diff --git a/src/src/acl.c b/src/src/acl.c
2417 index f2e0ef2..064ee6c 100644
2420 @@ -1803,27 +1803,27 @@ switch(vp->value)
2421 test whether it was successful or not. (This is for optional verification; for
2422 mandatory verification, the connection doesn't last this long.) */
2424 - if (tls_in.certificate_verified) return OK;
2425 - *user_msgptr = US"no verified certificate";
2427 + if (tls_in.certificate_verified) return OK;
2428 + *user_msgptr = US"no verified certificate";
2432 /* We can test the result of optional HELO verification that might have
2433 occurred earlier. If not, we can attempt the verification now. */
2435 - if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
2436 - return helo_verified? OK : FAIL;
2437 + if (!helo_verified && !helo_verify_failed) smtp_verify_helo();
2438 + return helo_verified? OK : FAIL;
2441 /* Do Client SMTP Authorization checks in a separate function, and turn the
2442 result code into user-friendly strings. */
2444 - rc = acl_verify_csa(list);
2445 - *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s",
2446 + rc = acl_verify_csa(list);
2447 + *log_msgptr = *user_msgptr = string_sprintf("client SMTP authorization %s",
2448 csa_reason_string[rc]);
2449 - csa_status = csa_status_string[rc];
2450 - DEBUG(D_acl) debug_printf("CSA result %s\n", csa_status);
2451 - return csa_return_code[rc];
2452 + csa_status = csa_status_string[rc];
2453 + DEBUG(D_acl) debug_printf("CSA result %s\n", csa_status);
2454 + return csa_return_code[rc];
2456 case VERIFY_HDR_SYNTAX:
2457 /* Check that all relevant header lines have the correct syntax. If there is
2458 @@ -1832,8 +1832,11 @@ switch(vp->value)
2461 rc = verify_check_headers(log_msgptr);
2462 - if (rc != OK && smtp_return_error_details && *log_msgptr != NULL)
2463 - *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
2464 + if (rc != OK && *log_msgptr)
2465 + if (smtp_return_error_details)
2466 + *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
2468 + acl_verify_message = *log_msgptr;
2471 case VERIFY_HDR_NAMES_ASCII:
2472 @@ -3788,7 +3791,8 @@ for (; cb != NULL; cb = cb->next)
2475 rc = acl_verify(where, addr, arg, user_msgptr, log_msgptr, basic_errno);
2476 - acl_verify_message = *user_msgptr;
2478 + acl_verify_message = *user_msgptr;
2479 if (verb == ACL_WARN) *user_msgptr = NULL;
2483 commit c8899c20aa08c9ae6a4c291aad23ba90512bebe4
2484 Author: Jeremy Harris <jgh146exb@wizmail.org>
2485 Date: Tue Aug 25 10:36:27 2015 +0100
2487 Close logs after daemon-process exceptional write. Bug 728
2489 diff --git a/src/src/daemon.c b/src/src/daemon.c
2490 index 2d10387..e1ff9a1 100644
2491 --- a/src/src/daemon.c
2492 +++ b/src/src/daemon.c
2493 @@ -735,6 +735,7 @@ else (void)close(dup_accept_socket);
2494 /* Release any store used in this process, including the store used for holding
2495 the incoming host address and an expanded active_hostname. */
2498 store_reset(reset_point);
2499 sender_host_address = NULL;
2502 commit f38917cc94ab337c15ff70c254dd564ee2dcafe7
2503 Author: Jeremy Harris <jgh146exb@wizmail.org>
2504 Date: Tue Sep 8 23:05:20 2015 +0100
2506 Capture substrings in ACL regex= . Bug 425.
2508 diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
2509 index c33e098..596e651 100644
2510 --- a/src/src/config.h.defaults
2511 +++ b/src/src/config.h.defaults
2512 @@ -116,6 +116,8 @@ it's a default value. */
2513 #define RADIUS_CONFIG_FILE
2514 #define RADIUS_LIB_TYPE
2516 +#define REGEX_VARS 9
2518 #define ROUTER_ACCEPT
2519 #define ROUTER_DNSLOOKUP
2520 #define ROUTER_IPLITERAL
2521 diff --git a/src/src/exim.c b/src/src/exim.c
2522 index d7cb5d8..999b94c 100644
2523 --- a/src/src/exim.c
2524 +++ b/src/src/exim.c
2525 @@ -1753,6 +1753,8 @@ regex_whitelisted_macro =
2526 regex_must_compile(US"^[A-Za-z0-9_/.-]*$", FALSE, TRUE);
2529 +for (i = 0; i < REGEX_VARS; i++) regex_vars[i] = NULL;
2532 /* If the program is called as "mailq" treat it as equivalent to "exim -bp";
2533 this seems to be a generally accepted convention, since one finds symbolic
2534 diff --git a/src/src/expand.c b/src/src/expand.c
2535 index 89e0ac7..1bff521 100644
2536 --- a/src/src/expand.c
2537 +++ b/src/src/expand.c
2538 @@ -1726,7 +1726,14 @@ if (Ustrncmp(name, "auth", 4) == 0)
2540 int n = Ustrtoul(name + 4, &endptr, 10);
2541 if (*endptr == 0 && n != 0 && n <= AUTH_VARS)
2542 - return (auth_vars[n-1] == NULL)? US"" : auth_vars[n-1];
2543 + return !auth_vars[n-1] ? US"" : auth_vars[n-1];
2545 +else if (Ustrncmp(name, "regex", 5) == 0)
2548 + int n = Ustrtoul(name + 5, &endptr, 10);
2549 + if (*endptr == 0 && n != 0 && n <= REGEX_VARS)
2550 + return !regex_vars[n-1] ? US"" : regex_vars[n-1];
2553 /* For all other variables, search the table */
2554 diff --git a/src/src/globals.c b/src/src/globals.c
2555 index 4188b4d..8445f00 100644
2556 --- a/src/src/globals.c
2557 +++ b/src/src/globals.c
2558 @@ -1090,8 +1090,9 @@ const pcre *regex_From = NULL;
2559 const pcre *regex_IGNOREQUOTA = NULL;
2560 const pcre *regex_PIPELINING = NULL;
2561 const pcre *regex_SIZE = NULL;
2562 -const pcre *regex_smtp_code = NULL;
2563 const pcre *regex_ismsgid = NULL;
2564 +const pcre *regex_smtp_code = NULL;
2565 +uschar *regex_vars[REGEX_VARS];
2566 #ifdef WHITELIST_D_MACROS
2567 const pcre *regex_whitelisted_macro = NULL;
2569 diff --git a/src/src/globals.h b/src/src/globals.h
2570 index 978a4cc..3c69e43 100644
2571 --- a/src/src/globals.h
2572 +++ b/src/src/globals.h
2573 @@ -717,8 +717,9 @@ extern const pcre *regex_From; /* For recognizing "From_" lines */
2574 extern const pcre *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */
2575 extern const pcre *regex_PIPELINING; /* For recognizing PIPELINING */
2576 extern const pcre *regex_SIZE; /* For recognizing SIZE settings */
2577 -extern const pcre *regex_smtp_code; /* For recognizing SMTP codes */
2578 extern const pcre *regex_ismsgid; /* Compiled r.e. for message it */
2579 +extern const pcre *regex_smtp_code; /* For recognizing SMTP codes */
2580 +extern uschar *regex_vars[]; /* $regexN variables */
2581 #ifdef WHITELIST_D_MACROS
2582 extern const pcre *regex_whitelisted_macro; /* For -D macro values */
2584 diff --git a/src/src/regex.c b/src/src/regex.c
2585 index ed73b6e..93422fa 100644
2586 --- a/src/src/regex.c
2587 +++ b/src/src/regex.c
2588 @@ -25,109 +25,120 @@ uschar regex_match_string_buffer[1024];
2589 extern FILE *mime_stream;
2590 extern uschar *mime_current_boundary;
2593 -regex(const uschar **listptr)
2595 +compile(const uschar * list)
2598 - const uschar *list = *listptr;
2599 uschar *regex_string;
2600 uschar regex_string_buffer[1024];
2601 - unsigned long mbox_size;
2604 - pcre_list *re_list_head = NULL;
2605 - pcre_list *re_list_item;
2606 const char *pcre_error;
2608 + pcre_list *re_list_head = NULL;
2611 + /* precompile our regexes */
2612 + while ((regex_string = string_nextinlist(&list, &sep,
2613 + regex_string_buffer,
2614 + sizeof(regex_string_buffer))) != NULL) {
2617 + /* parse option */
2618 + if ( (strcmpic(regex_string,US"false") == 0) ||
2619 + (Ustrcmp(regex_string,"0") == 0) )
2620 + continue; /* explicitly no matching */
2622 + /* compile our regular expression */
2623 + if (!(re = pcre_compile( CS regex_string,
2624 + 0, &pcre_error, &pcre_erroffset, NULL ))) {
2625 + log_write(0, LOG_MAIN,
2626 + "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.",
2627 + regex_string, pcre_error, pcre_erroffset);
2631 + ri = store_get(sizeof(pcre_list));
2633 + ri->pcre_text = string_copy(regex_string);
2634 + ri->next = re_list_head;
2635 + re_list_head = ri;
2637 + return re_list_head;
2641 +matcher(pcre_list * re_list_head, uschar * linebuffer, int len)
2645 + for(ri = re_list_head; ri; ri = ri->next)
2647 + int ovec[3*(REGEX_VARS+1)];
2650 + /* try matcher on the line */
2651 + n = pcre_exec(ri->re, NULL,
2652 + CS linebuffer, len, 0, 0,
2653 + ovec, nelem(ovec));
2656 + Ustrncpy(regex_match_string_buffer, ri->pcre_text, 1023);
2657 + regex_match_string = regex_match_string_buffer;
2659 + for (nn = 1; nn < n; nn++)
2660 + regex_vars[nn-1] =
2661 + string_copyn(linebuffer + ovec[nn*2], ovec[nn*2+1] - ovec[nn*2]);
2670 +regex(const uschar **listptr)
2672 + unsigned long mbox_size;
2674 + pcre_list *re_list_head;
2679 /* reset expansion variable */
2680 regex_match_string = NULL;
2682 - if (mime_stream == NULL) {
2683 - /* We are in the DATA ACL */
2684 + if (mime_stream == NULL) { /* We are in the DATA ACL */
2685 mbox_file = spool_mbox(&mbox_size, NULL);
2686 - if (mbox_file == NULL) {
2687 - /* error while spooling */
2688 + if (mbox_file == NULL) { /* error while spooling */
2689 log_write(0, LOG_MAIN|LOG_PANIC,
2690 "regex acl condition: error while creating mbox spool file");
2696 f_pos = ftell(mime_stream);
2697 mbox_file = mime_stream;
2701 /* precompile our regexes */
2702 - while ((regex_string = string_nextinlist(&list, &sep,
2703 - regex_string_buffer,
2704 - sizeof(regex_string_buffer))) != NULL) {
2706 - /* parse option */
2707 - if ( (strcmpic(regex_string,US"false") == 0) ||
2708 - (Ustrcmp(regex_string,"0") == 0) ) {
2709 - /* explicitly no matching */
2713 - /* compile our regular expression */
2714 - re = pcre_compile( CS regex_string,
2721 - log_write(0, LOG_MAIN,
2722 - "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", regex_string, pcre_error, pcre_erroffset);
2726 - re_list_item = store_get(sizeof(pcre_list));
2727 - re_list_item->re = re;
2728 - re_list_item->pcre_text = string_copy(regex_string);
2729 - re_list_item->next = re_list_head;
2730 - re_list_head = re_list_item;
2734 - /* no regexes -> nothing to do */
2735 - if (re_list_head == NULL) {
2738 + if (!(re_list_head = compile(*listptr)))
2739 + return FAIL; /* no regexes -> nothing to do */
2741 /* match each line against all regexes */
2742 linebuffer = store_get(32767);
2743 while (fgets(CS linebuffer, 32767, mbox_file) != NULL) {
2744 - if ( (mime_stream != NULL) && (mime_current_boundary != NULL) ) {
2745 - /* check boundary */
2746 - if (Ustrncmp(linebuffer,"--",2) == 0) {
2747 - if (Ustrncmp((linebuffer+2),mime_current_boundary,Ustrlen(mime_current_boundary)) == 0)
2748 - /* found boundary */
2752 - re_list_item = re_list_head;
2754 - /* try matcher on the line */
2755 - if (pcre_exec(re_list_item->re, NULL, CS linebuffer,
2756 - (int)Ustrlen(linebuffer), 0, 0, NULL, 0) >= 0) {
2757 - Ustrncpy(regex_match_string_buffer, re_list_item->pcre_text, 1023);
2758 - regex_match_string = regex_match_string_buffer;
2759 - if (mime_stream == NULL)
2760 - (void)fclose(mbox_file);
2762 - clearerr(mime_stream);
2763 - fseek(mime_stream,f_pos,SEEK_SET);
2767 - re_list_item = re_list_item->next;
2768 - } while (re_list_item != NULL);
2771 + if ( mime_stream && mime_current_boundary /* check boundary */
2772 + && Ustrncmp(linebuffer,"--",2) == 0
2773 + && Ustrncmp((linebuffer+2),mime_current_boundary,Ustrlen(mime_current_boundary)) == 0)
2774 + break; /* found boundary */
2776 + if ((ret = matcher(re_list_head, linebuffer, (int)Ustrlen(linebuffer))) == OK)
2779 + /* no matches ... */
2782 if (mime_stream == NULL)
2783 (void)fclose(mbox_file);
2785 @@ -135,67 +146,25 @@ regex(const uschar **listptr)
2786 fseek(mime_stream,f_pos,SEEK_SET);
2789 - /* no matches ... */
2796 mime_regex(const uschar **listptr)
2799 - const uschar *list = *listptr;
2800 - uschar *regex_string;
2801 - uschar regex_string_buffer[1024];
2803 pcre_list *re_list_head = NULL;
2804 - pcre_list *re_list_item;
2805 - const char *pcre_error;
2806 - int pcre_erroffset;
2808 uschar *mime_subject = NULL;
2809 int mime_subject_len = 0;
2812 /* reset expansion variable */
2813 regex_match_string = NULL;
2815 /* precompile our regexes */
2816 - while ((regex_string = string_nextinlist(&list, &sep,
2817 - regex_string_buffer,
2818 - sizeof(regex_string_buffer))) != NULL) {
2820 - /* parse option */
2821 - if ( (strcmpic(regex_string,US"false") == 0) ||
2822 - (Ustrcmp(regex_string,"0") == 0) ) {
2823 - /* explicitly no matching */
2827 - /* compile our regular expression */
2828 - re = pcre_compile( CS regex_string,
2835 - log_write(0, LOG_MAIN,
2836 - "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.", regex_string, pcre_error, pcre_erroffset);
2840 - re_list_item = store_get(sizeof(pcre_list));
2841 - re_list_item->re = re;
2842 - re_list_item->pcre_text = string_copy(regex_string);
2843 - re_list_item->next = re_list_head;
2844 - re_list_head = re_list_item;
2848 - /* no regexes -> nothing to do */
2849 - if (re_list_head == NULL) {
2852 + if (!(re_list_head = compile(*listptr)))
2853 + return FAIL; /* no regexes -> nothing to do */
2855 /* check if the file is already decoded */
2856 if (mime_decoded_filename == NULL) {
2857 @@ -207,43 +176,25 @@ mime_regex(const uschar **listptr)
2858 log_write(0, LOG_MAIN,
2859 "mime_regex acl condition warning - could not decode MIME part to file.");
2868 - f = fopen(CS mime_decoded_filename, "rb");
2871 + if (!(f = fopen(CS mime_decoded_filename, "rb"))) {
2872 log_write(0, LOG_MAIN,
2873 - "mime_regex acl condition warning - can't open '%s' for reading.", mime_decoded_filename);
2874 + "mime_regex acl condition warning - can't open '%s' for reading.",
2875 + mime_decoded_filename);
2880 /* get 32k memory */
2881 mime_subject = (uschar *)store_get(32767);
2883 - /* read max 32k chars from file */
2884 mime_subject_len = fread(mime_subject, 1, 32766, f);
2886 - re_list_item = re_list_head;
2888 - /* try matcher on the mmapped file */
2889 - debug_printf("Matching '%s'\n", re_list_item->pcre_text);
2890 - if (pcre_exec(re_list_item->re, NULL, CS mime_subject,
2891 - mime_subject_len, 0, 0, NULL, 0) >= 0) {
2892 - Ustrncpy(regex_match_string_buffer, re_list_item->pcre_text, 1023);
2893 - regex_match_string = regex_match_string_buffer;
2897 - re_list_item = re_list_item->next;
2898 - } while (re_list_item != NULL);
2900 + ret = matcher(re_list_head, mime_subject, mime_subject_len);
2903 - /* no matches ... */
2908 #endif /* WITH_CONTENT_SCAN */
2910 commit 895fbaf26d3450d4eeacbad8fe04c328a77645f0
2911 Author: Jeremy Harris <jgh146exb@wizmail.org>
2912 Date: Wed Sep 9 16:03:38 2015 +0100
2914 DSN: Under EXPERIMENTAL_DSN_INFO add extras to bounce messages. Bug 1686
2916 diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
2917 index 596e651..6af3b4d 100644
2918 --- a/src/src/config.h.defaults
2919 +++ b/src/src/config.h.defaults
2920 @@ -172,6 +172,7 @@ it's a default value. */
2921 #define EXPERIMENTAL_BRIGHTMAIL
2922 #define EXPERIMENTAL_DANE
2923 #define EXPERIMENTAL_DCC
2924 +#define EXPERIMENTAL_DSN_INFO
2925 #define EXPERIMENTAL_DMARC
2926 #define EXPERIMENTAL_EVENT
2927 #define EXPERIMENTAL_INTERNATIONAL
2928 diff --git a/src/src/deliver.c b/src/src/deliver.c
2929 index b5aa9b9..3f22dc9 100644
2930 --- a/src/src/deliver.c
2931 +++ b/src/src/deliver.c
2932 @@ -3223,41 +3223,56 @@ while (!done)
2936 - addr->transport_return = *ptr++;
2937 - addr->special_action = *ptr++;
2938 - memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
2939 - ptr += sizeof(addr->basic_errno);
2940 - memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
2941 - ptr += sizeof(addr->more_errno);
2942 - memcpy(&(addr->flags), ptr, sizeof(addr->flags));
2943 - ptr += sizeof(addr->flags);
2944 - addr->message = (*ptr)? string_copy(ptr) : NULL;
2946 - addr->user_message = (*ptr)? string_copy(ptr) : NULL;
2949 - /* Always two strings for host information, followed by the port number and DNSSEC mark */
2954 - h = store_get(sizeof(host_item));
2955 - h->name = string_copy(ptr);
2957 - h->address = string_copy(ptr);
2959 - memcpy(&(h->port), ptr, sizeof(h->port));
2960 - ptr += sizeof(h->port);
2961 - h->dnssec = *ptr == '2' ? DS_YES
2962 - : *ptr == '1' ? DS_NO
2965 - addr->host_used = h;
2968 +#ifdef EXPERIMENTAL_DSN_INFO
2969 + case '1': /* must arrive before A0, and applies to that addr */
2970 + /* Two strings: smtp_greeting and helo_response */
2971 + addr->smtp_greeting = string_copy(ptr);
2973 + addr->helo_response = string_copy(ptr);
2978 - /* Finished with this address */
2980 + addr->transport_return = *ptr++;
2981 + addr->special_action = *ptr++;
2982 + memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
2983 + ptr += sizeof(addr->basic_errno);
2984 + memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
2985 + ptr += sizeof(addr->more_errno);
2986 + memcpy(&(addr->flags), ptr, sizeof(addr->flags));
2987 + ptr += sizeof(addr->flags);
2988 + addr->message = (*ptr)? string_copy(ptr) : NULL;
2990 + addr->user_message = (*ptr)? string_copy(ptr) : NULL;
2993 - addr = addr->next;
2994 + /* Always two strings for host information, followed by the port number and DNSSEC mark */
2998 + h = store_get(sizeof(host_item));
2999 + h->name = string_copy(ptr);
3001 + h->address = string_copy(ptr);
3003 + memcpy(&(h->port), ptr, sizeof(h->port));
3004 + ptr += sizeof(h->port);
3005 + h->dnssec = *ptr == '2' ? DS_YES
3006 + : *ptr == '1' ? DS_NO
3009 + addr->host_used = h;
3013 + /* Finished with this address */
3015 + addr = addr->next;
3020 /* Local interface address/port */
3021 @@ -4423,7 +4438,6 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
3023 for (r = addr->retries; r != NULL; r = r->next)
3026 sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
3027 ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
3028 memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
3029 @@ -4438,11 +4452,31 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
3030 rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
3033 - /* The rest of the information goes in an 'A' item. */
3034 +#ifdef EXPERIMENTAL_DSN_INFO
3035 +/*um, are they really per-addr? Other per-conn stuff is not (auth, tls). But host_used is! */
3036 + if (addr->smtp_greeting)
3039 + DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting);
3040 + sprintf(CS ptr, "%.128s", addr->smtp_greeting);
3042 + if (addr->helo_response)
3044 + DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response);
3045 + sprintf(CS ptr, "%.128s", addr->helo_response);
3050 + rmt_dlv_checked_write(fd, 'A', '1', big_buffer, ptr - big_buffer);
3054 + /* The rest of the information goes in an 'A0' item. */
3056 - ptr = big_buffer + 2;
3057 sprintf(CS big_buffer, "%c%c", addr->transport_return,
3058 addr->special_action);
3059 + ptr = big_buffer + 2;
3060 memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
3061 ptr += sizeof(addr->basic_errno);
3062 memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
3063 @@ -4480,7 +4514,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++)
3066 /* Local interface address/port */
3067 +#ifdef EXPERIMENTAL_DSN_INFO
3068 + if (sending_ip_address)
3070 if (LOGGING(incoming_interface) && sending_ip_address)
3073 uschar * ptr = big_buffer;
3074 sprintf(CS ptr, "%.128s", sending_ip_address);
3075 @@ -7209,16 +7247,32 @@ wording. */
3077 for (addr = handled_addr; addr; addr = addr->next)
3080 fprintf(f, "Action: failed\n"
3081 "Final-Recipient: rfc822;%s\n"
3084 - if (addr->host_used && addr->host_used->name)
3086 - fprintf(f, "Remote-MTA: dns; %s\n",
3087 - addr->host_used->name);
3088 - print_dsn_diagnostic_code(addr, f);
3090 + if ((hu = addr->host_used) && hu->name)
3093 + fprintf(f, "Remote-MTA: dns; %s\n",
3095 +#ifdef EXPERIMENTAL_DSN_INFO
3098 + uschar * p = hu->port == 25
3099 + ? US"" : string_sprintf(":%d", hu->port);
3100 + fprintf(f, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p);
3102 + if ((s = addr->smtp_greeting) && *s)
3103 + fprintf(f, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s);
3104 + if ((s = addr->helo_response) && *s)
3105 + fprintf(f, "X-Remote-MTA-helo-response: X-str; %s\n", s);
3106 + if ((s = addr->message) && *s)
3107 + fprintf(f, "X-Exim-Diagnostic: X-str; %s\n", s);
3109 + print_dsn_diagnostic_code(addr, f);
3114 diff --git a/src/src/exim.c b/src/src/exim.c
3115 index 999b94c..084d649 100644
3116 --- a/src/src/exim.c
3117 +++ b/src/src/exim.c
3118 @@ -847,6 +847,12 @@ fprintf(f, "Support for:");
3119 #ifdef EXPERIMENTAL_DMARC
3120 fprintf(f, " Experimental_DMARC");
3122 +#ifdef EXPERIMENTAL_DSN_INFO
3123 + fprintf(f, " Experimental_DSN_info");
3125 +#ifdef EXPERIMENTAL_INTERNATIONAL
3126 + fprintf(f, " Experimental_International");
3128 #ifdef EXPERIMENTAL_PROXY
3129 fprintf(f, " Experimental_Proxy");
3131 @@ -859,9 +865,6 @@ fprintf(f, "Support for:");
3132 #ifdef EXPERIMENTAL_SOCKS
3133 fprintf(f, " Experimental_SOCKS");
3135 -#ifdef EXPERIMENTAL_INTERNATIONAL
3136 - fprintf(f, " Experimental_International");
3140 fprintf(f, "Lookups (built-in):");
3141 diff --git a/src/src/globals.c b/src/src/globals.c
3142 index 8445f00..f3b6791 100644
3143 --- a/src/src/globals.c
3144 +++ b/src/src/globals.c
3145 @@ -354,13 +354,17 @@ address_item address_defaults = {
3146 NULL, /* return_filename */
3147 NULL, /* self_hostname */
3148 NULL, /* shadow_message */
3149 - #ifdef SUPPORT_TLS
3153 NULL, /* peercert */
3155 OCSP_NOT_REQ, /* ocsp */
3158 +#ifdef EXPERIMENTAL_DSN_INFO
3159 + NULL, /* smtp_greeting */
3160 + NULL, /* helo_response */
3162 NULL, /* authenticator */
3164 NULL, /* auth_sndr */
3165 diff --git a/src/src/structs.h b/src/src/structs.h
3166 index 438b521..db9e843 100644
3167 --- a/src/src/structs.h
3168 +++ b/src/src/structs.h
3169 @@ -561,13 +561,18 @@ typedef struct address_item {
3170 uschar *self_hostname; /* after self=pass */
3171 uschar *shadow_message; /* info about shadow transporting */
3173 - #ifdef SUPPORT_TLS
3175 uschar *cipher; /* Cipher used for transport */
3176 void *ourcert; /* Certificate offered to peer, binary */
3177 void *peercert; /* Certificate from peer, binary */
3178 uschar *peerdn; /* DN of server's certificate */
3179 int ocsp; /* OCSP status of peer cert */
3183 +#ifdef EXPERIMENTAL_DSN_INFO
3184 + const uschar *smtp_greeting; /* peer self-identification */
3185 + const uschar *helo_response; /* peer message */
3188 uschar *authenticator; /* auth driver name used by transport */
3189 uschar *auth_id; /* auth "login" name used by transport */
3190 diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
3191 index c93f2ef..ac40460 100644
3192 --- a/src/src/transports/smtp.c
3193 +++ b/src/src/transports/smtp.c
3194 @@ -440,6 +440,8 @@ Arguments:
3195 rc to put in each address's transport_return field
3196 pass_message if TRUE, set the "pass message" flag in the address
3197 host if set, mark addrs as having used this host
3198 + smtp_greeting from peer
3199 + helo_response from peer
3201 If errno_value has the special value ERRNO_CONNECTTIMEOUT, ETIMEDOUT is put in
3202 the errno field, and RTEF_CTOUT is ORed into the more_errno field, to indicate
3203 @@ -450,7 +452,11 @@ Returns: nothing
3206 set_errno(address_item *addrlist, int errno_value, uschar *msg, int rc,
3207 - BOOL pass_message, host_item * host)
3208 + BOOL pass_message, host_item * host
3209 +#ifdef EXPERIMENTAL_DSN_INFO
3210 + , const uschar * smtp_greeting, const uschar * helo_response
3216 @@ -459,7 +465,7 @@ if (errno_value == ERRNO_CONNECTTIMEOUT)
3217 errno_value = ETIMEDOUT;
3218 orvalue = RTEF_CTOUT;
3220 -for (addr = addrlist; addr != NULL; addr = addr->next)
3221 +for (addr = addrlist; addr; addr = addr->next)
3222 if (addr->transport_return >= PENDING)
3224 addr->basic_errno = errno_value;
3225 @@ -471,10 +477,31 @@ for (addr = addrlist; addr != NULL; addr = addr->next)
3227 addr->transport_return = rc;
3230 addr->host_used = host;
3231 +#ifdef EXPERIMENTAL_DSN_INFO
3232 + if (smtp_greeting)
3233 + {uschar * s = Ustrchr(smtp_greeting, '\n'); if (s) *s = '\0';}
3234 + addr->smtp_greeting = smtp_greeting;
3236 + if (helo_response)
3237 + {uschar * s = Ustrchr(helo_response, '\n'); if (s) *s = '\0';}
3238 + addr->helo_response = helo_response;
3245 +set_errno_nohost(address_item *addrlist, int errno_value, uschar *msg, int rc,
3246 + BOOL pass_message)
3248 +set_errno(addrlist, errno_value, msg, rc, pass_message, NULL
3249 +#ifdef EXPERIMENTAL_DSN_INFO
3256 /*************************************************
3257 @@ -847,7 +874,7 @@ while (count-- > 0)
3259 uschar *message = string_sprintf("SMTP timeout after RCPT TO:<%s>",
3260 transport_rcpt_address(addr, include_affixes));
3261 - set_errno(addrlist, ETIMEDOUT, message, DEFER, FALSE, NULL);
3262 + set_errno_nohost(addrlist, ETIMEDOUT, message, DEFER, FALSE);
3263 retry_add_item(addr, addr->address_retry_key, 0);
3264 update_waiting = FALSE;
3266 @@ -1096,8 +1123,8 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
3267 /* Internal problem, message in buffer. */
3270 - set_errno(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
3271 - DEFER, FALSE, NULL);
3272 + set_errno_nohost(addrlist, ERRNO_AUTHPROB, string_copy(buffer),
3277 @@ -1111,9 +1138,9 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
3279 if (require_auth == OK && !smtp_authenticated)
3281 - set_errno(addrlist, ERRNO_AUTHFAIL,
3282 + set_errno_nohost(addrlist, ERRNO_AUTHFAIL,
3283 string_sprintf("authentication required but %s", fail_reason), DEFER,
3289 @@ -1152,7 +1179,7 @@ if (ob->authenticated_sender != NULL)
3291 uschar *message = string_sprintf("failed to expand "
3292 "authenticated_sender: %s", expand_string_message);
3293 - set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
3294 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
3298 @@ -1381,6 +1408,10 @@ smtp_outblock outblock;
3299 int max_rcpt = tblock->max_addresses;
3300 uschar *igquotstr = US"";
3302 +#ifdef EXPERIMENTAL_DSN_INFO
3303 +uschar *smtp_greeting = NULL;
3304 +uschar *helo_response = NULL;
3306 uschar *helo_data = NULL;
3308 uschar *message = NULL;
3309 @@ -1432,8 +1463,8 @@ tls_modify_variables(&tls_out);
3313 - set_errno(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
3314 - DEFER, FALSE, NULL);
3315 + set_errno_nohost(addrlist, ERRNO_TLSFAILURE, US"TLS support not available",
3320 @@ -1450,8 +1481,8 @@ if (continue_hostname == NULL)
3322 if (inblock.sock < 0)
3324 - set_errno(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
3325 - NULL, DEFER, FALSE, NULL);
3326 + set_errno_nohost(addrlist, (errno == ETIMEDOUT)? ERRNO_CONNECTTIMEOUT : errno,
3327 + NULL, DEFER, FALSE);
3331 @@ -1469,18 +1500,18 @@ if (continue_hostname == NULL)
3332 && dane_required /* do not error on only dane-requested */
3335 - set_errno(addrlist, ERRNO_DNSDEFER,
3336 + set_errno_nohost(addrlist, ERRNO_DNSDEFER,
3337 string_sprintf("DANE error: tlsa lookup %s",
3338 rc == DEFER ? "DEFER" : "FAIL"),
3344 else if (dane_required)
3346 - set_errno(addrlist, ERRNO_DNSDEFER,
3347 + set_errno_nohost(addrlist, ERRNO_DNSDEFER,
3348 string_sprintf("DANE error: %s lookup not DNSSEC", host->name),
3349 - FAIL, FALSE, NULL);
3354 @@ -1501,7 +1532,7 @@ if (continue_hostname == NULL)
3355 if ((helo_data = string_domain_utf8_to_alabel(helo_data, &errstr)), errstr)
3357 errstr = string_sprintf("failed to expand helo_data: %s", errstr);
3358 - set_errno(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL);
3359 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE);
3363 @@ -1514,8 +1545,12 @@ if (continue_hostname == NULL)
3367 - if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
3368 - ob->command_timeout)) goto RESPONSE_FAILED;
3369 + BOOL good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
3370 + '2', ob->command_timeout);
3371 +#ifdef EXPERIMENTAL_DSN_INFO
3372 + smtp_greeting = string_copy(buffer);
3374 + if (!good_response) goto RESPONSE_FAILED;
3376 #ifdef EXPERIMENTAL_EVENT
3378 @@ -1525,9 +1560,9 @@ if (continue_hostname == NULL)
3379 s = event_raise(tblock->event_action, US"smtp:connect", buffer);
3382 - set_errno(addrlist, ERRNO_EXPANDFAIL,
3383 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL,
3384 string_sprintf("deferred by smtp:connect event expansion: %s", s),
3385 - DEFER, FALSE, NULL);
3390 @@ -1541,7 +1576,7 @@ if (continue_hostname == NULL)
3392 uschar *message = string_sprintf("failed to expand helo_data: %s",
3393 expand_string_message);
3394 - set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
3395 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
3399 @@ -1606,9 +1641,18 @@ goto SEND_QUIT;
3400 if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
3401 ob->command_timeout))
3403 - if (errno != 0 || buffer[0] == 0 || lmtp) goto RESPONSE_FAILED;
3404 + if (errno != 0 || buffer[0] == 0 || lmtp)
3406 +#ifdef EXPERIMENTAL_DSN_INFO
3407 + helo_response = string_copy(buffer);
3409 + goto RESPONSE_FAILED;
3413 +#ifdef EXPERIMENTAL_DSN_INFO
3414 + helo_response = string_copy(buffer);
3419 @@ -1618,10 +1662,16 @@ goto SEND_QUIT;
3423 + BOOL good_response;
3425 if (smtp_write_command(&outblock, FALSE, "HELO %s\r\n", helo_data) < 0)
3427 - if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
3428 - ob->command_timeout)) goto RESPONSE_FAILED;
3429 + good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
3430 + '2', ob->command_timeout);
3431 +#ifdef EXPERIMENTAL_DSN_INFO
3432 + helo_response = string_copy(buffer);
3434 + if (!good_response) goto RESPONSE_FAILED;
3437 /* Set IGNOREQUOTA if the response to LHLO specifies support and the
3438 @@ -1671,6 +1721,11 @@ error messages. Note that smtp_use_size and smtp_use_pipelining will have been
3439 set from the command line if they were set in the process that passed the
3442 +/*XXX continue case needs to propagate DSN_INFO, prob. in deliver.c
3443 +as the contine goes via transport_pass_socket() and doublefork and exec.
3444 +It does not wait. Unclear how we keep separate host's responses
3445 +separate - we could match up by host ip+port as a bodge. */
3449 inblock.sock = outblock.sock = fileno(stdin);
3450 @@ -1749,7 +1804,7 @@ if ( tls_offered
3452 /* TLS session is set up */
3454 - for (addr = addrlist; addr != NULL; addr = addr->next)
3455 + for (addr = addrlist; addr; addr = addr->next)
3456 if (addr->transport_return == PENDING_DEFER)
3458 addr->cipher = tls_out.cipher;
3459 @@ -1774,6 +1829,8 @@ start of the Exim process (in exim.c). */
3460 if (tls_out.active >= 0)
3463 + BOOL good_response;
3465 if (helo_data == NULL)
3467 helo_data = expand_string(ob->helo_data);
3468 @@ -1781,7 +1838,7 @@ if (tls_out.active >= 0)
3470 uschar *message = string_sprintf("failed to expand helo_data: %s",
3471 expand_string_message);
3472 - set_errno(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE, NULL);
3473 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, message, DEFER, FALSE);
3477 @@ -1790,8 +1847,12 @@ if (tls_out.active >= 0)
3478 /* For SMTPS we need to wait for the initial OK response. */
3481 - if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
3482 - ob->command_timeout)) goto RESPONSE_FAILED;
3483 + good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
3484 + '2', ob->command_timeout);
3485 +#ifdef EXPERIMENTAL_DSN_INFO
3486 + smtp_greeting = string_copy(buffer);
3488 + if (!good_response) goto RESPONSE_FAILED;
3492 @@ -1806,9 +1867,12 @@ if (tls_out.active >= 0)
3493 if (smtp_write_command(&outblock, FALSE, "%s %s\r\n",
3494 lmtp? "LHLO" : greeting_cmd, helo_data) < 0)
3496 - if (!smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
3497 - ob->command_timeout))
3498 - goto RESPONSE_FAILED;
3499 + good_response = smtp_read_response(&inblock, buffer, sizeof(buffer),
3500 + '2', ob->command_timeout);
3501 +#ifdef EXPERIMENTAL_DSN_INFO
3502 + helo_response = string_copy(buffer);
3504 + if (!good_response) goto RESPONSE_FAILED;
3507 /* If the host is required to use a secure channel, ensure that we
3508 @@ -1935,8 +1999,8 @@ if (tblock->filter_command != NULL)
3512 - set_errno(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
3514 + set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
3519 @@ -2065,7 +2129,7 @@ pending_MAIL = TRUE; /* The block starts with MAIL */
3521 if (s = string_address_utf8_to_alabel(return_path, &errstr), errstr)
3523 - set_errno(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE, NULL);
3524 + set_errno_nohost(addrlist, ERRNO_EXPANDFAIL, errstr, DEFER, FALSE);
3528 @@ -2217,8 +2281,8 @@ if (mua_wrapper)
3529 if (badaddr->transport_return != PENDING_OK)
3531 /*XXX could we find a better errno than 0 here? */
3532 - set_errno(addrlist, 0, badaddr->message, FAIL,
3533 - testflag(badaddr, af_pass_message), NULL);
3534 + set_errno_nohost(addrlist, 0, badaddr->message, FAIL,
3535 + testflag(badaddr, af_pass_message));
3539 @@ -2475,7 +2539,7 @@ if (!ok) ok = TRUE; else
3541 sprintf(CS buffer, "%.500s\n", addr->unique);
3543 - DEBUG(D_deliver) debug_printf("journalling %s", buffer);
3544 + DEBUG(D_deliver) debug_printf("journalling %s\n", buffer);
3545 len = Ustrlen(CS buffer);
3546 if (write(journal_fd, buffer, len) != len)
3547 log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
3548 @@ -2512,7 +2576,7 @@ if (!ok) ok = TRUE; else
3550 sprintf(CS buffer, "%.500s\n", addr->unique);
3552 - DEBUG(D_deliver) debug_printf("journalling(PRDR) %s", buffer);
3553 + DEBUG(D_deliver) debug_printf("journalling(PRDR) %s\n", buffer);
3554 len = Ustrlen(CS buffer);
3555 if (write(journal_fd, buffer, len) != len)
3556 log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
3557 @@ -2542,22 +2606,27 @@ the problem is not related to this specific message. */
3563 + uschar * set_message;
3566 - save_errno = errno;
3568 - send_quit = check_response(host, &save_errno, addrlist->more_errno,
3569 - buffer, &code, &message, &pass_message);
3572 + save_errno = errno;
3574 + send_quit = check_response(host, &save_errno, addrlist->more_errno,
3575 + buffer, &code, &message, &pass_message);
3580 - save_errno = errno;
3582 - message = US string_sprintf("send() to %s [%s] failed: %s",
3583 - host->name, host->address, strerror(save_errno));
3584 - send_quit = FALSE;
3587 + save_errno = errno;
3589 + message = US string_sprintf("send() to %s [%s] failed: %s",
3590 + host->name, host->address, strerror(save_errno));
3591 + send_quit = FALSE;
3595 /* This label is jumped to directly when a TLS negotiation has failed,
3596 or was not done for a host for which it is required. Values will be set
3597 @@ -2578,16 +2647,14 @@ if (!ok)
3600 ok = FALSE; /* For when reached by GOTO */
3601 + set_message = message;
3606 - set_errno(addrlist, save_errno, message, FAIL, pass_message, host);
3610 - set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
3613 + yield = set_rc = DEFER;
3616 /* We want to handle timeouts after MAIL or "." and loss of connection after
3617 @@ -2646,14 +2713,15 @@ if (!ok)
3620 if (mua_wrapper) code = '5'; /* Force hard failure in wrapper mode */
3621 - set_errno(addrlist, save_errno, message, (code == '5')? FAIL : DEFER,
3622 - pass_message, host);
3624 /* If there's an errno, the message contains just the identity of
3627 - if (code != '5') /* Anything other than 5 is treated as temporary */
3630 + else /* Anything other than 5 is treated as temporary */
3634 message = US string_sprintf("%s: %s", message, strerror(save_errno));
3635 if (host->next != NULL) log_write(0, LOG_MAIN, "%s", message);
3636 @@ -2670,11 +2738,17 @@ if (!ok)
3641 yield = (save_errno == ERRNO_CHHEADER_FAIL ||
3642 save_errno == ERRNO_FILTER_FAIL)? ERROR : DEFER;
3643 - set_errno(addrlist, save_errno, message, DEFER, pass_message, host);
3647 + set_errno(addrlist, save_errno, set_message, set_rc, pass_message, host
3648 +#ifdef EXPERIMENTAL_DSN_INFO
3649 + , smtp_greeting, helo_response
3655 @@ -2787,6 +2861,9 @@ if (completed_address && ok && send_quit)
3656 /* If the socket is successfully passed, we musn't send QUIT (or
3657 indeed anything!) from here. */
3659 +/*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to
3660 +propagate it from the initial
3662 if (ok && transport_pass_socket(tblock->name, host->name, host->address,
3663 new_message_id, inblock.sock))
3665 @@ -2796,7 +2873,11 @@ if (completed_address && ok && send_quit)
3667 /* If RSET failed and there are addresses left, they get deferred. */
3669 - else set_errno(first_addr, errno, msg, DEFER, FALSE, host);
3670 + else set_errno(first_addr, errno, msg, DEFER, FALSE, host
3671 +#ifdef EXPERIMENTAL_DSN_INFO
3672 + , smtp_greeting, helo_response
3678 @@ -2938,6 +3019,10 @@ for (addr = addrlist; addr != NULL; addr = addr->next)
3679 addr->peerdn = NULL;
3680 addr->ocsp = OCSP_NOT_REQ;
3682 +#ifdef EXPERIMENTAL_DSN_INFO
3683 + addr->smtp_greeting = NULL;
3684 + addr->helo_response = NULL;
3689 @@ -3479,7 +3564,7 @@ for (cutoff_retry = 0; expired &&
3693 - set_errno(addrlist, 0, NULL, OK, FALSE, NULL);
3694 + set_errno_nohost(addrlist, 0, NULL, OK, FALSE);
3695 for (addr = addrlist; addr != NULL; addr = addr->next)
3697 addr->host_used = host;